summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--RELEASE_NOTES.md4
-rw-r--r--TODO.md13
-rw-r--r--activitypub.c17
-rw-r--r--data.c17
-rw-r--r--html.c43
-rw-r--r--snac.h2
6 files changed, 71 insertions, 25 deletions
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 4fbe71b..d6ce13c 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -4,6 +4,8 @@
4 4
5Added proper HTTP caching when serving static files (attached images, avatars, etc.) 5Added proper HTTP caching when serving static files (attached images, avatars, etc.)
6 6
7Sensitive content messages can now have a summary (i.e. no longer limited to ...)
8
7Added a way to block full instances (from the command-line tool, as I consider this to be an administration priviledge). 9Added a way to block full instances (from the command-line tool, as I consider this to be an administration priviledge).
8 10
9If the user style.css does not exist, the server-wide one if served instead. 11If the user style.css does not exist, the server-wide one if served instead.
@@ -18,6 +20,8 @@ For polls, show the time left before it closes.
18 20
19Added some support for post pinning. 21Added some support for post pinning.
20 22
23Fixed a bug that prevented unfollows to be shown in the notification area.
24
21## 2.35 25## 2.35
22 26
23Fixed broken URL links with the # symbol on them. 27Fixed broken URL links with the # symbol on them.
diff --git a/TODO.md b/TODO.md
index 6d4b430..7539883 100644
--- a/TODO.md
+++ b/TODO.md
@@ -12,8 +12,6 @@ Mastodon API: fix whatever the fuck is making the official app and Megalodon to
12 12
13Improve support for audio attachments. 13Improve support for audio attachments.
14 14
15Add a quick way to block complete domains / instances.
16
17Add support for pinning posts. 15Add support for pinning posts.
18 16
19Important: deleting a follower should do more that just delete the object, see https://codeberg.org/grunfink/snac2/issues/43#issuecomment-956721 17Important: deleting a follower should do more that just delete the object, see https://codeberg.org/grunfink/snac2/issues/43#issuecomment-956721
@@ -33,7 +31,8 @@ Implement bulleted lists. Mastodon is crap and won't show them, but other implem
33User 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." 31User 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."
34 32
35Test all the possible XSS vulnerabilities in https://raw.githubusercontent.com/danielmiessler/SecLists/master/Fuzzing/big-list-of-naughty-strings.txt 33Test all the possible XSS vulnerabilities in https://raw.githubusercontent.com/danielmiessler/SecLists/master/Fuzzing/big-list-of-naughty-strings.txt
36Minor 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() (?). 34
35index_list() and index_list_desc() should not return deleted (i.e. dash prefixed) entries.
37 36
38## Closed 37## Closed
39 38
@@ -260,3 +259,11 @@ Replace weird, vestigial 'touch-by-append-spaces' in actor_get() with a more pro
260With 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). 259With 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).
261 260
262Implement HTTP caches (If-None-Match / ETag) (2023-07-02T11:11:20+0200). 261Implement HTTP caches (If-None-Match / ETag) (2023-07-02T11:11:20+0200).
262
263Add a quick way to block complete domains / instances (2023-07-04T14:35:44+0200).
264
265_object_user_cache() should call index_del() (2023-07-04T14:36:37+0200).
266
267Add a content warning description (2023-07-04T15:02:19+0200).
268
269Propagate the CW status and description from the replied message (2023-07-04T15:02:19+0200).
diff --git a/activitypub.c b/activitypub.c
index ce72f3f..fa592e7 100644
--- a/activitypub.c
+++ b/activitypub.c
@@ -449,7 +449,7 @@ int is_msg_for_me(snac *snac, const xs_dict *c_msg)
449} 449}
450 450
451 451
452void process_tags(snac *snac, const char *content, xs_str **n_content, xs_list **tag) 452xs_str *process_tags(snac *snac, const char *content, xs_list **tag)
453/* parses mentions and tags from content */ 453/* parses mentions and tags from content */
454{ 454{
455 xs_str *nc = xs_str_new(NULL); 455 xs_str *nc = xs_str_new(NULL);
@@ -559,8 +559,9 @@ void process_tags(snac *snac, const char *content, xs_str **n_content, xs_list *
559 n++; 559 n++;
560 } 560 }
561 561
562 *n_content = nc; 562 *tag = tl;
563 *tag = tl; 563
564 return nc;
564} 565}
565 566
566 567
@@ -688,6 +689,9 @@ void notify(snac *snac, const char *type, const char *utype, const char *actor,
688 /* finally, store it in the notification folder */ 689 /* finally, store it in the notification folder */
689 if (strcmp(type, "Follow") == 0) 690 if (strcmp(type, "Follow") == 0)
690 objid = id; 691 objid = id;
692 else
693 if (strcmp(utype, "Follow") == 0)
694 objid = actor;
691 695
692 notify_add(snac, type, utype, actor, objid != NULL ? objid : id); 696 notify_add(snac, type, utype, actor, objid != NULL ? objid : id);
693} 697}
@@ -836,6 +840,7 @@ xs_dict *msg_actor(snac *snac)
836 xs *ctxt = xs_list_new(); 840 xs *ctxt = xs_list_new();
837 xs *icon = xs_dict_new(); 841 xs *icon = xs_dict_new();
838 xs *keys = xs_dict_new(); 842 xs *keys = xs_dict_new();
843 xs *tags = xs_list_new();
839 xs *avtr = NULL; 844 xs *avtr = NULL;
840 xs *kid = NULL; 845 xs *kid = NULL;
841 xs *f_bio = NULL; 846 xs *f_bio = NULL;
@@ -853,8 +858,10 @@ xs_dict *msg_actor(snac *snac)
853 msg = xs_dict_set(msg, "preferredUsername", snac->uid); 858 msg = xs_dict_set(msg, "preferredUsername", snac->uid);
854 msg = xs_dict_set(msg, "published", xs_dict_get(snac->config, "published")); 859 msg = xs_dict_set(msg, "published", xs_dict_get(snac->config, "published"));
855 860
856 f_bio = not_really_markdown(xs_dict_get(snac->config, "bio"), NULL); 861 xs *f_bio_2 = not_really_markdown(xs_dict_get(snac->config, "bio"), NULL);
862 f_bio = process_tags(snac, f_bio_2, &tags);
857 msg = xs_dict_set(msg, "summary", f_bio); 863 msg = xs_dict_set(msg, "summary", f_bio);
864 msg = xs_dict_set(msg, "tag", tags);
858 865
859 char *folders[] = { "inbox", "outbox", "followers", "following", NULL }; 866 char *folders[] = { "inbox", "outbox", "followers", "following", NULL };
860 for (n = 0; folders[n]; n++) { 867 for (n = 0; folders[n]; n++) {
@@ -1053,7 +1060,7 @@ xs_dict *msg_note(snac *snac, const xs_str *content, const xs_val *rcpts,
1053 irt = xs_val_new(XSTYPE_NULL); 1060 irt = xs_val_new(XSTYPE_NULL);
1054 1061
1055 /* extract the mentions and hashtags and convert the content */ 1062 /* extract the mentions and hashtags and convert the content */
1056 process_tags(snac, fc2, &fc1, &tag); 1063 fc1 = process_tags(snac, fc2, &tag);
1057 1064
1058 /* create the attachment list, if there are any */ 1065 /* create the attachment list, if there are any */
1059 if (!xs_is_null(attach)) { 1066 if (!xs_is_null(attach)) {
diff --git a/data.c b/data.c
index 87cfc98..c466598 100644
--- a/data.c
+++ b/data.c
@@ -496,9 +496,11 @@ xs_list *index_list(const char *fn, int max)
496 list = xs_list_new(); 496 list = xs_list_new();
497 497
498 while (n < max && fgets(line, sizeof(line), f) != NULL) { 498 while (n < max && fgets(line, sizeof(line), f) != NULL) {
499 line[32] = '\0'; 499 if (line[0] != '-') {
500 list = xs_list_append(list, line); 500 line[32] = '\0';
501 n++; 501 list = xs_list_append(list, line);
502 n++;
503 }
502 } 504 }
503 505
504 fclose(f); 506 fclose(f);
@@ -524,9 +526,11 @@ xs_list *index_list_desc(const char *fn, int skip, int show)
524 /* move to the end minus one entry (or more, if skipping entries) */ 526 /* move to the end minus one entry (or more, if skipping entries) */
525 if (!fseek(f, 0, SEEK_END) && !fseek(f, (skip + 1) * -33, SEEK_CUR)) { 527 if (!fseek(f, 0, SEEK_END) && !fseek(f, (skip + 1) * -33, SEEK_CUR)) {
526 while (n < show && fgets(line, sizeof(line), f) != NULL) { 528 while (n < show && fgets(line, sizeof(line), f) != NULL) {
527 line[32] = '\0'; 529 if (line[0] != '-') {
528 list = xs_list_append(list, line); 530 line[32] = '\0';
529 n++; 531 list = xs_list_append(list, line);
532 n++;
533 }
530 534
531 /* move backwards 2 entries */ 535 /* move backwards 2 entries */
532 if (fseek(f, -66, SEEK_CUR) == -1) 536 if (fseek(f, -66, SEEK_CUR) == -1)
@@ -862,6 +866,7 @@ int _object_user_cache(snac *snac, const char *id, const char *cachedir, int del
862 866
863 if (del) { 867 if (del) {
864 ret = unlink(cfn); 868 ret = unlink(cfn);
869 index_del(idx, id);
865 } 870 }
866 else { 871 else {
867 if ((ret = link(ofn, cfn)) != -1) 872 if ((ret = link(ofn, cfn)) != -1)
diff --git a/html.c b/html.c
index 425df4b..2eb542a 100644
--- a/html.c
+++ b/html.c
@@ -362,8 +362,10 @@ d_char *html_user_header(snac *snac, d_char *s, int local)
362 s = xs_str_cat(s, s1); 362 s = xs_str_cat(s, s1);
363 363
364 if (local) { 364 if (local) {
365 xs *bio = not_really_markdown(xs_dict_get(snac->config, "bio"), NULL); 365 xs *bio1 = not_really_markdown(xs_dict_get(snac->config, "bio"), NULL);
366 xs *s1 = xs_fmt("<div class=\"p-note snac-top-user-bio\">%s</div>\n", bio); 366 xs *tags = xs_list_new();
367 xs *bio2 = process_tags(snac, bio1, &tags);
368 xs *s1 = xs_fmt("<div class=\"p-note snac-top-user-bio\">%s</div>\n", bio2);
367 369
368 s = xs_str_cat(s, s1); 370 s = xs_str_cat(s, s1);
369 } 371 }
@@ -387,7 +389,8 @@ d_char *html_top_controls(snac *snac, d_char *s)
387 "<textarea class=\"snac-textarea\" name=\"content\" " 389 "<textarea class=\"snac-textarea\" name=\"content\" "
388 "rows=\"8\" wrap=\"virtual\" required=\"required\"></textarea>\n" 390 "rows=\"8\" wrap=\"virtual\" required=\"required\"></textarea>\n"
389 "<input type=\"hidden\" name=\"in_reply_to\" value=\"\">\n" 391 "<input type=\"hidden\" name=\"in_reply_to\" value=\"\">\n"
390 "<p>%s: <input type=\"checkbox\" name=\"sensitive\">\n" 392 "<p>%s: <input type=\"checkbox\" name=\"sensitive\"> "
393 "<input type=\"text\" name=\"summary\" placeholder=\"%s\">\n"
391 "<p>%s: <input type=\"checkbox\" name=\"mentioned_only\">\n" 394 "<p>%s: <input type=\"checkbox\" name=\"mentioned_only\">\n"
392 395
393 "<details><summary>%s</summary>\n" /** attach **/ 396 "<details><summary>%s</summary>\n" /** attach **/
@@ -512,6 +515,7 @@ d_char *html_top_controls(snac *snac, d_char *s)
512 xs *s1 = xs_fmt(_tmpl, 515 xs *s1 = xs_fmt(_tmpl,
513 snac->actor, 516 snac->actor,
514 L("Sensitive content"), 517 L("Sensitive content"),
518 L("Sensitive content description"),
515 L("Only for mentioned people"), 519 L("Only for mentioned people"),
516 520
517 L("Attach..."), 521 L("Attach..."),
@@ -684,8 +688,10 @@ xs_str *html_entry_controls(snac *snac, xs_str *os, const xs_dict *msg, const ch
684 688
685 const char *prev_src1 = xs_dict_get(msg, "sourceContent"); 689 const char *prev_src1 = xs_dict_get(msg, "sourceContent");
686 690
687 if (!xs_is_null(prev_src1) && strcmp(actor, snac->actor) == 0) { 691 if (!xs_is_null(prev_src1) && strcmp(actor, snac->actor) == 0) { /** edit **/
688 xs *prev_src = xs_replace(prev_src1, "<", "&lt;"); 692 xs *prev_src = xs_replace(prev_src1, "<", "&lt;");
693 const xs_val *sensitive = xs_dict_get(msg, "sensitive");
694 const char *summary = xs_dict_get(msg, "summary");
689 695
690 /* post can be edited */ 696 /* post can be edited */
691 xs *s1 = xs_fmt( 697 xs *s1 = xs_fmt(
@@ -697,7 +703,8 @@ xs_str *html_entry_controls(snac *snac, xs_str *os, const xs_dict *msg, const ch
697 "rows=\"4\" wrap=\"virtual\" required=\"required\">%s</textarea>\n" 703 "rows=\"4\" wrap=\"virtual\" required=\"required\">%s</textarea>\n"
698 "<input type=\"hidden\" name=\"edit_id\" value=\"%s\">\n" 704 "<input type=\"hidden\" name=\"edit_id\" value=\"%s\">\n"
699 705
700 "<p>%s: <input type=\"checkbox\" name=\"sensitive\">\n" 706 "<p>%s: <input type=\"checkbox\" name=\"sensitive\" %s> "
707 "<input type=\"text\" name=\"summary\" placeholder=\"%s\" value=\"%s\">\n"
701 "<p>%s: <input type=\"checkbox\" name=\"mentioned_only\">\n" 708 "<p>%s: <input type=\"checkbox\" name=\"mentioned_only\">\n"
702 709
703 "<details><summary>%s</summary>\n" 710 "<details><summary>%s</summary>\n"
@@ -717,6 +724,9 @@ xs_str *html_entry_controls(snac *snac, xs_str *os, const xs_dict *msg, const ch
717 prev_src, 724 prev_src,
718 id, 725 id,
719 L("Sensitive content"), 726 L("Sensitive content"),
727 xs_type(sensitive) == XSTYPE_TRUE ? "checked" : "",
728 L("Sensitive content description"),
729 xs_is_null(summary) ? "" : summary,
720 L("Only for mentioned people"), 730 L("Only for mentioned people"),
721 L("Attach..."), 731 L("Attach..."),
722 L("File"), 732 L("File"),
@@ -728,10 +738,13 @@ xs_str *html_entry_controls(snac *snac, xs_str *os, const xs_dict *msg, const ch
728 s = xs_str_cat(s, s1); 738 s = xs_str_cat(s, s1);
729 } 739 }
730 740
731 { 741 { /** reply **/
732 /* the post textarea */ 742 /* the post textarea */
733 xs *ct = build_mentions(snac, msg); 743 xs *ct = build_mentions(snac, msg);
734 744
745 const xs_val *sensitive = xs_dict_get(msg, "sensitive");
746 const char *summary = xs_dict_get(msg, "summary");
747
735 xs *s1 = xs_fmt( 748 xs *s1 = xs_fmt(
736 "<p><details><summary>%s</summary>\n" 749 "<p><details><summary>%s</summary>\n"
737 "<p><div class=\"snac-note\" id=\"%s_reply\">\n" 750 "<p><div class=\"snac-note\" id=\"%s_reply\">\n"
@@ -741,7 +754,8 @@ xs_str *html_entry_controls(snac *snac, xs_str *os, const xs_dict *msg, const ch
741 "rows=\"4\" wrap=\"virtual\" required=\"required\">%s</textarea>\n" 754 "rows=\"4\" wrap=\"virtual\" required=\"required\">%s</textarea>\n"
742 "<input type=\"hidden\" name=\"in_reply_to\" value=\"%s\">\n" 755 "<input type=\"hidden\" name=\"in_reply_to\" value=\"%s\">\n"
743 756
744 "<p>%s: <input type=\"checkbox\" name=\"sensitive\">\n" 757 "<p>%s: <input type=\"checkbox\" name=\"sensitive\" %s> "
758 "<input type=\"text\" name=\"summary\" placeholder=\"%s\" value=\"%s\">\n"
745 "<p>%s: <input type=\"checkbox\" name=\"mentioned_only\">\n" 759 "<p>%s: <input type=\"checkbox\" name=\"mentioned_only\">\n"
746 760
747 "<details><summary>%s</summary>\n" 761 "<details><summary>%s</summary>\n"
@@ -761,6 +775,9 @@ xs_str *html_entry_controls(snac *snac, xs_str *os, const xs_dict *msg, const ch
761 ct, 775 ct,
762 id, 776 id,
763 L("Sensitive content"), 777 L("Sensitive content"),
778 xs_type(sensitive) == XSTYPE_TRUE ? "checked" : "",
779 L("Sensitive content description"),
780 xs_is_null(summary) ? "" : summary,
764 L("Only for mentioned people"), 781 L("Only for mentioned people"),
765 L("Attach..."), 782 L("Attach..."),
766 L("File"), 783 L("File"),
@@ -1437,7 +1454,7 @@ xs_str *html_notifications(snac *snac)
1437 "<form autocomplete=\"off\" " 1454 "<form autocomplete=\"off\" "
1438 "method=\"post\" action=\"%s/admin/clear-notifications\" id=\"clear\">\n" 1455 "method=\"post\" action=\"%s/admin/clear-notifications\" id=\"clear\">\n"
1439 "<input type=\"submit\" class=\"snac-btn-like\" value=\"%s\">\n" 1456 "<input type=\"submit\" class=\"snac-btn-like\" value=\"%s\">\n"
1440 "</form><p>", snac->actor, L("Clear all")); 1457 "</form><p>\n", snac->actor, L("Clear all"));
1441 s = xs_str_cat(s, s1); 1458 s = xs_str_cat(s, s1);
1442 1459
1443 while (xs_list_iter(&p, &v)) { 1460 while (xs_list_iter(&p, &v)) {
@@ -1498,16 +1515,19 @@ xs_str *html_notifications(snac *snac)
1498 else 1515 else
1499 if (strcmp(type, "Update") == 0 && strcmp(utype, "Question") == 0) 1516 if (strcmp(type, "Update") == 0 && strcmp(utype, "Question") == 0)
1500 label = L("Finished poll"); 1517 label = L("Finished poll");
1518 else
1519 if (strcmp(type, "Undo") == 0 && strcmp(utype, "Follow") == 0)
1520 label = L("Unfollow");
1501 1521
1502 xs *s1 = xs_fmt("<div class=\"snac-post-with-desc\">\n" 1522 xs *s1 = xs_fmt("<div class=\"snac-post-with-desc\">\n"
1503 "<p><b>%s by <a href=\"%s\">%s</a></b>:</p>\n", 1523 "<p><b>%s by <a href=\"%s\">%s</a></b>:</p>\n",
1504 label, actor_id, a_name); 1524 label, actor_id, a_name);
1505 s = xs_str_cat(s, s1); 1525 s = xs_str_cat(s, s1);
1506 1526
1507 if (strcmp(type, "Follow") == 0) { 1527 if (strcmp(type, "Follow") == 0 || strcmp(utype, "Follow") == 0) {
1508 s = xs_str_cat(s, "<div class=\"snac-post\">\n"); 1528 s = xs_str_cat(s, "<div class=\"snac-post\">\n");
1509 1529
1510 s = html_msg_icon(snac, s, obj); 1530 s = html_actor_icon(s, actor, NULL, NULL, NULL, 0);
1511 1531
1512 s = xs_str_cat(s, "</div>\n"); 1532 s = xs_str_cat(s, "</div>\n");
1513 } 1533 }
@@ -1843,6 +1863,7 @@ int html_post_handler(const xs_dict *req, const char *q_path,
1843 xs_list *attach_file = xs_dict_get(p_vars, "attach"); 1863 xs_list *attach_file = xs_dict_get(p_vars, "attach");
1844 xs_str *to = xs_dict_get(p_vars, "to"); 1864 xs_str *to = xs_dict_get(p_vars, "to");
1845 xs_str *sensitive = xs_dict_get(p_vars, "sensitive"); 1865 xs_str *sensitive = xs_dict_get(p_vars, "sensitive");
1866 xs_str *summary = xs_dict_get(p_vars, "summary");
1846 xs_str *edit_id = xs_dict_get(p_vars, "edit_id"); 1867 xs_str *edit_id = xs_dict_get(p_vars, "edit_id");
1847 xs_str *alt_text = xs_dict_get(p_vars, "alt_text"); 1868 xs_str *alt_text = xs_dict_get(p_vars, "alt_text");
1848 int priv = !xs_is_null(xs_dict_get(p_vars, "mentioned_only")); 1869 int priv = !xs_is_null(xs_dict_get(p_vars, "mentioned_only"));
@@ -1921,7 +1942,7 @@ int html_post_handler(const xs_dict *req, const char *q_path,
1921 1942
1922 if (sensitive != NULL) { 1943 if (sensitive != NULL) {
1923 msg = xs_dict_set(msg, "sensitive", xs_stock_true); 1944 msg = xs_dict_set(msg, "sensitive", xs_stock_true);
1924 msg = xs_dict_set(msg, "summary", "..."); 1945 msg = xs_dict_set(msg, "summary", xs_is_null(summary) ? "..." : summary);
1925 } 1946 }
1926 1947
1927 if (xs_is_null(edit_id)) { 1948 if (xs_is_null(edit_id)) {
diff --git a/snac.h b/snac.h
index 74f4969..171d069 100644
--- a/snac.h
+++ b/snac.h
@@ -207,6 +207,8 @@ int webfinger_get_handler(xs_dict *req, char *q_path,
207 207
208const char *default_avatar_base64(void); 208const char *default_avatar_base64(void);
209 209
210xs_str *process_tags(snac *snac, const char *content, xs_list **tag);
211
210xs_dict *msg_admiration(snac *snac, char *object, char *type); 212xs_dict *msg_admiration(snac *snac, char *object, char *type);
211xs_dict *msg_create(snac *snac, const xs_dict *object); 213xs_dict *msg_create(snac *snac, const xs_dict *object);
212xs_dict *msg_follow(snac *snac, const char *actor); 214xs_dict *msg_follow(snac *snac, const char *actor);