From cce687bd601680741e93ab75da3d02a99c676387 Mon Sep 17 00:00:00 2001 From: grunfink Date: Fri, 31 Jul 2026 08:26:22 +0200 Subject: Mark actors from boosted posts as non-broken. --- activitypub.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index 514e764..39029b6 100644 --- a/activitypub.c +++ b/activitypub.c @@ -3053,6 +3053,9 @@ int process_input_message(snac *snac, const xs_dict *msg, const xs_dict *req) /* distribute the post to users following these hashtags */ followed_hashtag_distribute(a_msg); + /* actor is [back] alive */ + actor_failure(who, 2); + do_notify = 1; } else -- cgit From de81a9c59ab513ce473cdca1091fdd81de9fe45e Mon Sep 17 00:00:00 2001 From: grunfink Date: Mon, 3 Aug 2026 04:54:03 +0200 Subject: When mentioning, allow users with - in their names. --- activitypub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index 39029b6..92eb7f5 100644 --- a/activitypub.c +++ b/activitypub.c @@ -940,7 +940,7 @@ xs_str *process_tags(snac *snac, const char *content, xs_list **tag) /* use this same server */ def_srv = xs_dup(xs_dict_get(srv_config, "host")); - split = xs_regex_split(content, "(@[A-Za-z0-9_]+(@[A-Za-z0-9\\.-]+)?|&#[0-9]+;|#(_|[^[:punct:][:space:]])+)"); + split = xs_regex_split(content, "(@[A-Za-z0-9_-]+(@[A-Za-z0-9\\.-]+)?|&#[0-9]+;|#(_|[^[:punct:][:space:]])+)"); p = split; while (xs_list_iter(&p, &v)) { -- cgit From 71a83e6578f910c3baa251e4128208b201ce9e45 Mon Sep 17 00:00:00 2001 From: default Date: Wed, 26 Aug 2026 07:59:23 +0200 Subject: Use snac_op in actor_failure(). --- activitypub.c | 10 +++++----- data.c | 11 +++++++---- html.c | 2 +- snac.h | 10 +++++++++- 4 files changed, 22 insertions(+), 11 deletions(-) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index 92eb7f5..4de0be7 100644 --- a/activitypub.c +++ b/activitypub.c @@ -3054,7 +3054,7 @@ int process_input_message(snac *snac, const xs_dict *msg, const xs_dict *req) followed_hashtag_distribute(a_msg); /* actor is [back] alive */ - actor_failure(who, 2); + actor_failure(who, OP_DEL); do_notify = 1; } @@ -3461,7 +3461,7 @@ void process_user_queue_item(snac *user, xs_dict *q_item) const char *actor = xs_dict_get(q_item, "actor"); double mtime = object_mtime(actor); - if (actor_failure(actor, 0) == -1) { + if (actor_failure(actor, OP_CHECK) == -1) { /* actor is broken beyond repair */ snac_debug(user, 1, xs_fmt("actor_refresh skipped broken actor %s", actor)); } @@ -3478,16 +3478,16 @@ void process_user_queue_item(snac *user, xs_dict *q_item) actor_add(actor, actor_o); /* mark actor and instance as working */ - actor_failure(actor, 2); + actor_failure(actor, OP_DEL); instance_failure(actor, 2); } else { if (status == HTTP_STATUS_GONE || status == HTTP_STATUS_NOT_FOUND) { - actor_failure(actor, 1); + actor_failure(actor, OP_ADD); snac_log(user, xs_fmt("actor_refresh marking actor %s as broken %d", actor, status)); } else { - actor_failure(actor, 2); + actor_failure(actor, OP_DEL); object_touch(actor); } } diff --git a/data.c b/data.c index 806938c..7a8f884 100644 --- a/data.c +++ b/data.c @@ -3233,7 +3233,7 @@ xs_list *content_search(snac *user, const char *regex, } -int actor_failure(const char *actor, int op) +int actor_failure(const char *actor, snac_op op) /* actor failure maintenance */ { int ret = 0; @@ -3242,13 +3242,13 @@ int actor_failure(const char *actor, int op) xs *fn = xs_fmt("%s/failure/%s", srv_basedir, md5); switch (op) { - case 0: /** check **/ + case OP_CHECK: /** check **/ if (mtime(fn)) ret = -1; break; - case 1: /** register a failure **/ + case OP_ADD: /** register a failure **/ if (mtime(fn) == 0.0) { FILE *f; @@ -3261,11 +3261,14 @@ int actor_failure(const char *actor, int op) break; - case 2: /** clear a failure **/ + case OP_DEL: /** clear a failure **/ /* called whenever a message comes from this instance */ unlink(fn); break; + + default: + break; } return ret; diff --git a/html.c b/html.c index 3f35040..f18e233 100644 --- a/html.c +++ b/html.c @@ -362,7 +362,7 @@ xs_html *html_actor_icon(snac *user, xs_dict *actor, const char *date, xs_html_raw("💔"))); } - if (actor_failure(actor_id, 0) == -1) { + if (actor_failure(actor_id, OP_CHECK) == -1) { xs_html_add(actor_icon, xs_html_text(" "), xs_html_tag("span", diff --git a/snac.h b/snac.h index 1644315..602fa0c 100644 --- a/snac.h +++ b/snac.h @@ -79,6 +79,14 @@ typedef struct { enum { THST_STOP, THST_WAIT, THST_IN, THST_QUEUE } th_state[MAX_THREADS]; } srv_state; +typedef enum { + OP_CHECK = 0, + OP_ADD = 1, + OP_DEL = 2, + OP_LIST = 3, + OP_FIND = 4 +} snac_op; + extern srv_state *p_state; enum { @@ -300,7 +308,7 @@ int content_match(const char *file, const xs_dict *msg); xs_list *content_search(snac *user, const char *regex, int priv, int skip, int show, int max_secs, int *timeout); -int actor_failure(const char *actor, int op); +int actor_failure(const char *actor, snac_op op); int instance_failure(const char *url, int op); int grave(const char *objid, int op); -- cgit From 48aba53ddbca75bfdbda7d224c6d2c315fcd282a Mon Sep 17 00:00:00 2001 From: default Date: Wed, 26 Aug 2026 08:02:41 +0200 Subject: Use snac_op in instance_failure(). --- activitypub.c | 10 +++++----- data.c | 11 +++++++---- rss.c | 2 +- snac.h | 2 +- 4 files changed, 14 insertions(+), 11 deletions(-) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index 4de0be7..8155fe4 100644 --- a/activitypub.c +++ b/activitypub.c @@ -2594,7 +2594,7 @@ int process_input_message(snac *snac, const xs_dict *msg, const xs_dict *req) } /* this instance is alive */ - instance_failure(actor, 2); + instance_failure(actor, OP_DEL); /* question votes may not have a type */ if (xs_is_null(type)) @@ -3029,7 +3029,7 @@ int process_input_message(snac *snac, const xs_dict *msg, const xs_dict *req) const char *who = get_atto(a_msg); /* got the admired object: instance is [back] online */ - instance_failure(object, 2); + instance_failure(object, OP_DEL); if (who && !is_muted(snac, who)) { /* bring the actor */ @@ -3479,7 +3479,7 @@ void process_user_queue_item(snac *user, xs_dict *q_item) /* mark actor and instance as working */ actor_failure(actor, OP_DEL); - instance_failure(actor, 2); + instance_failure(actor, OP_DEL); } else { if (status == HTTP_STATUS_GONE || status == HTTP_STATUS_NOT_FOUND) { @@ -3604,7 +3604,7 @@ void process_queue_item(xs_dict *q_item) return; } - if (instance_failure(inbox, 0)) { + if (instance_failure(inbox, OP_CHECK)) { srv_debug(1, xs_fmt("output message error: too many failures for instance %s", inbox)); return; } @@ -3621,7 +3621,7 @@ void process_queue_item(xs_dict *q_item) status = send_to_inbox_raw(keyid, seckey, inbox, msg, &payload, &p_size, timeout); /* register or clear a value for this instance */ - instance_failure(inbox, valid_status(status) ? 2 : 1); + instance_failure(inbox, valid_status(status) ? OP_DEL : OP_ADD); if (payload) { if (p_size > 1024) { diff --git a/data.c b/data.c index 7a8f884..3736bc9 100644 --- a/data.c +++ b/data.c @@ -3275,7 +3275,7 @@ int actor_failure(const char *actor, snac_op op) } -int instance_failure(const char *url, int op) +int instance_failure(const char *url, snac_op op) /* do some checks and accounting on instance failures */ { int ret = 0; @@ -3290,7 +3290,7 @@ int instance_failure(const char *url, int op) xs *fn = xs_fmt("%s/failure/%s", srv_basedir, md5); switch (op) { - case 0: /** check **/ + case OP_CHECK: /** check **/ if ((mt = mtime(fn)) != 0.0) { /* grace time */ double seconds_failing = xs_number_get(xs_dict_get_def(srv_config, "max_failing_days", "15")) @@ -3302,7 +3302,7 @@ int instance_failure(const char *url, int op) break; - case 1: /** register a failure **/ + case OP_ADD: /** register a failure **/ if (mtime(fn) == 0.0) { FILE *f; @@ -3315,11 +3315,14 @@ int instance_failure(const char *url, int op) break; - case 2: /** clear a failure **/ + case OP_DEL: /** clear a failure **/ /* called whenever a message comes from this instance */ unlink(fn); break; + + default: + break; } return ret; diff --git a/rss.c b/rss.c index 9b4ae65..5ec85cb 100644 --- a/rss.c +++ b/rss.c @@ -282,7 +282,7 @@ void rss_to_timeline(snac *user, const char *url) continue; /* the instance is [back] online */ - instance_failure(id, 2); + instance_failure(id, OP_DEL); if (timeline_here(user, id)) { snac_debug(user, 1, xs_fmt("RSS entry already in timeline (id) %s", id)); diff --git a/snac.h b/snac.h index 602fa0c..d21c7ad 100644 --- a/snac.h +++ b/snac.h @@ -309,7 +309,7 @@ xs_list *content_search(snac *user, const char *regex, int priv, int skip, int show, int max_secs, int *timeout); int actor_failure(const char *actor, snac_op op); -int instance_failure(const char *url, int op); +int instance_failure(const char *url, snac_op op); int grave(const char *objid, int op); -- cgit From d7fc3d950d4654a3291066fed667f1b7d48e70bb Mon Sep 17 00:00:00 2001 From: default Date: Wed, 26 Aug 2026 08:05:16 +0200 Subject: Use snac_op in grave(). --- activitypub.c | 4 ++-- data.c | 11 +++++++---- html.c | 2 +- snac.h | 2 +- utils.c | 4 ++-- 5 files changed, 13 insertions(+), 10 deletions(-) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index 8155fe4..df319f0 100644 --- a/activitypub.c +++ b/activitypub.c @@ -3951,7 +3951,7 @@ int activitypub_get_handler(const xs_dict *req, const char *q_path, uid = xs_list_get(l, 1); if (!user_open(&snac, uid)) { /* invalid user */ - status = grave(uid, 0) ? HTTP_STATUS_GONE : HTTP_STATUS_NOT_FOUND; + status = grave(uid, OP_CHECK) ? HTTP_STATUS_GONE : HTTP_STATUS_NOT_FOUND; srv_debug(1, xs_fmt("activitypub_get_handler bad user %s %d", uid, status)); return status; } @@ -4151,7 +4151,7 @@ int activitypub_post_handler(const xs_dict *req, const char *q_path, const char *uid = xs_list_get(l, 1); if (!user_open(&snac, uid)) { /* invalid user */ - status = grave(uid, 0) ? HTTP_STATUS_GONE : HTTP_STATUS_NOT_FOUND; + status = grave(uid, OP_CHECK) ? HTTP_STATUS_GONE : HTTP_STATUS_NOT_FOUND; srv_debug(1, xs_fmt("activitypub_post_handler bad user %s %d", uid, status)); return status; } diff --git a/data.c b/data.c index 3736bc9..333ed31 100644 --- a/data.c +++ b/data.c @@ -3329,7 +3329,7 @@ int instance_failure(const char *url, snac_op op) } -int grave(const char *objid, int op) +int grave(const char *objid, snac_op op) /* the graveyeard of deleted objects */ { int ret = 0; @@ -3339,11 +3339,11 @@ int grave(const char *objid, int op) FILE *f; switch (op) { - case 0: /** check **/ + case OP_CHECK: /** check **/ ret = mtime(fn) > 0.0 ? 1 : 0; break; - case 1: /** add **/ + case OP_ADD: /** add **/ mkdirx(dir); if ((f = fopen(fn, "w")) != NULL) { @@ -3353,9 +3353,12 @@ int grave(const char *objid, int op) break; - case 2: /** del **/ + case OP_DEL: /** del **/ unlink(fn); break; + + default: + break; } return ret; diff --git a/html.c b/html.c index f18e233..8f177cc 100644 --- a/html.c +++ b/html.c @@ -4717,7 +4717,7 @@ int html_get_handler(const xs_dict *req, const char *q_path, if (!uid || !user_open(&snac, uid)) { /* invalid user */ - status = grave(uid, 0) ? HTTP_STATUS_GONE : HTTP_STATUS_NOT_FOUND; + status = grave(uid, OP_CHECK) ? HTTP_STATUS_GONE : HTTP_STATUS_NOT_FOUND; srv_debug(2, xs_fmt("html_get_handler bad user '%s' %d", xs_or(uid, "(null)"), status)); return status; } diff --git a/snac.h b/snac.h index d21c7ad..84223e6 100644 --- a/snac.h +++ b/snac.h @@ -311,7 +311,7 @@ xs_list *content_search(snac *user, const char *regex, int actor_failure(const char *actor, snac_op op); int instance_failure(const char *url, snac_op op); -int grave(const char *objid, int op); +int grave(const char *objid, snac_op op); void enqueue_input(snac *snac, const xs_dict *msg, const xs_dict *req, int retries); void enqueue_shared_input(const xs_dict *msg, const xs_dict *req, int retries); diff --git a/utils.c b/utils.c index 6941081..c1855b2 100644 --- a/utils.c +++ b/utils.c @@ -372,7 +372,7 @@ int adduser(const char *uid) } /* remove the grave */ - grave(uid, 2); + grave(uid, OP_DEL); printf("\nUser password is %s\n", pwd); @@ -467,7 +467,7 @@ int deluser(snac *user) } } - grave(user->uid, 1); + grave(user->uid, OP_ADD); rm_rf(user->basedir); -- cgit From 748b578c96bb5d6c3b372d533bc374e2fb918348 Mon Sep 17 00:00:00 2001 From: grunfink Date: Sun, 30 Aug 2026 07:43:18 +0200 Subject: Fixed EmojiReact code to allow any emoticon in emojis.json, not only those with colon-wrapped ids. --- activitypub.c | 6 +++--- html.c | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index df319f0..bb6de13 100644 --- a/activitypub.c +++ b/activitypub.c @@ -1607,7 +1607,7 @@ xs_dict *msg_emoji_init(snac *snac, const char *mid, const char *eid_o) { xs_dict *n_msg = msg_admiration(snac, mid, "EmojiReact"); - xs *eid = xs_strip_chars_i(xs_dup(eid_o), ":"); + xs *eid = xs_dup(eid_o); xs *content = NULL; xs *tag = xs_list_new(); xs *dict = xs_dict_new(); @@ -1623,14 +1623,14 @@ xs_dict *msg_emoji_init(snac *snac, const char *mid, const char *eid_o) content = xs_dup(eid); else if (*eid == '%') { - content = xs_url_dec_emoji(xs_dup(eid)); + content = xs_url_dec_emoji(eid); if (content == NULL) { xs_free(n_msg); return NULL; } } else { - content = xs_fmt(":%s:", eid); + content = xs_dup(eid); const char *emo = xs_dict_get(emjs, content); if (emo == NULL) { diff --git a/html.c b/html.c index e5c84fb..134cc87 100644 --- a/html.c +++ b/html.c @@ -5727,8 +5727,6 @@ int html_post_handler(const xs_dict *req, const char *q_path, if (strcmp(action, L("EmojiReact")) == 0) { /** **/ xs *eid = xs_dup(xs_dict_get(p_vars, "eid")); - eid = xs_strip_chars_i(eid, ":"); - xs *ret = msg_emoji_init(&snac, id, eid); /* fails if either invalid or already reacted */ if (!ret) { -- cgit From eea4e1fbce6915c598a0a2211a88f7389c47c0a2 Mon Sep 17 00:00:00 2001 From: grunfink Date: Sun, 30 Aug 2026 08:03:22 +0200 Subject: Fixed a bug in Undo + EmojiReact. --- activitypub.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index bb6de13..4d1a449 100644 --- a/activitypub.c +++ b/activitypub.c @@ -2836,10 +2836,9 @@ int process_input_message(snac *snac, const xs_dict *msg, const xs_dict *req) } /* *key emojis are like w/ Emoji tag */ else - if ((isEmoji || strcmp(utype, "EmojiReact") == 0) && - (content && strcmp(content, "♥") != 0)) { + if (isEmoji || strcmp(utype, "EmojiReact") == 0) { const xs_val *mid = xs_dict_get(object, "id"); - int status = object_rm_emoji_react((char *)id, mid); + int status = object_rm_emoji_react(id, mid); /* ensure *key notifications type */ utype = "EmojiReact"; -- cgit From 62166d33affa48b625867b246ae1c282fc97035b Mon Sep 17 00:00:00 2001 From: grunfink Date: Sun, 30 Aug 2026 08:16:00 +0200 Subject: Added a key check to Undo. --- activitypub.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index 4d1a449..5c93bec 100644 --- a/activitypub.c +++ b/activitypub.c @@ -2813,6 +2813,10 @@ int process_input_message(snac *snac, const xs_dict *msg, const xs_dict *req) utype = "Follow"; } + if (strcmp(actor, key_id)) { + snac_log(snac, xs_fmt("Undo: mismatched actor '%s' and key '%s'", actor, key_id)); + } + else if (strcmp(utype, "Follow") == 0) { /** **/ if (!id) { snac_log(snac, xs_fmt("no id (msg.object.object) when " -- cgit From dde11b15de1db1b7695794abef4d190e4de60da1 Mon Sep 17 00:00:00 2001 From: grunfink Date: Wed, 2 Sep 2026 09:56:42 +0200 Subject: In activitypub_post_handler(), drop input messages that are too big. --- activitypub.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index 5c93bec..c148812 100644 --- a/activitypub.c +++ b/activitypub.c @@ -4110,6 +4110,12 @@ int activitypub_post_handler(const xs_dict *req, const char *q_path, xs_str_in(i_ctype, "application/ld+json") == -1) return 0; + if (p_size >= 100000) { + *body = xs_str_new("too big"); + *ctype = "text/plain"; + return HTTP_STATUS_BAD_REQUEST; + } + /* decode the message */ xs *msg = xs_json_loads(payload); const char *id = xs_dict_get(msg, "id"); -- cgit From e7db1c7175631ca6bf77b63cb117da51a046db69 Mon Sep 17 00:00:00 2001 From: grunfink Date: Wed, 2 Sep 2026 10:23:24 +0200 Subject: Also drop too big messages in activitypub_request(). --- activitypub.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index c148812..7687013 100644 --- a/activitypub.c +++ b/activitypub.c @@ -82,6 +82,9 @@ int activitypub_request(snac *user, const char *url, xs_dict **data) NULL, NULL, 0, &status, &payload, &p_size, 0); } + if (p_size >= 100000) + return HTTP_STATUS_BAD_REQUEST; + if (status == 0 || (status >= 500 && status <= 599)) { /* I found an instance running Misskey that returned 500 on signed messages but returned the object -- cgit From 7bf914ba1cb9b3bf4b24e142aa329e0bd71f2d80 Mon Sep 17 00:00:00 2001 From: grunfink Date: Wed, 2 Sep 2026 10:25:43 +0200 Subject: Fixed previous commit. --- activitypub.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index 7687013..af009ae 100644 --- a/activitypub.c +++ b/activitypub.c @@ -82,9 +82,6 @@ int activitypub_request(snac *user, const char *url, xs_dict **data) NULL, NULL, 0, &status, &payload, &p_size, 0); } - if (p_size >= 100000) - return HTTP_STATUS_BAD_REQUEST; - if (status == 0 || (status >= 500 && status <= 599)) { /* I found an instance running Misskey that returned 500 on signed messages but returned the object @@ -99,6 +96,9 @@ int activitypub_request(snac *user, const char *url, xs_dict **data) NULL, 0, &status, &payload, &p_size, 0); } + if (p_size >= 100000) + return HTTP_STATUS_BAD_REQUEST; + if (valid_status(status)) { /* ensure it's ActivityPub data */ ctype = xs_dict_get(response, "content-type"); -- cgit