diff options
| author | Ruben Beltran del Rio <git@r.bdr.sh> | 2026-06-29 17:43:24 +0000 |
|---|---|---|
| committer | Ruben Beltran del Rio <git@r.bdr.sh> | 2026-06-29 17:43:24 +0000 |
| commit | 15d4dfc538dce7bfce4b0926b77f7f200cca99ff (patch) | |
| tree | f0dbceb404d2bab3896ffd6b42ec4b41f8f01c7e /activitypub.c | |
| parent | 30849656518854f1ff5af2ad8e583ceb199d1fbd (diff) | |
| parent | 25ccc2599aa722b0552193961d4cda15928112d8 (diff) | |
Diffstat (limited to 'activitypub.c')
| -rw-r--r-- | activitypub.c | 85 |
1 files changed, 76 insertions, 9 deletions
diff --git a/activitypub.c b/activitypub.c index 2f6da8b..514e764 100644 --- a/activitypub.c +++ b/activitypub.c @@ -1829,7 +1829,18 @@ xs_dict *msg_actor(snac *snac) keys = xs_dict_append(keys, "id", kid); keys = xs_dict_append(keys, "owner", snac->actor); - keys = xs_dict_append(keys, "publicKeyPem", xs_dict_get(snac->key, "public")); + + xs *public_key_pem = xs_dup(xs_dict_get(snac->key, "public")); + + if (xs_is_string(public_key_pem)) { + /* crop any garbage after the PEM */ + const char *pem_trailer = "\n-----END PUBLIC KEY-----\n"; + int i = xs_str_in(public_key_pem, pem_trailer); + if (i > 0) + public_key_pem[i + strlen(pem_trailer)] = '\0'; + } + + keys = xs_dict_append(keys, "publicKeyPem", public_key_pem); msg = xs_dict_set(msg, "publicKey", keys); /* if the "bot" config field is set to true, change type to "Service" */ @@ -2675,8 +2686,9 @@ int process_input_message(snac *snac, const xs_dict *msg, const xs_dict *req) /* check the signature */ xs *sig_err = NULL; + xs *key_id = NULL; - if (!check_signature(req, &sig_err)) { + if (!check_signature(req, &sig_err, &key_id)) { srv_log(xs_fmt("bad signature %s (%s)", actor, sig_err)); srv_archive_error("check_signature", sig_err, req, msg); @@ -2965,8 +2977,9 @@ int process_input_message(snac *snac, const xs_dict *msg, const xs_dict *req) snac_debug(snac, 1, xs_dup("ignored 'Accept' + 'Create'")); } else { - srv_archive_error("accept", "ignored Accept", req, msg); - snac_debug(snac, 1, xs_fmt("ignored 'Accept' for object type '%s'", utype)); + xs_str *e = xs_fmt("ignored 'Accept' for object type '%s'", utype); + srv_archive_error("accept", e, req, msg); + snac_log(snac, e); } } else @@ -3055,10 +3068,19 @@ int process_input_message(snac *snac, const xs_dict *msg, const xs_dict *req) else if (strcmp(type, "Update") == 0) { /** **/ if (xs_match(utype, "Person|Service|Application")) { /** **/ - actor_add(actor, xs_dict_get(msg, "object")); - timeline_touch(snac); + if (strcmp(actor, key_id) == 0) { + actor_add(actor, xs_dict_get(msg, "object")); + timeline_touch(snac); + + snac_log(snac, xs_fmt("updated actor %s", actor)); + } + else { + /* actor / key mismatch: don't accept blindly, but request an actor update + from the original source, as the Update may come from a relay and be legit */ + enqueue_actor_refresh(snac, actor, -10); - snac_log(snac, xs_fmt("updated actor %s", actor)); + snac_log(snac, xs_fmt("Update: mismatched actor '%s' and key '%s'", actor, key_id)); + } } else if (xs_match(utype, "Note|Page|Article|Video|Audio|Event")) { /** **/ @@ -3068,6 +3090,18 @@ int process_input_message(snac *snac, const xs_dict *msg, const xs_dict *req) snac_log(snac, xs_fmt("malformed message: no 'id' field")); else if (object_here(id)) { + const char *atto = get_atto(object); + + if (atto == NULL) + snac_log(snac, xs_fmt("ignored post 'Update' with no attributedTo %s", id)); + else + if (strcmp(atto, key_id) != 0) { + /* actor / key mismatch: request the object from the original source */ + enqueue_object_request(snac, id, -10); + + snac_log(snac, xs_fmt("Update: mismatched attributedTo '%s' and key '%s'", atto, key_id)); + } + else if (xs_startswith(id, srv_baseurl) && !xs_startswith(id, actor)) snac_log(snac, xs_fmt("ignored incorrect 'Update' %s %s", actor, id)); else { @@ -3108,10 +3142,22 @@ int process_input_message(snac *snac, const xs_dict *msg, const xs_dict *req) if (xs_type(object) == XSTYPE_DICT) object = xs_dict_get(object, "id"); + xs *obj_data = NULL; + if (xs_is_null(object)) snac_log(snac, xs_fmt("malformed message: no 'id' field")); else - if (object_here(object)) { + if (valid_status(object_get(object, &obj_data))) { + const char *atto = get_atto(obj_data); + + if (atto == NULL) + snac_log(snac, xs_fmt("ignored 'Delete' for object without attributedTo %s", object)); + else + if (strcmp(atto, key_id) != 0) { + /* don't call srv_archive_error() on this, because it can be a delete from a relay */ + snac_log(snac, xs_fmt("Delete: mismatched attributedTo '%s' and key '%s'", atto, key_id)); + } + else if (xs_startswith(object, srv_baseurl) && !is_msg_mine(snac, object)) snac_log(snac, xs_fmt("ignored incorrect 'Delete' %s %s", actor, object)); else { @@ -3155,7 +3201,13 @@ int process_input_message(snac *snac, const xs_dict *msg, const xs_dict *req) const char *old_account = xs_dict_get(msg, "object"); const char *new_account = xs_dict_get(msg, "target"); - if (!xs_is_null(old_account) && !xs_is_null(new_account)) { + if (xs_is_string(old_account) && xs_is_string(new_account)) { + if (strcmp(old_account, key_id) != 0) { + xs_str *e = xs_fmt("'Move': mismatched old_account %s and key %s", old_account, key_id); + srv_archive_error("move_old_account_key_mismatch", e, req, msg); + snac_log(snac, e); + } + else if (following_check(snac, old_account)) { xs *n_actor = NULL; @@ -3421,6 +3473,10 @@ void process_user_queue_item(snac *user, xs_dict *q_item) actor_o = actor_get_collections(user, actor_o, 1); actor_add(actor, actor_o); + + /* mark actor and instance as working */ + actor_failure(actor, 2); + instance_failure(actor, 2); } else { if (status == HTTP_STATUS_GONE || status == HTTP_STATUS_NOT_FOUND) { @@ -3880,6 +3936,12 @@ int activitypub_get_handler(const xs_dict *req, const char *q_path, return 0; xs *l = xs_split_n(q_path, "/", 2); + + if (xs_list_len(l) <= 1) { + srv_debug(1, xs_fmt("activitypub_get_handler bad path %s", q_path)); + return HTTP_STATUS_BAD_REQUEST; + } + const char *uid; const char *p_path; @@ -4067,6 +4129,11 @@ int activitypub_post_handler(const xs_dict *req, const char *q_path, /* get the user and path */ xs *l = xs_split_n(q_path, "/", 2); + if (xs_list_len(l) <= 1) { + srv_debug(1, xs_fmt("activitypub_post_handler bad path %s", q_path)); + return HTTP_STATUS_BAD_REQUEST; + } + if (xs_list_len(l) == 2 && strcmp(xs_list_get(l, 1), "shared-inbox") == 0) { enqueue_shared_input(msg, req, 0); return HTTP_STATUS_ACCEPTED; |