diff options
Diffstat (limited to 'activitypub.c')
| -rw-r--r-- | activitypub.c | 146 |
1 files changed, 119 insertions, 27 deletions
diff --git a/activitypub.c b/activitypub.c index 73fbbc6..53f102e 100644 --- a/activitypub.c +++ b/activitypub.c | |||
| @@ -125,10 +125,10 @@ int actor_request(snac *user, const char *actor, xs_dict **data) | |||
| 125 | *data = NULL; | 125 | *data = NULL; |
| 126 | 126 | ||
| 127 | /* get from disk first */ | 127 | /* get from disk first */ |
| 128 | status = actor_get(actor, data); | 128 | status = actor_get_refresh(user, actor, data); |
| 129 | 129 | ||
| 130 | if (status != 200) { | 130 | if (!valid_status(status)) { |
| 131 | /* actor data non-existent or stale: get from the net */ | 131 | /* actor data non-existent: get from the net */ |
| 132 | status = activitypub_request(user, actor, &payload); | 132 | status = activitypub_request(user, actor, &payload); |
| 133 | 133 | ||
| 134 | if (valid_status(status)) { | 134 | if (valid_status(status)) { |
| @@ -149,8 +149,6 @@ int actor_request(snac *user, const char *actor, xs_dict **data) | |||
| 149 | if (valid_status(status) && data && *data) | 149 | if (valid_status(status) && data && *data) |
| 150 | inbox_add_by_actor(*data); | 150 | inbox_add_by_actor(*data); |
| 151 | } | 151 | } |
| 152 | else | ||
| 153 | srv_debug(2, xs_fmt("NOT collected")); | ||
| 154 | 152 | ||
| 155 | return status; | 153 | return status; |
| 156 | } | 154 | } |
| @@ -313,6 +311,12 @@ int timeline_request(snac *snac, char **id, xs_str **wrk, int level) | |||
| 313 | if (level < MAX_CONVERSATION_LEVELS && !xs_is_null(*id)) { | 311 | if (level < MAX_CONVERSATION_LEVELS && !xs_is_null(*id)) { |
| 314 | xs *msg = NULL; | 312 | xs *msg = NULL; |
| 315 | 313 | ||
| 314 | /* from a blocked instance? discard and break */ | ||
| 315 | if (is_instance_blocked(*id)) { | ||
| 316 | snac_debug(snac, 1, xs_fmt("timeline_request blocked instance %s", *id)); | ||
| 317 | return status; | ||
| 318 | } | ||
| 319 | |||
| 316 | /* is the object already there? */ | 320 | /* is the object already there? */ |
| 317 | if (!valid_status(object_get(*id, &msg))) { | 321 | if (!valid_status(object_get(*id, &msg))) { |
| 318 | /* no; download it */ | 322 | /* no; download it */ |
| @@ -354,18 +358,22 @@ int timeline_request(snac *snac, char **id, xs_str **wrk, int level) | |||
| 354 | if (xs_match(type, "Note|Page|Article|Video")) { | 358 | if (xs_match(type, "Note|Page|Article|Video")) { |
| 355 | const char *actor = get_atto(object); | 359 | const char *actor = get_atto(object); |
| 356 | 360 | ||
| 357 | /* request (and drop) the actor for this entry */ | 361 | if (content_check("filter_reject.txt", object)) |
| 358 | if (!xs_is_null(actor)) | 362 | snac_log(snac, xs_fmt("timeline_request rejected by content %s", nid)); |
| 359 | actor_request(snac, actor, NULL); | 363 | else { |
| 364 | /* request (and drop) the actor for this entry */ | ||
| 365 | if (!xs_is_null(actor)) | ||
| 366 | actor_request(snac, actor, NULL); | ||
| 360 | 367 | ||
| 361 | /* does it have an ancestor? */ | 368 | /* does it have an ancestor? */ |
| 362 | char *in_reply_to = xs_dict_get(object, "inReplyTo"); | 369 | char *in_reply_to = xs_dict_get(object, "inReplyTo"); |
| 363 | 370 | ||
| 364 | /* store */ | 371 | /* store */ |
| 365 | timeline_add(snac, nid, object); | 372 | timeline_add(snac, nid, object); |
| 366 | 373 | ||
| 367 | /* recurse! */ | 374 | /* recurse! */ |
| 368 | timeline_request(snac, &in_reply_to, NULL, level + 1); | 375 | timeline_request(snac, &in_reply_to, NULL, level + 1); |
| 376 | } | ||
| 369 | } | 377 | } |
| 370 | } | 378 | } |
| 371 | } | 379 | } |
| @@ -623,6 +631,12 @@ int is_msg_for_me(snac *snac, const xs_dict *c_msg) | |||
| 623 | const char *type = xs_dict_get(c_msg, "type"); | 631 | const char *type = xs_dict_get(c_msg, "type"); |
| 624 | const char *actor = xs_dict_get(c_msg, "actor"); | 632 | const char *actor = xs_dict_get(c_msg, "actor"); |
| 625 | 633 | ||
| 634 | if (strcmp(actor, snac->actor) == 0) { | ||
| 635 | /* message by myself? (most probably via the shared-inbox) reject */ | ||
| 636 | snac_debug(snac, 1, xs_fmt("ignoring message by myself")); | ||
| 637 | return 0; | ||
| 638 | } | ||
| 639 | |||
| 626 | if (xs_match(type, "Like|Announce")) { | 640 | if (xs_match(type, "Like|Announce")) { |
| 627 | const char *object = xs_dict_get(c_msg, "object"); | 641 | const char *object = xs_dict_get(c_msg, "object"); |
| 628 | 642 | ||
| @@ -657,6 +671,12 @@ int is_msg_for_me(snac *snac, const xs_dict *c_msg) | |||
| 657 | return !xs_is_null(object) && strcmp(snac->actor, object) == 0; | 671 | return !xs_is_null(object) && strcmp(snac->actor, object) == 0; |
| 658 | } | 672 | } |
| 659 | 673 | ||
| 674 | /* only accept Ping directed to us */ | ||
| 675 | if (xs_match(type, "Ping")) { | ||
| 676 | char *dest = xs_dict_get(c_msg, "to"); | ||
| 677 | return !xs_is_null(dest) && strcmp(snac->actor, dest) == 0; | ||
| 678 | } | ||
| 679 | |||
| 660 | /* if it's not a Create or Update, allow as is */ | 680 | /* if it's not a Create or Update, allow as is */ |
| 661 | if (!xs_match(type, "Create|Update")) { | 681 | if (!xs_match(type, "Create|Update")) { |
| 662 | return 1; | 682 | return 1; |
| @@ -1072,7 +1092,7 @@ xs_dict *msg_collection(snac *snac, char *id) | |||
| 1072 | 1092 | ||
| 1073 | msg = xs_dict_append(msg, "attributedTo", snac->actor); | 1093 | msg = xs_dict_append(msg, "attributedTo", snac->actor); |
| 1074 | msg = xs_dict_append(msg, "orderedItems", ol); | 1094 | msg = xs_dict_append(msg, "orderedItems", ol); |
| 1075 | msg = xs_dict_append(msg, "totalItems", xs_stock_0); | 1095 | msg = xs_dict_append(msg, "totalItems", xs_stock(0)); |
| 1076 | 1096 | ||
| 1077 | return msg; | 1097 | return msg; |
| 1078 | } | 1098 | } |
| @@ -1129,8 +1149,10 @@ xs_dict *msg_admiration(snac *snac, char *object, char *type) | |||
| 1129 | 1149 | ||
| 1130 | if (valid_status(object_get(object, &a_msg))) { | 1150 | if (valid_status(object_get(object, &a_msg))) { |
| 1131 | xs *rcpts = xs_list_new(); | 1151 | xs *rcpts = xs_list_new(); |
| 1152 | xs *o_md5 = xs_md5_hex(object, strlen(object)); | ||
| 1153 | xs *id = xs_fmt("%s/%s/%s", snac->actor, *type == 'L' ? "l" : "a", o_md5); | ||
| 1132 | 1154 | ||
| 1133 | msg = msg_base(snac, type, "@dummy", snac->actor, "@now", object); | 1155 | msg = msg_base(snac, type, id, snac->actor, "@now", object); |
| 1134 | 1156 | ||
| 1135 | if (is_msg_public(a_msg)) | 1157 | if (is_msg_public(a_msg)) |
| 1136 | rcpts = xs_list_append(rcpts, public_address); | 1158 | rcpts = xs_list_append(rcpts, public_address); |
| @@ -1146,6 +1168,33 @@ xs_dict *msg_admiration(snac *snac, char *object, char *type) | |||
| 1146 | } | 1168 | } |
| 1147 | 1169 | ||
| 1148 | 1170 | ||
| 1171 | xs_dict *msg_repulsion(snac *user, char *id, char *type) | ||
| 1172 | /* creates an Undo + admiration message */ | ||
| 1173 | { | ||
| 1174 | xs *a_msg = NULL; | ||
| 1175 | xs_dict *msg = NULL; | ||
| 1176 | |||
| 1177 | if (valid_status(object_get(id, &a_msg))) { | ||
| 1178 | /* create a clone of the original admiration message */ | ||
| 1179 | xs *object = msg_admiration(user, id, type); | ||
| 1180 | |||
| 1181 | /* delete the published date */ | ||
| 1182 | object = xs_dict_del(object, "published"); | ||
| 1183 | |||
| 1184 | /* create an undo message for this object */ | ||
| 1185 | msg = msg_undo(user, object); | ||
| 1186 | |||
| 1187 | /* copy the 'to' field */ | ||
| 1188 | msg = xs_dict_set(msg, "to", xs_dict_get(object, "to")); | ||
| 1189 | } | ||
| 1190 | |||
| 1191 | /* now we despise this */ | ||
| 1192 | object_unadmire(id, user->actor, *type == 'L' ? 1 : 0); | ||
| 1193 | |||
| 1194 | return msg; | ||
| 1195 | } | ||
| 1196 | |||
| 1197 | |||
| 1149 | xs_dict *msg_actor(snac *snac) | 1198 | xs_dict *msg_actor(snac *snac) |
| 1150 | /* create a Person message for this actor */ | 1199 | /* create a Person message for this actor */ |
| 1151 | { | 1200 | { |
| @@ -1170,7 +1219,7 @@ xs_dict *msg_actor(snac *snac) | |||
| 1170 | msg = xs_dict_set(msg, "preferredUsername", snac->uid); | 1219 | msg = xs_dict_set(msg, "preferredUsername", snac->uid); |
| 1171 | msg = xs_dict_set(msg, "published", xs_dict_get(snac->config, "published")); | 1220 | msg = xs_dict_set(msg, "published", xs_dict_get(snac->config, "published")); |
| 1172 | 1221 | ||
| 1173 | xs *f_bio_2 = not_really_markdown(xs_dict_get(snac->config, "bio"), NULL); | 1222 | xs *f_bio_2 = not_really_markdown(xs_dict_get(snac->config, "bio"), NULL, NULL); |
| 1174 | f_bio = process_tags(snac, f_bio_2, &tags); | 1223 | f_bio = process_tags(snac, f_bio_2, &tags); |
| 1175 | msg = xs_dict_set(msg, "summary", f_bio); | 1224 | msg = xs_dict_set(msg, "summary", f_bio); |
| 1176 | msg = xs_dict_set(msg, "tag", tags); | 1225 | msg = xs_dict_set(msg, "tag", tags); |
| @@ -1378,7 +1427,7 @@ xs_dict *msg_note(snac *snac, const xs_str *content, const xs_val *rcpts, | |||
| 1378 | } | 1427 | } |
| 1379 | 1428 | ||
| 1380 | /* format the content */ | 1429 | /* format the content */ |
| 1381 | fc2 = not_really_markdown(content, &atls); | 1430 | fc2 = not_really_markdown(content, &atls, &tag); |
| 1382 | 1431 | ||
| 1383 | if (in_reply_to != NULL && *in_reply_to) { | 1432 | if (in_reply_to != NULL && *in_reply_to) { |
| 1384 | xs *p_msg = NULL; | 1433 | xs *p_msg = NULL; |
| @@ -1556,6 +1605,7 @@ xs_dict *msg_question(snac *user, const char *content, xs_list *attach, | |||
| 1556 | } | 1605 | } |
| 1557 | 1606 | ||
| 1558 | if (xs_set_add(&seen, v2) == 1) { | 1607 | if (xs_set_add(&seen, v2) == 1) { |
| 1608 | d = xs_dict_append(d, "type", "Note"); | ||
| 1559 | d = xs_dict_append(d, "name", v2); | 1609 | d = xs_dict_append(d, "name", v2); |
| 1560 | d = xs_dict_append(d, "replies", replies); | 1610 | d = xs_dict_append(d, "replies", replies); |
| 1561 | o = xs_list_append(o, d); | 1611 | o = xs_list_append(o, d); |
| @@ -1608,7 +1658,7 @@ int update_question(snac *user, const char *id) | |||
| 1608 | const char *name = xs_dict_get(v, "name"); | 1658 | const char *name = xs_dict_get(v, "name"); |
| 1609 | if (name) { | 1659 | if (name) { |
| 1610 | lopts = xs_list_append(lopts, name); | 1660 | lopts = xs_list_append(lopts, name); |
| 1611 | rcnt = xs_dict_set(rcnt, name, xs_stock_0); | 1661 | rcnt = xs_dict_set(rcnt, name, xs_stock(0)); |
| 1612 | } | 1662 | } |
| 1613 | } | 1663 | } |
| 1614 | 1664 | ||
| @@ -1891,6 +1941,8 @@ int process_input_message(snac *snac, xs_dict *msg, xs_dict *req) | |||
| 1891 | } | 1941 | } |
| 1892 | else | 1942 | else |
| 1893 | if (strcmp(type, "Undo") == 0) { /** **/ | 1943 | if (strcmp(type, "Undo") == 0) { /** **/ |
| 1944 | char *id = xs_dict_get(object, "object"); | ||
| 1945 | |||
| 1894 | if (xs_type(object) != XSTYPE_DICT) | 1946 | if (xs_type(object) != XSTYPE_DICT) |
| 1895 | utype = "Follow"; | 1947 | utype = "Follow"; |
| 1896 | 1948 | ||
| @@ -1903,6 +1955,23 @@ int process_input_message(snac *snac, xs_dict *msg, xs_dict *req) | |||
| 1903 | snac_log(snac, xs_fmt("error deleting follower %s", actor)); | 1955 | snac_log(snac, xs_fmt("error deleting follower %s", actor)); |
| 1904 | } | 1956 | } |
| 1905 | else | 1957 | else |
| 1958 | if (strcmp(utype, "Like") == 0) { /** **/ | ||
| 1959 | int status = object_unadmire(id, actor, 1); | ||
| 1960 | |||
| 1961 | snac_log(snac, xs_fmt("Unlike for %s %d", id, status)); | ||
| 1962 | } | ||
| 1963 | else | ||
| 1964 | if (strcmp(utype, "Announce") == 0) { /** **/ | ||
| 1965 | int status = 200; | ||
| 1966 | |||
| 1967 | /* commented out: if a followed user boosts something that | ||
| 1968 | is requested and then unboosts, the post remains here, | ||
| 1969 | but with no apparent reason, and that is confusing */ | ||
| 1970 | //status = object_unadmire(id, actor, 0); | ||
| 1971 | |||
| 1972 | snac_log(snac, xs_fmt("Unboost for %s %d", id, status)); | ||
| 1973 | } | ||
| 1974 | else | ||
| 1906 | snac_debug(snac, 1, xs_fmt("ignored 'Undo' for object type '%s'", utype)); | 1975 | snac_debug(snac, 1, xs_fmt("ignored 'Undo' for object type '%s'", utype)); |
| 1907 | } | 1976 | } |
| 1908 | else | 1977 | else |
| @@ -1912,7 +1981,7 @@ int process_input_message(snac *snac, xs_dict *msg, xs_dict *req) | |||
| 1912 | return 1; | 1981 | return 1; |
| 1913 | } | 1982 | } |
| 1914 | 1983 | ||
| 1915 | if (strcmp(utype, "Note") == 0) { /** **/ | 1984 | if (xs_match(utype, "Note|Article")) { /** **/ |
| 1916 | char *id = xs_dict_get(object, "id"); | 1985 | char *id = xs_dict_get(object, "id"); |
| 1917 | char *in_reply_to = xs_dict_get(object, "inReplyTo"); | 1986 | char *in_reply_to = xs_dict_get(object, "inReplyTo"); |
| 1918 | xs *wrk = NULL; | 1987 | xs *wrk = NULL; |
| @@ -1921,10 +1990,15 @@ int process_input_message(snac *snac, xs_dict *msg, xs_dict *req) | |||
| 1921 | snac_debug(snac, 0, xs_fmt("dropped reply %s to hidden post %s", id, in_reply_to)); | 1990 | snac_debug(snac, 0, xs_fmt("dropped reply %s to hidden post %s", id, in_reply_to)); |
| 1922 | } | 1991 | } |
| 1923 | else { | 1992 | else { |
| 1993 | if (content_check("filter_reject.txt", object)) { | ||
| 1994 | snac_log(snac, xs_fmt("rejected by content %s", id)); | ||
| 1995 | return 1; | ||
| 1996 | } | ||
| 1997 | |||
| 1924 | timeline_request(snac, &in_reply_to, &wrk, 0); | 1998 | timeline_request(snac, &in_reply_to, &wrk, 0); |
| 1925 | 1999 | ||
| 1926 | if (timeline_add(snac, id, object)) { | 2000 | if (timeline_add(snac, id, object)) { |
| 1927 | snac_log(snac, xs_fmt("new 'Note' %s %s", actor, id)); | 2001 | snac_log(snac, xs_fmt("new '%s' %s %s", utype, actor, id)); |
| 1928 | do_notify = 1; | 2002 | do_notify = 1; |
| 1929 | } | 2003 | } |
| 1930 | 2004 | ||
| @@ -1988,12 +2062,12 @@ int process_input_message(snac *snac, xs_dict *msg, xs_dict *req) | |||
| 1988 | if (xs_type(object) == XSTYPE_DICT) | 2062 | if (xs_type(object) == XSTYPE_DICT) |
| 1989 | object = xs_dict_get(object, "id"); | 2063 | object = xs_dict_get(object, "id"); |
| 1990 | 2064 | ||
| 1991 | if (timeline_admire(snac, object, actor, 1) == 201) { | 2065 | if (timeline_admire(snac, object, actor, 1) == 201) |
| 1992 | snac_log(snac, xs_fmt("new 'Like' %s %s", actor, object)); | 2066 | snac_log(snac, xs_fmt("new 'Like' %s %s", actor, object)); |
| 1993 | do_notify = 1; | ||
| 1994 | } | ||
| 1995 | else | 2067 | else |
| 1996 | snac_log(snac, xs_fmt("repeated 'Like' from %s to %s", actor, object)); | 2068 | snac_log(snac, xs_fmt("repeated 'Like' from %s to %s", actor, object)); |
| 2069 | |||
| 2070 | do_notify = 1; | ||
| 1997 | } | 2071 | } |
| 1998 | else | 2072 | else |
| 1999 | if (strcmp(type, "Announce") == 0) { /** **/ | 2073 | if (strcmp(type, "Announce") == 0) { /** **/ |
| @@ -2019,13 +2093,13 @@ int process_input_message(snac *snac, xs_dict *msg, xs_dict *req) | |||
| 2019 | xs *who_o = NULL; | 2093 | xs *who_o = NULL; |
| 2020 | 2094 | ||
| 2021 | if (valid_status(actor_request(snac, who, &who_o))) { | 2095 | if (valid_status(actor_request(snac, who, &who_o))) { |
| 2022 | if (timeline_admire(snac, object, actor, 0) == 201) { | 2096 | if (timeline_admire(snac, object, actor, 0) == 201) |
| 2023 | snac_log(snac, xs_fmt("new 'Announce' %s %s", actor, object)); | 2097 | snac_log(snac, xs_fmt("new 'Announce' %s %s", actor, object)); |
| 2024 | do_notify = 1; | ||
| 2025 | } | ||
| 2026 | else | 2098 | else |
| 2027 | snac_log(snac, xs_fmt("repeated 'Announce' from %s to %s", | 2099 | snac_log(snac, xs_fmt("repeated 'Announce' from %s to %s", |
| 2028 | actor, object)); | 2100 | actor, object)); |
| 2101 | |||
| 2102 | do_notify = 1; | ||
| 2029 | } | 2103 | } |
| 2030 | else | 2104 | else |
| 2031 | snac_debug(snac, 1, xs_fmt("dropped 'Announce' on actor request error %s", who)); | 2105 | snac_debug(snac, 1, xs_fmt("dropped 'Announce' on actor request error %s", who)); |
| @@ -2236,6 +2310,24 @@ void process_user_queue_item(snac *snac, xs_dict *q_item) | |||
| 2236 | verify_links(snac); | 2310 | verify_links(snac); |
| 2237 | } | 2311 | } |
| 2238 | else | 2312 | else |
| 2313 | if (strcmp(type, "actor_refresh") == 0) { | ||
| 2314 | const char *actor = xs_dict_get(q_item, "actor"); | ||
| 2315 | double mtime = object_mtime(actor); | ||
| 2316 | |||
| 2317 | /* only refresh if it was refreshed more than an hour ago */ | ||
| 2318 | if (mtime + 3600.0 < (double) time(NULL)) { | ||
| 2319 | xs *actor_o = NULL; | ||
| 2320 | int status; | ||
| 2321 | |||
| 2322 | if (valid_status((status = activitypub_request(snac, actor, &actor_o)))) | ||
| 2323 | actor_add(actor, actor_o); | ||
| 2324 | else | ||
| 2325 | object_touch(actor); | ||
| 2326 | |||
| 2327 | snac_log(snac, xs_fmt("actor_refresh %s %d", actor, status)); | ||
| 2328 | } | ||
| 2329 | } | ||
| 2330 | else | ||
| 2239 | snac_log(snac, xs_fmt("unexpected user q_item type '%s'", type)); | 2331 | snac_log(snac, xs_fmt("unexpected user q_item type '%s'", type)); |
| 2240 | } | 2332 | } |
| 2241 | 2333 | ||