commit 8faa066

default  ·  2023-07-05 07:51:45 +0000 UTC
parents c47df76, 38ee86f
Merge branch 'master' of triptico.com:git/snac2
6 files changed,  +71, -25
M data.c
M html.c
M snac.h
+4, -0
 1@@ -4,6 +4,8 @@
 2 
 3 Added proper HTTP caching when serving static files (attached images, avatars, etc.)
 4 
 5+Sensitive content messages can now have a summary (i.e. no longer limited to ...)
 6+
 7 Added a way to block full instances (from the command-line tool, as I consider this to be an administration priviledge).
 8 
 9 If the user style.css does not exist, the server-wide one if served instead.
10@@ -18,6 +20,8 @@ For polls, show the time left before it closes.
11 
12 Added some support for post pinning.
13 
14+Fixed a bug that prevented unfollows to be shown in the notification area.
15+
16 ## 2.35
17 
18 Fixed broken URL links with the # symbol on them.
+10, -3
 1@@ -12,8 +12,6 @@ Mastodon API: fix whatever the fuck is making the official app and Megalodon to
 2 
 3 Improve support for audio attachments.
 4 
 5-Add a quick way to block complete domains / instances.
 6-
 7 Add support for pinning posts.
 8 
 9 Important: deleting a follower should do more that just delete the object, see https://codeberg.org/grunfink/snac2/issues/43#issuecomment-956721
10@@ -33,7 +31,8 @@ Implement bulleted lists. Mastodon is crap and won't show them, but other implem
11 User request: "will it be possible to click on a link and instead of opening the original instance, we'll be able only to see a list of the posts of this person here in comam?. Something like Mastodon does."
12 
13 Test all the possible XSS vulnerabilities in https://raw.githubusercontent.com/danielmiessler/SecLists/master/Fuzzing/big-list-of-naughty-strings.txt
14-Minor data storage housekeeping: index_list() and index_list_desc() should not return deleted (i.e. dash prefixed) entries; _object_user_cache() should call index_del() (?).
15+
16+index_list() and index_list_desc() should not return deleted (i.e. dash prefixed) entries.
17 
18 ## Closed
19 
20@@ -260,3 +259,11 @@ Replace weird, vestigial 'touch-by-append-spaces' in actor_get() with a more pro
21 With this new disk layout, hidden posts (and their children) can be directly skipped when rendering the HTML timeline (are there any other implications?) (2023-06-23T06:48:51+0200).
22 
23 Implement HTTP caches (If-None-Match / ETag) (2023-07-02T11:11:20+0200).
24+
25+Add a quick way to block complete domains / instances (2023-07-04T14:35:44+0200).
26+
27+_object_user_cache() should call index_del() (2023-07-04T14:36:37+0200).
28+
29+Add a content warning description (2023-07-04T15:02:19+0200).
30+
31+Propagate the CW status and description from the replied message (2023-07-04T15:02:19+0200).
+12, -5
 1@@ -449,7 +449,7 @@ int is_msg_for_me(snac *snac, const xs_dict *c_msg)
 2 }
 3 
 4 
 5-void process_tags(snac *snac, const char *content, xs_str **n_content, xs_list **tag)
 6+xs_str *process_tags(snac *snac, const char *content, xs_list **tag)
 7 /* parses mentions and tags from content */
 8 {
 9     xs_str *nc  = xs_str_new(NULL);
10@@ -559,8 +559,9 @@ void process_tags(snac *snac, const char *content, xs_str **n_content, xs_list *
11         n++;
12     }
13 
14-    *n_content = nc;
15-    *tag       = tl;
16+    *tag = tl;
17+
18+    return nc;
19 }
20 
21 
22@@ -688,6 +689,9 @@ void notify(snac *snac, const char *type, const char *utype, const char *actor,
23     /* finally, store it in the notification folder */
24     if (strcmp(type, "Follow") == 0)
25         objid = id;
26+    else
27+    if (strcmp(utype, "Follow") == 0)
28+        objid = actor;
29 
30     notify_add(snac, type, utype, actor, objid != NULL ? objid : id);
31 }
32@@ -836,6 +840,7 @@ xs_dict *msg_actor(snac *snac)
33     xs *ctxt     = xs_list_new();
34     xs *icon     = xs_dict_new();
35     xs *keys     = xs_dict_new();
36+    xs *tags     = xs_list_new();
37     xs *avtr     = NULL;
38     xs *kid      = NULL;
39     xs *f_bio    = NULL;
40@@ -853,8 +858,10 @@ xs_dict *msg_actor(snac *snac)
41     msg = xs_dict_set(msg, "preferredUsername", snac->uid);
42     msg = xs_dict_set(msg, "published",         xs_dict_get(snac->config, "published"));
43 
44-    f_bio = not_really_markdown(xs_dict_get(snac->config, "bio"), NULL);
45+    xs *f_bio_2 = not_really_markdown(xs_dict_get(snac->config, "bio"), NULL);
46+    f_bio = process_tags(snac, f_bio_2, &tags);
47     msg = xs_dict_set(msg, "summary", f_bio);
48+    msg = xs_dict_set(msg, "tag", tags);
49 
50     char *folders[] = { "inbox", "outbox", "followers", "following", NULL };
51     for (n = 0; folders[n]; n++) {
52@@ -1053,7 +1060,7 @@ xs_dict *msg_note(snac *snac, const xs_str *content, const xs_val *rcpts,
53         irt = xs_val_new(XSTYPE_NULL);
54 
55     /* extract the mentions and hashtags and convert the content */
56-    process_tags(snac, fc2, &fc1, &tag);
57+    fc1 = process_tags(snac, fc2, &tag);
58 
59     /* create the attachment list, if there are any */
60     if (!xs_is_null(attach)) {
M data.c
+11, -6
 1@@ -496,9 +496,11 @@ xs_list *index_list(const char *fn, int max)
 2         list = xs_list_new();
 3 
 4         while (n < max && fgets(line, sizeof(line), f) != NULL) {
 5-            line[32] = '\0';
 6-            list = xs_list_append(list, line);
 7-            n++;
 8+            if (line[0] != '-') {
 9+                line[32] = '\0';
10+                list = xs_list_append(list, line);
11+                n++;
12+            }
13         }
14 
15         fclose(f);
16@@ -524,9 +526,11 @@ xs_list *index_list_desc(const char *fn, int skip, int show)
17         /* move to the end minus one entry (or more, if skipping entries) */
18         if (!fseek(f, 0, SEEK_END) && !fseek(f, (skip + 1) * -33, SEEK_CUR)) {
19             while (n < show && fgets(line, sizeof(line), f) != NULL) {
20-                line[32] = '\0';
21-                list = xs_list_append(list, line);
22-                n++;
23+                if (line[0] != '-') {
24+                    line[32] = '\0';
25+                    list = xs_list_append(list, line);
26+                    n++;
27+                }
28 
29                 /* move backwards 2 entries */
30                 if (fseek(f, -66, SEEK_CUR) == -1)
31@@ -862,6 +866,7 @@ int _object_user_cache(snac *snac, const char *id, const char *cachedir, int del
32 
33     if (del) {
34         ret = unlink(cfn);
35+        index_del(idx, id);
36     }
37     else {
38         if ((ret = link(ofn, cfn)) != -1)
M html.c
+32, -11
  1@@ -362,8 +362,10 @@ d_char *html_user_header(snac *snac, d_char *s, int local)
  2         s = xs_str_cat(s, s1);
  3 
  4         if (local) {
  5-            xs *bio = not_really_markdown(xs_dict_get(snac->config, "bio"), NULL);
  6-            xs *s1  = xs_fmt("<div class=\"p-note snac-top-user-bio\">%s</div>\n", bio);
  7+            xs *bio1 = not_really_markdown(xs_dict_get(snac->config, "bio"), NULL);
  8+            xs *tags = xs_list_new();
  9+            xs *bio2 = process_tags(snac, bio1, &tags);
 10+            xs *s1   = xs_fmt("<div class=\"p-note snac-top-user-bio\">%s</div>\n", bio2);
 11 
 12             s = xs_str_cat(s, s1);
 13         }
 14@@ -387,7 +389,8 @@ d_char *html_top_controls(snac *snac, d_char *s)
 15         "<textarea class=\"snac-textarea\" name=\"content\" "
 16         "rows=\"8\" wrap=\"virtual\" required=\"required\"></textarea>\n"
 17         "<input type=\"hidden\" name=\"in_reply_to\" value=\"\">\n"
 18-        "<p>%s: <input type=\"checkbox\" name=\"sensitive\">\n"
 19+        "<p>%s: <input type=\"checkbox\" name=\"sensitive\"> "
 20+        "<input type=\"text\" name=\"summary\" placeholder=\"%s\">\n"
 21         "<p>%s: <input type=\"checkbox\" name=\"mentioned_only\">\n"
 22 
 23         "<details><summary>%s</summary>\n" /** attach **/
 24@@ -512,6 +515,7 @@ d_char *html_top_controls(snac *snac, d_char *s)
 25     xs *s1 = xs_fmt(_tmpl,
 26         snac->actor,
 27         L("Sensitive content"),
 28+        L("Sensitive content description"),
 29         L("Only for mentioned people"),
 30 
 31         L("Attach..."),
 32@@ -684,8 +688,10 @@ xs_str *html_entry_controls(snac *snac, xs_str *os, const xs_dict *msg, const ch
 33 
 34     const char *prev_src1 = xs_dict_get(msg, "sourceContent");
 35 
 36-    if (!xs_is_null(prev_src1) && strcmp(actor, snac->actor) == 0) {
 37+    if (!xs_is_null(prev_src1) && strcmp(actor, snac->actor) == 0) { /** edit **/
 38         xs *prev_src = xs_replace(prev_src1, "<", "&lt;");
 39+        const xs_val *sensitive = xs_dict_get(msg, "sensitive");
 40+        const char *summary = xs_dict_get(msg, "summary");
 41 
 42         /* post can be edited */
 43         xs *s1 = xs_fmt(
 44@@ -697,7 +703,8 @@ xs_str *html_entry_controls(snac *snac, xs_str *os, const xs_dict *msg, const ch
 45             "rows=\"4\" wrap=\"virtual\" required=\"required\">%s</textarea>\n"
 46             "<input type=\"hidden\" name=\"edit_id\" value=\"%s\">\n"
 47 
 48-            "<p>%s: <input type=\"checkbox\" name=\"sensitive\">\n"
 49+            "<p>%s: <input type=\"checkbox\" name=\"sensitive\" %s> "
 50+            "<input type=\"text\" name=\"summary\" placeholder=\"%s\" value=\"%s\">\n"
 51             "<p>%s: <input type=\"checkbox\" name=\"mentioned_only\">\n"
 52 
 53             "<details><summary>%s</summary>\n"
 54@@ -717,6 +724,9 @@ xs_str *html_entry_controls(snac *snac, xs_str *os, const xs_dict *msg, const ch
 55             prev_src,
 56             id,
 57             L("Sensitive content"),
 58+            xs_type(sensitive) == XSTYPE_TRUE ? "checked" : "",
 59+            L("Sensitive content description"),
 60+            xs_is_null(summary) ? "" : summary,
 61             L("Only for mentioned people"),
 62             L("Attach..."),
 63             L("File"),
 64@@ -728,10 +738,13 @@ xs_str *html_entry_controls(snac *snac, xs_str *os, const xs_dict *msg, const ch
 65         s = xs_str_cat(s, s1);
 66     }
 67 
 68-    {
 69+    { /** reply **/
 70         /* the post textarea */
 71         xs *ct = build_mentions(snac, msg);
 72 
 73+        const xs_val *sensitive = xs_dict_get(msg, "sensitive");
 74+        const char *summary = xs_dict_get(msg, "summary");
 75+
 76         xs *s1 = xs_fmt(
 77             "<p><details><summary>%s</summary>\n"
 78             "<p><div class=\"snac-note\" id=\"%s_reply\">\n"
 79@@ -741,7 +754,8 @@ xs_str *html_entry_controls(snac *snac, xs_str *os, const xs_dict *msg, const ch
 80             "rows=\"4\" wrap=\"virtual\" required=\"required\">%s</textarea>\n"
 81             "<input type=\"hidden\" name=\"in_reply_to\" value=\"%s\">\n"
 82 
 83-            "<p>%s: <input type=\"checkbox\" name=\"sensitive\">\n"
 84+            "<p>%s: <input type=\"checkbox\" name=\"sensitive\" %s> "
 85+            "<input type=\"text\" name=\"summary\" placeholder=\"%s\" value=\"%s\">\n"
 86             "<p>%s: <input type=\"checkbox\" name=\"mentioned_only\">\n"
 87 
 88             "<details><summary>%s</summary>\n"
 89@@ -761,6 +775,9 @@ xs_str *html_entry_controls(snac *snac, xs_str *os, const xs_dict *msg, const ch
 90             ct,
 91             id,
 92             L("Sensitive content"),
 93+            xs_type(sensitive) == XSTYPE_TRUE ? "checked" : "",
 94+            L("Sensitive content description"),
 95+            xs_is_null(summary) ? "" : summary,
 96             L("Only for mentioned people"),
 97             L("Attach..."),
 98             L("File"),
 99@@ -1437,7 +1454,7 @@ xs_str *html_notifications(snac *snac)
100         "<form autocomplete=\"off\" "
101         "method=\"post\" action=\"%s/admin/clear-notifications\" id=\"clear\">\n"
102         "<input type=\"submit\" class=\"snac-btn-like\" value=\"%s\">\n"
103-        "</form><p>", snac->actor, L("Clear all"));
104+        "</form><p>\n", snac->actor, L("Clear all"));
105     s = xs_str_cat(s, s1);
106 
107     while (xs_list_iter(&p, &v)) {
108@@ -1498,16 +1515,19 @@ xs_str *html_notifications(snac *snac)
109         else
110         if (strcmp(type, "Update") == 0 && strcmp(utype, "Question") == 0)
111             label = L("Finished poll");
112+        else
113+        if (strcmp(type, "Undo") == 0 && strcmp(utype, "Follow") == 0)
114+            label = L("Unfollow");
115 
116         xs *s1 = xs_fmt("<div class=\"snac-post-with-desc\">\n"
117                         "<p><b>%s by <a href=\"%s\">%s</a></b>:</p>\n",
118             label, actor_id, a_name);
119         s = xs_str_cat(s, s1);
120 
121-        if (strcmp(type, "Follow") == 0) {
122+        if (strcmp(type, "Follow") == 0 || strcmp(utype, "Follow") == 0) {
123             s = xs_str_cat(s, "<div class=\"snac-post\">\n");
124 
125-            s = html_msg_icon(snac, s, obj);
126+            s = html_actor_icon(s, actor, NULL, NULL, NULL, 0);
127 
128             s = xs_str_cat(s, "</div>\n");
129         }
130@@ -1843,6 +1863,7 @@ int html_post_handler(const xs_dict *req, const char *q_path,
131         xs_list *attach_file = xs_dict_get(p_vars, "attach");
132         xs_str *to           = xs_dict_get(p_vars, "to");
133         xs_str *sensitive    = xs_dict_get(p_vars, "sensitive");
134+        xs_str *summary      = xs_dict_get(p_vars, "summary");
135         xs_str *edit_id      = xs_dict_get(p_vars, "edit_id");
136         xs_str *alt_text     = xs_dict_get(p_vars, "alt_text");
137         int priv             = !xs_is_null(xs_dict_get(p_vars, "mentioned_only"));
138@@ -1921,7 +1942,7 @@ int html_post_handler(const xs_dict *req, const char *q_path,
139 
140             if (sensitive != NULL) {
141                 msg = xs_dict_set(msg, "sensitive", xs_stock_true);
142-                msg = xs_dict_set(msg, "summary",   "...");
143+                msg = xs_dict_set(msg, "summary",   xs_is_null(summary) ? "..." : summary);
144             }
145 
146             if (xs_is_null(edit_id)) {
M snac.h
+2, -0
1@@ -207,6 +207,8 @@ int webfinger_get_handler(xs_dict *req, char *q_path,
2 
3 const char *default_avatar_base64(void);
4 
5+xs_str *process_tags(snac *snac, const char *content, xs_list **tag);
6+
7 xs_dict *msg_admiration(snac *snac, char *object, char *type);
8 xs_dict *msg_create(snac *snac, const xs_dict *object);
9 xs_dict *msg_follow(snac *snac, const char *actor);