From 63741cb66a6146c16898e0cafde1722a327a0059 Mon Sep 17 00:00:00 2001 From: Yonle Date: Tue, 11 Jul 2023 22:03:51 +0700 Subject: [PATCH] html.c: Escape XML characters & View unknown type attachment link Signed-off-by: Yonle --- html.c | 97 +++++++++++++++++++++++++++++++++------------------------- xs.h | 15 +++++++++ 2 files changed, 71 insertions(+), 41 deletions(-) diff --git a/html.c b/html.c index 13c8e8b..4541571 100644 --- a/html.c +++ b/html.c @@ -105,7 +105,7 @@ xs_str *html_actor_icon(xs_str *os, char *actor, { xs *s1 = xs_fmt("%s", - xs_dict_get(actor, "id"), name); + xs_dict_get(actor, "id"), xs_encode_html(name)); s = xs_str_cat(s, s1); } @@ -139,7 +139,7 @@ xs_str *html_actor_icon(xs_str *os, char *actor, xs *s1 = xs_fmt( "\n\n", - date_title, date_label); + xs_encode_html(date_title), xs_encode_html(date_label)); s = xs_str_cat(s, s1); } @@ -164,7 +164,7 @@ xs_str *html_actor_icon(xs_str *os, char *actor, s1 = xs_fmt( "
%s", - xs_dict_get(actor, "id"), user); + xs_dict_get(actor, "id"), xs_encode_html(user)); s = xs_str_cat(s, s1); } @@ -245,9 +245,9 @@ d_char *html_user_header(snac *snac, d_char *s, int local) { xs *s1 = xs_fmt("%s (@%s@%s)\n", - xs_dict_get(snac->config, "name"), - snac->uid, - xs_dict_get(srv_config, "host")); + xs_encode_html(xs_dict_get(snac->config, "name")), + xs_encode_html(snac->uid), + xs_encode_html(xs_dict_get(srv_config, "host"))); s = xs_str_cat(s, s1); } @@ -284,18 +284,18 @@ d_char *html_user_header(snac *snac, d_char *s, int local) "\n" "\n" "\n", - xs_dict_get(srv_config, "host"), - xs_dict_get(snac->config, "name"), - snac->uid, - xs_dict_get(srv_config, "host"), - s_bio, - s_avatar); + xs_encode_html(xs_dict_get(srv_config, "host")), + xs_encode_html(xs_dict_get(snac->config, "name")), + xs_encode_html(snac->uid), + xs_encode_html(xs_dict_get(srv_config, "host")), + xs_encode_html(s_bio), + xs_encode_html(s_avatar)); s = xs_str_cat(s, s1); } { xs *s1 = xs_fmt("\n", snac->actor); + "title=\"RSS\" href=\"%s.rss\" />\n", snac->actor); /* snac->actor is likely need to be URLEncoded. */ s = xs_str_cat(s, s1); } @@ -355,16 +355,16 @@ d_char *html_user_header(snac *snac, d_char *s, int local) "

@%s@%s

\n"; xs *s1 = xs_fmt(_tmpl, - xs_dict_get(snac->config, "name"), - xs_dict_get(snac->config, "uid"), xs_dict_get(srv_config, "host") + xs_encode_html(xs_dict_get(snac->config, "name")), + xs_encode_html(xs_dict_get(snac->config, "uid")), xs_encode_html(xs_dict_get(srv_config, "host")) ); s = xs_str_cat(s, s1); if (local) { - xs *bio1 = not_really_markdown(xs_dict_get(snac->config, "bio"), NULL); + xs *bio1 = not_really_markdown(xs_encode_html(xs_dict_get(snac->config, "bio")), NULL); xs *tags = xs_list_new(); - xs *bio2 = process_tags(snac, bio1, &tags); + xs *bio2 = xs_encode_html(process_tags(snac, bio1, &tags)); xs *s1 = xs_fmt("
%s
\n", bio2); s = xs_str_cat(s, s1); @@ -914,7 +914,7 @@ xs_str *html_entry(snac *snac, xs_str *os, const xs_dict *msg, int local, xs *s1 = xs_fmt( "
" "%s %s
", - snac->actor, xs_dict_get(snac->config, "name"), L("boosted") + snac->actor, xs_encode_html(xs_dict_get(snac->config, "name")), L("boosted") ); s = xs_str_cat(s, s1); @@ -928,7 +928,7 @@ xs_str *html_entry(snac *snac, xs_str *os, const xs_dict *msg, int local, "
" "%s %s
\n", xs_dict_get(actor_r, "id"), - name, + xs_encode_html(name), L("boosted") ); @@ -967,7 +967,7 @@ xs_str *html_entry(snac *snac, xs_str *os, const xs_dict *msg, int local, char *cw = xs_dict_get(snac->config, "cw"); if (xs_is_null(cw) || local) cw = ""; - xs *s1 = xs_fmt("
%s [%s]\n", cw, v, L("SENSITIVE CONTENT")); + xs *s1 = xs_fmt("
%s [%s]\n", cw, xs_encode_html(v), L("SENSITIVE CONTENT")); s = xs_str_cat(s, s1); sensitive = 1; } @@ -1049,7 +1049,7 @@ xs_str *html_entry(snac *snac, xs_str *os, const xs_dict *msg, int local, if (name && replies) { int nr = xs_number_get(xs_dict_get(replies, "totalItems")); - xs *l = xs_fmt("%s:%d\n", name, nr); + xs *l = xs_fmt("%s:%d\n", xs_encode_html(name), nr); c = xs_str_cat(c, l); } @@ -1073,7 +1073,7 @@ xs_str *html_entry(snac *snac, xs_str *os, const xs_dict *msg, int local, xs *opt = xs_fmt(" %s
\n", !xs_is_null(oo) ? "radio" : "checkbox", - name, name, name); + xs_encode_html(name), xs_encode_html(name), xs_encode_html(name)); s1 = xs_str_cat(s1, opt); } @@ -1107,7 +1107,7 @@ xs_str *html_entry(snac *snac, xs_str *os, const xs_dict *msg, int local, /* skip leading zeros */ for (; *p == '0' || *p == ':'; p++); - xs *s1 = xs_fmt("

%s %s

", L("Closes in"), p); + xs *s1 = xs_fmt("

%s %s

", L("Closes in"), xs_encode_html(p)); c = xs_str_cat(c, s1); } } @@ -1136,7 +1136,7 @@ xs_str *html_entry(snac *snac, xs_str *os, const xs_dict *msg, int local, if (xs_startswith(t, "image/")) { char *url = xs_dict_get(v, "url"); - char *name = xs_dict_get(v, "name"); + char *name = xs_encode_html(xs_dict_get(v, "name")); if (url != NULL) { if (xs_is_null(name)) @@ -1151,9 +1151,31 @@ xs_str *html_entry(snac *snac, xs_str *os, const xs_dict *msg, int local, else if (xs_startswith(t, "video/")) { char *url = xs_dict_get(v, "url"); + char *name = xs_encode_html(xs_dict_get(v, "name")); if (url != NULL) { - xs *s1 = xs_fmt("\n", url); + xs *s1 = xs_fmt("\n", url, url, name ? name : "No description."); + + s = xs_str_cat(s, s1); + } + } + else + if (xs_startswith(t, "audio/")) { + char *url = xs_dict_get(v, "url"); + char *name = xs_encode_html(xs_dict_get(v, "name")); + + if (url != NULL) { + xs *s1 = xs_fmt("\n", url, url, name ? name : "No description."); + + s = xs_str_cat(s, s1); + } + } + else { + char *url = xs_dict_get(v, "url"); + char *name = xs_encode_html(xs_dict_get(v, "name")); + + if (url != NULL) { + xs *s1 = xs_fmt("Attachment: %s", url, name ? name : "No description"); s = xs_str_cat(s, s1); } @@ -1327,7 +1349,7 @@ xs_str *html_timeline(snac *snac, const xs_list *list, int local, int skip, int d_char *html_people_list(snac *snac, d_char *os, d_char *list, const char *header, const char *t) { xs *s = xs_str_new(NULL); - xs *h = xs_fmt("

%s

\n", header); + xs *h = xs_fmt("

%s

\n", xs_encode_html(header)); char *p, *actor_id; s = xs_str_cat(s, h); @@ -1357,7 +1379,7 @@ d_char *html_people_list(snac *snac, d_char *os, d_char *list, const char *heade if (xs_startswith(sc, "

")) s = xs_str_cat(s, sc); else { - xs *s1 = xs_fmt("

%s

", sc); + xs *s1 = xs_fmt("

%s

", xs_encode_html(sc)); s = xs_str_cat(s, s1); } @@ -1529,7 +1551,7 @@ xs_str *html_notifications(snac *snac) xs *s1 = xs_fmt("
\n" "

%s by %s:

\n", - label, actor_id, a_name); + xs_encode_html(label), actor_id, xs_encode_html(a_name)); s = xs_str_cat(s, s1); if (strcmp(type, "Follow") == 0 || strcmp(utype, "Follow") == 0) { @@ -1754,9 +1776,6 @@ int html_get_handler(const xs_dict *req, const char *q_path, xs *bio = not_really_markdown(xs_dict_get(snac.config, "bio"), NULL); char *p, *v; - /* escape tags */ - bio = xs_replace_i(bio, "<", "<"); - bio = xs_replace_i(bio, ">", ">"); rss = xs_fmt( "\n" @@ -1766,11 +1785,11 @@ int html_get_handler(const xs_dict *req, const char *q_path, "en\n" "%s.rss\n" "%s\n", - xs_dict_get(snac.config, "name"), - snac.uid, - xs_dict_get(srv_config, "host"), + xs_encode_html(xs_dict_get(snac.config, "name")), + xs_encode_html(snac.uid), + xs_encode_html(xs_dict_get(srv_config, "host")), snac.actor, - bio + xs_encode_html(bio) ); p = elems; @@ -1785,14 +1804,10 @@ int html_get_handler(const xs_dict *req, const char *q_path, if (!xs_startswith(id, snac.actor)) continue; - xs *content = sanitize(xs_dict_get(msg, "content")); + xs *content = xs_encode_html(sanitize(xs_dict_get(msg, "content"))); xs *title = xs_str_new(NULL); int i; - /* escape tags */ - content = xs_replace_i(content, "<", "<"); - content = xs_replace_i(content, ">", ">"); - for (i = 0; content[i] && content[i] != '<' && content[i] != '&' && i < 40; i++) title = xs_append_m(title, &content[i], 1); @@ -1802,7 +1817,7 @@ int html_get_handler(const xs_dict *req, const char *q_path, "%s\n" "%s\n" "\n", - title, id, content + xs_encode_html(title), id, xs_encode_html(content) ); rss = xs_str_cat(rss, s); diff --git a/xs.h b/xs.h index ad8a35d..6bf3eb8 100644 --- a/xs.h +++ b/xs.h @@ -72,6 +72,7 @@ xs_str *xs_replace_in(xs_str *str, const char *sfrom, const char *sto, int times xs_str *xs_fmt(const char *fmt, ...); int xs_str_in(const char *haystack, const char *needle); int _xs_startsorends(const char *str, const char *xfix, int ends); +xs_str *xs_encode_html(const xs_str *str); #define xs_startswith(str, prefix) _xs_startsorends(str, prefix, 0) #define xs_endswith(str, postfix) _xs_startsorends(str, postfix, 1) xs_str *xs_crop_i(xs_str *str, int start, int end); @@ -506,6 +507,20 @@ int _xs_startsorends(const char *str, const char *xfix, int ends) return !!(ssz >= psz && memcmp(xfix, str + (ends ? ssz - psz : 0), psz) == 0); } +xs_str *xs_encode_html(const char *str) +/* escapes html characters */ +{ + xs_str *encoded = xs_replace(str, "&", "&"); + encoded = xs_replace(encoded, "<", "<"); + encoded = xs_replace(encoded, ">", ">"); + encoded = xs_replace(encoded, "\"", """); + encoded = xs_replace(encoded, "'", "'"); + + // Restore only
. Probably safe. Let's hope nothing goes wrong with this. + encoded = xs_replace(encoded, "<br>", "
"); + + return encoded; +} xs_str *xs_crop_i(xs_str *str, int start, int end) /* crops the d_char to be only from start to end */