aboutsummaryrefslogtreecommitdiff
path: root/activitypub.c
diff options
context:
space:
mode:
Diffstat (limited to 'activitypub.c')
-rw-r--r--activitypub.c85
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;