diff options
| author | 2024-12-23 13:42:45 +0100 | |
|---|---|---|
| committer | 2024-12-23 13:42:45 +0100 | |
| commit | a7ca4007f2a55a8becab1e4595d2696dd6e7bfd1 (patch) | |
| tree | 3128196bd7eb298be5a37edac5922009ec5fcac1 /mastoapi.c | |
| parent | Merge tag '2.66' (diff) | |
| parent | Version 2.67 RELEASED. (diff) | |
| download | penes-snac2-a7ca4007f2a55a8becab1e4595d2696dd6e7bfd1.tar.gz penes-snac2-a7ca4007f2a55a8becab1e4595d2696dd6e7bfd1.tar.xz penes-snac2-a7ca4007f2a55a8becab1e4595d2696dd6e7bfd1.zip | |
Merge tag '2.67'
Version 2.67 RELEASED.
Diffstat (limited to 'mastoapi.c')
| -rw-r--r-- | mastoapi.c | 259 |
1 files changed, 192 insertions, 67 deletions
| @@ -293,47 +293,54 @@ int oauth_post_handler(const xs_dict *req, const char *q_path, | |||
| 293 | snac snac; | 293 | snac snac; |
| 294 | 294 | ||
| 295 | if (user_open(&snac, login)) { | 295 | if (user_open(&snac, login)) { |
| 296 | /* check the login + password */ | 296 | const char *addr = xs_or(xs_dict_get(req, "remote-addr"), |
| 297 | if (check_password(login, passwd, xs_dict_get(snac.config, "passwd"))) { | 297 | xs_dict_get(req, "x-forwarded-for")); |
| 298 | /* success! redirect to the desired uri */ | ||
| 299 | xs *code = random_str(); | ||
| 300 | 298 | ||
| 301 | xs_free(*body); | 299 | if (badlogin_check(login, addr)) { |
| 300 | /* check the login + password */ | ||
| 301 | if (check_password(login, passwd, xs_dict_get(snac.config, "passwd"))) { | ||
| 302 | /* success! redirect to the desired uri */ | ||
| 303 | xs *code = random_str(); | ||
| 302 | 304 | ||
| 303 | if (strcmp(redir, "urn:ietf:wg:oauth:2.0:oob") == 0) { | 305 | xs_free(*body); |
| 304 | *body = xs_dup(code); | ||
| 305 | } | ||
| 306 | else { | ||
| 307 | if (xs_str_in(redir, "?") != -1) | ||
| 308 | *body = xs_fmt("%s&code=%s", redir, code); | ||
| 309 | else | ||
| 310 | *body = xs_fmt("%s?code=%s", redir, code); | ||
| 311 | 306 | ||
| 312 | status = HTTP_STATUS_SEE_OTHER; | 307 | if (strcmp(redir, "urn:ietf:wg:oauth:2.0:oob") == 0) { |
| 313 | } | 308 | *body = xs_dup(code); |
| 309 | } | ||
| 310 | else { | ||
| 311 | if (xs_str_in(redir, "?") != -1) | ||
| 312 | *body = xs_fmt("%s&code=%s", redir, code); | ||
| 313 | else | ||
| 314 | *body = xs_fmt("%s?code=%s", redir, code); | ||
| 314 | 315 | ||
| 315 | /* if there is a state, add it */ | 316 | status = HTTP_STATUS_SEE_OTHER; |
| 316 | if (!xs_is_null(state) && *state) { | 317 | } |
| 317 | *body = xs_str_cat(*body, "&state="); | ||
| 318 | *body = xs_str_cat(*body, state); | ||
| 319 | } | ||
| 320 | 318 | ||
| 321 | srv_log(xs_fmt("oauth x-snac-login: '%s' success, redirect to %s", | 319 | /* if there is a state, add it */ |
| 320 | if (!xs_is_null(state) && *state) { | ||
| 321 | *body = xs_str_cat(*body, "&state="); | ||
| 322 | *body = xs_str_cat(*body, state); | ||
| 323 | } | ||
| 324 | |||
| 325 | srv_log(xs_fmt("oauth x-snac-login: '%s' success, redirect to %s", | ||
| 322 | login, *body)); | 326 | login, *body)); |
| 323 | 327 | ||
| 324 | /* assign the login to the app */ | 328 | /* assign the login to the app */ |
| 325 | xs *app = app_get(cid); | 329 | xs *app = app_get(cid); |
| 326 | 330 | ||
| 327 | if (app != NULL) { | 331 | if (app != NULL) { |
| 328 | app = xs_dict_set(app, "uid", login); | 332 | app = xs_dict_set(app, "uid", login); |
| 329 | app = xs_dict_set(app, "code", code); | 333 | app = xs_dict_set(app, "code", code); |
| 330 | app_add(cid, app); | 334 | app_add(cid, app); |
| 335 | } | ||
| 336 | else | ||
| 337 | srv_log(xs_fmt("oauth x-snac-login: error getting app %s", cid)); | ||
| 338 | } | ||
| 339 | else { | ||
| 340 | srv_debug(1, xs_fmt("oauth x-snac-login: login '%s' incorrect", login)); | ||
| 341 | badlogin_inc(login, addr); | ||
| 331 | } | 342 | } |
| 332 | else | ||
| 333 | srv_log(xs_fmt("oauth x-snac-login: error getting app %s", cid)); | ||
| 334 | } | 343 | } |
| 335 | else | ||
| 336 | srv_debug(1, xs_fmt("oauth x-snac-login: login '%s' incorrect", login)); | ||
| 337 | 344 | ||
| 338 | user_free(&snac); | 345 | user_free(&snac); |
| 339 | } | 346 | } |
| @@ -474,29 +481,36 @@ int oauth_post_handler(const xs_dict *req, const char *q_path, | |||
| 474 | snac user; | 481 | snac user; |
| 475 | 482 | ||
| 476 | if (user_open(&user, login)) { | 483 | if (user_open(&user, login)) { |
| 477 | /* check the login + password */ | 484 | const char *addr = xs_or(xs_dict_get(req, "remote-addr"), |
| 478 | if (check_password(login, passwd, xs_dict_get(user.config, "passwd"))) { | 485 | xs_dict_get(req, "x-forwarded-for")); |
| 479 | /* success! create a new token */ | ||
| 480 | xs *tokid = random_str(); | ||
| 481 | 486 | ||
| 482 | srv_debug(1, xs_fmt("x-snac-new-token: " | 487 | if (badlogin_check(login, addr)) { |
| 488 | /* check the login + password */ | ||
| 489 | if (check_password(login, passwd, xs_dict_get(user.config, "passwd"))) { | ||
| 490 | /* success! create a new token */ | ||
| 491 | xs *tokid = random_str(); | ||
| 492 | |||
| 493 | srv_debug(1, xs_fmt("x-snac-new-token: " | ||
| 483 | "successful login for %s, new token %s", login, tokid)); | 494 | "successful login for %s, new token %s", login, tokid)); |
| 484 | 495 | ||
| 485 | xs *token = xs_dict_new(); | 496 | xs *token = xs_dict_new(); |
| 486 | token = xs_dict_append(token, "token", tokid); | 497 | token = xs_dict_append(token, "token", tokid); |
| 487 | token = xs_dict_append(token, "client_id", "snac-client"); | 498 | token = xs_dict_append(token, "client_id", "snac-client"); |
| 488 | token = xs_dict_append(token, "client_secret", ""); | 499 | token = xs_dict_append(token, "client_secret", ""); |
| 489 | token = xs_dict_append(token, "uid", login); | 500 | token = xs_dict_append(token, "uid", login); |
| 490 | token = xs_dict_append(token, "code", ""); | 501 | token = xs_dict_append(token, "code", ""); |
| 491 | 502 | ||
| 492 | token_add(tokid, token); | 503 | token_add(tokid, token); |
| 493 | 504 | ||
| 494 | *ctype = "text/plain"; | 505 | *ctype = "text/plain"; |
| 495 | xs_free(*body); | 506 | xs_free(*body); |
| 496 | *body = xs_dup(tokid); | 507 | *body = xs_dup(tokid); |
| 497 | } | 508 | } |
| 509 | else | ||
| 510 | badlogin_inc(login, addr); | ||
| 498 | 511 | ||
| 499 | user_free(&user); | 512 | user_free(&user); |
| 513 | } | ||
| 500 | } | 514 | } |
| 501 | } | 515 | } |
| 502 | } | 516 | } |
| @@ -898,7 +912,7 @@ xs_dict *mastoapi_status(snac *snac, const xs_dict *msg) | |||
| 898 | const char *o_href = xs_dict_get(v, "href"); | 912 | const char *o_href = xs_dict_get(v, "href"); |
| 899 | const char *name = xs_dict_get(v, "name"); | 913 | const char *name = xs_dict_get(v, "name"); |
| 900 | 914 | ||
| 901 | if (xs_match(type, "image/*|video/*|Image|Video")) { /* */ | 915 | if (xs_match(type, "image/*|video/*|audio/*|Image|Video")) { /* */ |
| 902 | xs *matteid = xs_fmt("%s_%d", id, xs_list_len(matt)); | 916 | xs *matteid = xs_fmt("%s_%d", id, xs_list_len(matt)); |
| 903 | xs *href = make_url(o_href, proxy, 1); | 917 | xs *href = make_url(o_href, proxy, 1); |
| 904 | 918 | ||
| @@ -910,7 +924,8 @@ xs_dict *mastoapi_status(snac *snac, const xs_dict *msg) | |||
| 910 | d = xs_dict_append(d, "remote_url", href); | 924 | d = xs_dict_append(d, "remote_url", href); |
| 911 | d = xs_dict_append(d, "description", name); | 925 | d = xs_dict_append(d, "description", name); |
| 912 | 926 | ||
| 913 | d = xs_dict_append(d, "type", (*type == 'v' || *type == 'V') ? "video" : "image"); | 927 | d = xs_dict_append(d, "type", (*type == 'v' || *type == 'V') ? "video" : |
| 928 | (*type == 'a' || *type == 'A') ? "audio" : "image"); | ||
| 914 | 929 | ||
| 915 | matt = xs_list_append(matt, d); | 930 | matt = xs_list_append(matt, d); |
| 916 | } | 931 | } |
| @@ -990,7 +1005,7 @@ xs_dict *mastoapi_status(snac *snac, const xs_dict *msg) | |||
| 990 | const char *o_url = xs_dict_get(icon, "url"); | 1005 | const char *o_url = xs_dict_get(icon, "url"); |
| 991 | 1006 | ||
| 992 | if (!xs_is_null(o_url)) { | 1007 | if (!xs_is_null(o_url)) { |
| 993 | xs *url = make_url(o_url, snac->actor, 1); | 1008 | xs *url = make_url(o_url, snac ? snac->actor : NULL, 1); |
| 994 | xs *nm = xs_strip_chars_i(xs_dup(name), ":"); | 1009 | xs *nm = xs_strip_chars_i(xs_dup(name), ":"); |
| 995 | 1010 | ||
| 996 | d1 = xs_dict_append(d1, "shortcode", nm); | 1011 | d1 = xs_dict_append(d1, "shortcode", nm); |
| @@ -1193,10 +1208,13 @@ int process_auth_token(snac *snac, const xs_dict *req) | |||
| 1193 | return logged_in; | 1208 | return logged_in; |
| 1194 | } | 1209 | } |
| 1195 | 1210 | ||
| 1211 | |||
| 1196 | void credentials_get(char **body, char **ctype, int *status, snac snac) | 1212 | void credentials_get(char **body, char **ctype, int *status, snac snac) |
| 1197 | { | 1213 | { |
| 1198 | xs *acct = xs_dict_new(); | 1214 | xs *acct = xs_dict_new(); |
| 1199 | 1215 | ||
| 1216 | const xs_val *bot = xs_dict_get(snac.config, "bot"); | ||
| 1217 | |||
| 1200 | acct = xs_dict_append(acct, "id", snac.md5); | 1218 | acct = xs_dict_append(acct, "id", snac.md5); |
| 1201 | acct = xs_dict_append(acct, "username", xs_dict_get(snac.config, "uid")); | 1219 | acct = xs_dict_append(acct, "username", xs_dict_get(snac.config, "uid")); |
| 1202 | acct = xs_dict_append(acct, "acct", xs_dict_get(snac.config, "uid")); | 1220 | acct = xs_dict_append(acct, "acct", xs_dict_get(snac.config, "uid")); |
| @@ -1206,7 +1224,7 @@ void credentials_get(char **body, char **ctype, int *status, snac snac) | |||
| 1206 | acct = xs_dict_append(acct, "note", xs_dict_get(snac.config, "bio")); | 1224 | acct = xs_dict_append(acct, "note", xs_dict_get(snac.config, "bio")); |
| 1207 | acct = xs_dict_append(acct, "url", snac.actor); | 1225 | acct = xs_dict_append(acct, "url", snac.actor); |
| 1208 | acct = xs_dict_append(acct, "locked", xs_stock(XSTYPE_FALSE)); | 1226 | acct = xs_dict_append(acct, "locked", xs_stock(XSTYPE_FALSE)); |
| 1209 | acct = xs_dict_append(acct, "bot", xs_dict_get(snac.config, "bot")); | 1227 | acct = xs_dict_append(acct, "bot", xs_stock(xs_is_true(bot) ? XSTYPE_TRUE : XSTYPE_FALSE)); |
| 1210 | acct = xs_dict_append(acct, "emojis", xs_stock(XSTYPE_LIST)); | 1228 | acct = xs_dict_append(acct, "emojis", xs_stock(XSTYPE_LIST)); |
| 1211 | 1229 | ||
| 1212 | xs *src = xs_json_loads("{\"privacy\":\"public\", \"language\":\"en\"," | 1230 | xs *src = xs_json_loads("{\"privacy\":\"public\", \"language\":\"en\"," |
| @@ -1220,7 +1238,7 @@ void credentials_get(char **body, char **ctype, int *status, snac snac) | |||
| 1220 | src = xs_dict_set(src, "sensitive", | 1238 | src = xs_dict_set(src, "sensitive", |
| 1221 | strcmp(cw, "open") == 0 ? xs_stock(XSTYPE_TRUE) : xs_stock(XSTYPE_FALSE)); | 1239 | strcmp(cw, "open") == 0 ? xs_stock(XSTYPE_TRUE) : xs_stock(XSTYPE_FALSE)); |
| 1222 | 1240 | ||
| 1223 | src = xs_dict_set(src, "bot", xs_dict_get(snac.config, "bot")); | 1241 | src = xs_dict_set(src, "bot", xs_stock(xs_is_true(bot) ? XSTYPE_TRUE : XSTYPE_FALSE)); |
| 1224 | 1242 | ||
| 1225 | xs *avatar = NULL; | 1243 | xs *avatar = NULL; |
| 1226 | const char *av = xs_dict_get(snac.config, "avatar"); | 1244 | const char *av = xs_dict_get(snac.config, "avatar"); |
| @@ -1319,7 +1337,7 @@ xs_list *mastoapi_timeline(snac *user, const xs_dict *args, const char *index_fn | |||
| 1319 | 1337 | ||
| 1320 | const char *max_id = xs_dict_get(args, "max_id"); | 1338 | const char *max_id = xs_dict_get(args, "max_id"); |
| 1321 | const char *since_id = xs_dict_get(args, "since_id"); | 1339 | const char *since_id = xs_dict_get(args, "since_id"); |
| 1322 | const char *min_id = xs_dict_get(args, "min_id"); | 1340 | const char *min_id = xs_dict_get(args, "min_id"); /* unsupported old-to-new navigation */ |
| 1323 | const char *limit_s = xs_dict_get(args, "limit"); | 1341 | const char *limit_s = xs_dict_get(args, "limit"); |
| 1324 | int limit = 0; | 1342 | int limit = 0; |
| 1325 | int cnt = 0; | 1343 | int cnt = 0; |
| @@ -1330,7 +1348,7 @@ xs_list *mastoapi_timeline(snac *user, const xs_dict *args, const char *index_fn | |||
| 1330 | if (limit == 0) | 1348 | if (limit == 0) |
| 1331 | limit = 20; | 1349 | limit = 20; |
| 1332 | 1350 | ||
| 1333 | if (index_desc_first(f, md5, 0)) { | 1351 | if (min_id == NULL && index_desc_first(f, md5, 0)) { |
| 1334 | do { | 1352 | do { |
| 1335 | xs *msg = NULL; | 1353 | xs *msg = NULL; |
| 1336 | 1354 | ||
| @@ -1348,13 +1366,6 @@ xs_list *mastoapi_timeline(snac *user, const xs_dict *args, const char *index_fn | |||
| 1348 | break; | 1366 | break; |
| 1349 | } | 1367 | } |
| 1350 | 1368 | ||
| 1351 | /* only returns entries newer than min_id */ | ||
| 1352 | /* what does really "Return results immediately newer than ID" mean? */ | ||
| 1353 | if (min_id) { | ||
| 1354 | if (strcmp(md5, MID_TO_MD5(min_id)) == 0) | ||
| 1355 | break; | ||
| 1356 | } | ||
| 1357 | |||
| 1358 | /* get the entry */ | 1369 | /* get the entry */ |
| 1359 | if (user) { | 1370 | if (user) { |
| 1360 | if (!valid_status(timeline_get_by_md5(user, md5, &msg))) | 1371 | if (!valid_status(timeline_get_by_md5(user, md5, &msg))) |
| @@ -1438,8 +1449,35 @@ xs_list *mastoapi_timeline(snac *user, const xs_dict *args, const char *index_fn | |||
| 1438 | } | 1449 | } |
| 1439 | 1450 | ||
| 1440 | 1451 | ||
| 1452 | xs_str *timeline_link_header(const char *endpoint, xs_list *timeline) | ||
| 1453 | /* returns a Link header with paging information */ | ||
| 1454 | { | ||
| 1455 | xs_str *s = NULL; | ||
| 1456 | |||
| 1457 | if (xs_list_len(timeline) == 0) | ||
| 1458 | return NULL; | ||
| 1459 | |||
| 1460 | const xs_dict *first_st = xs_list_get(timeline, 0); | ||
| 1461 | const xs_dict *last_st = xs_list_get(timeline, -1); | ||
| 1462 | const char *first_id = xs_dict_get(first_st, "id"); | ||
| 1463 | const char *last_id = xs_dict_get(last_st, "id"); | ||
| 1464 | const char *host = xs_dict_get(srv_config, "host"); | ||
| 1465 | const char *protocol = xs_dict_get_def(srv_config, "protocol", "https"); | ||
| 1466 | |||
| 1467 | s = xs_fmt( | ||
| 1468 | "<%s:/" "/%s%s?max_id=%s>; rel=\"next\", " | ||
| 1469 | "<%s:/" "/%s%s?since_id=%s>; rel=\"prev\"", | ||
| 1470 | protocol, host, endpoint, last_id, | ||
| 1471 | protocol, host, endpoint, first_id); | ||
| 1472 | |||
| 1473 | srv_debug(1, xs_fmt("timeline_link_header %s", s)); | ||
| 1474 | |||
| 1475 | return s; | ||
| 1476 | } | ||
| 1477 | |||
| 1478 | |||
| 1441 | int mastoapi_get_handler(const xs_dict *req, const char *q_path, | 1479 | int mastoapi_get_handler(const xs_dict *req, const char *q_path, |
| 1442 | char **body, int *b_size, char **ctype) | 1480 | char **body, int *b_size, char **ctype, xs_str **link) |
| 1443 | { | 1481 | { |
| 1444 | (void)b_size; | 1482 | (void)b_size; |
| 1445 | 1483 | ||
| @@ -1699,6 +1737,8 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, | |||
| 1699 | xs *ifn = user_index_fn(&snac1, "private"); | 1737 | xs *ifn = user_index_fn(&snac1, "private"); |
| 1700 | xs *out = mastoapi_timeline(&snac1, args, ifn); | 1738 | xs *out = mastoapi_timeline(&snac1, args, ifn); |
| 1701 | 1739 | ||
| 1740 | *link = timeline_link_header("/api/v1/timelines/home", out); | ||
| 1741 | |||
| 1702 | *body = xs_json_dumps(out, 4); | 1742 | *body = xs_json_dumps(out, 4); |
| 1703 | *ctype = "application/json"; | 1743 | *ctype = "application/json"; |
| 1704 | status = HTTP_STATUS_OK; | 1744 | status = HTTP_STATUS_OK; |
| @@ -1763,8 +1803,14 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, | |||
| 1763 | xs *out = xs_list_new(); | 1803 | xs *out = xs_list_new(); |
| 1764 | const xs_dict *v; | 1804 | const xs_dict *v; |
| 1765 | const xs_list *excl = xs_dict_get(args, "exclude_types[]"); | 1805 | const xs_list *excl = xs_dict_get(args, "exclude_types[]"); |
| 1806 | const char *min_id = xs_dict_get(args, "min_id"); | ||
| 1766 | const char *max_id = xs_dict_get(args, "max_id"); | 1807 | const char *max_id = xs_dict_get(args, "max_id"); |
| 1767 | 1808 | ||
| 1809 | if (dbglevel) { | ||
| 1810 | xs *js = xs_json_dumps(args, 0); | ||
| 1811 | srv_debug(1, xs_fmt("mastoapi_notifications args %s", js)); | ||
| 1812 | } | ||
| 1813 | |||
| 1768 | xs_list_foreach(l, v) { | 1814 | xs_list_foreach(l, v) { |
| 1769 | xs *noti = notify_get(&snac1, v); | 1815 | xs *noti = notify_get(&snac1, v); |
| 1770 | 1816 | ||
| @@ -1795,6 +1841,12 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, | |||
| 1795 | continue; | 1841 | continue; |
| 1796 | } | 1842 | } |
| 1797 | 1843 | ||
| 1844 | if (min_id) { | ||
| 1845 | if (strcmp(fid, min_id) <= 0) { | ||
| 1846 | continue; | ||
| 1847 | } | ||
| 1848 | } | ||
| 1849 | |||
| 1798 | /* convert the type */ | 1850 | /* convert the type */ |
| 1799 | if (strcmp(type, "Like") == 0 || strcmp(type, "EmojiReact") == 0) | 1851 | if (strcmp(type, "Like") == 0 || strcmp(type, "EmojiReact") == 0) |
| 1800 | type = "favourite"; | 1852 | type = "favourite"; |
| @@ -1842,6 +1894,8 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, | |||
| 1842 | out = xs_list_append(out, mn); | 1894 | out = xs_list_append(out, mn); |
| 1843 | } | 1895 | } |
| 1844 | 1896 | ||
| 1897 | srv_debug(1, xs_fmt("mastoapi_notifications count %d", xs_list_len(out))); | ||
| 1898 | |||
| 1845 | *body = xs_json_dumps(out, 4); | 1899 | *body = xs_json_dumps(out, 4); |
| 1846 | *ctype = "application/json"; | 1900 | *ctype = "application/json"; |
| 1847 | status = HTTP_STATUS_OK; | 1901 | status = HTTP_STATUS_OK; |
| @@ -2273,9 +2327,22 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, | |||
| 2273 | } | 2327 | } |
| 2274 | else | 2328 | else |
| 2275 | if (strcmp(cmd, "/v1/markers") == 0) { /** **/ | 2329 | if (strcmp(cmd, "/v1/markers") == 0) { /** **/ |
| 2276 | *body = xs_dup("{}"); | 2330 | if (logged_in) { |
| 2277 | *ctype = "application/json"; | 2331 | const xs_list *timeline = xs_dict_get(args, "timeline[]"); |
| 2278 | status = HTTP_STATUS_OK; | 2332 | xs_str *json = NULL; |
| 2333 | if (!xs_is_null(timeline)) | ||
| 2334 | json = xs_json_dumps(markers_get(&snac1, timeline), 4); | ||
| 2335 | |||
| 2336 | if (!xs_is_null(json)) | ||
| 2337 | *body = json; | ||
| 2338 | else | ||
| 2339 | *body = xs_dup("{}"); | ||
| 2340 | |||
| 2341 | *ctype = "application/json"; | ||
| 2342 | status = HTTP_STATUS_OK; | ||
| 2343 | } | ||
| 2344 | else | ||
| 2345 | status = HTTP_STATUS_UNAUTHORIZED; | ||
| 2279 | } | 2346 | } |
| 2280 | else | 2347 | else |
| 2281 | if (strcmp(cmd, "/v1/followed_tags") == 0) { /** **/ | 2348 | if (strcmp(cmd, "/v1/followed_tags") == 0) { /** **/ |
| @@ -2310,6 +2377,37 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path, | |||
| 2310 | if (xs_is_null(offset) || strcmp(offset, "0") == 0) { | 2377 | if (xs_is_null(offset) || strcmp(offset, "0") == 0) { |
| 2311 | /* reply something only for offset 0; otherwise, | 2378 | /* reply something only for offset 0; otherwise, |
| 2312 | apps like Tusky keep asking again and again */ | 2379 | apps like Tusky keep asking again and again */ |
| 2380 | if (xs_startswith(q, "https://")) { | ||
| 2381 | xs *md5 = xs_md5_hex(q, strlen(q)); | ||
| 2382 | |||
| 2383 | if (!timeline_here(&snac1, md5)) { | ||
| 2384 | xs *object = NULL; | ||
| 2385 | int status; | ||
| 2386 | |||
| 2387 | status = activitypub_request(&snac1, q, &object); | ||
| 2388 | snac_debug(&snac1, 1, xs_fmt("Request searched URL %s %d", q, status)); | ||
| 2389 | |||
| 2390 | if (valid_status(status)) { | ||
| 2391 | /* got it; also request the actor */ | ||
| 2392 | const char *attr_to = get_atto(object); | ||
| 2393 | xs *actor_obj = NULL; | ||
| 2394 | |||
| 2395 | if (!xs_is_null(attr_to)) { | ||
| 2396 | status = actor_request(&snac1, attr_to, &actor_obj); | ||
| 2397 | |||
| 2398 | snac_debug(&snac1, 1, xs_fmt("Request author %s of %s %d", attr_to, q, status)); | ||
| 2399 | |||
| 2400 | if (valid_status(status)) { | ||
| 2401 | /* add the actor */ | ||
| 2402 | actor_add(attr_to, actor_obj); | ||
| 2403 | |||
| 2404 | /* add the post to the timeline */ | ||
| 2405 | timeline_add(&snac1, q, object); | ||
| 2406 | } | ||
| 2407 | } | ||
| 2408 | } | ||
| 2409 | } | ||
| 2410 | } | ||
| 2313 | 2411 | ||
| 2314 | if (!xs_is_null(q)) { | 2412 | if (!xs_is_null(q)) { |
| 2315 | if (xs_is_null(type) || strcmp(type, "accounts") == 0) { | 2413 | if (xs_is_null(type) || strcmp(type, "accounts") == 0) { |
| @@ -2945,6 +3043,7 @@ int mastoapi_post_handler(const xs_dict *req, const char *q_path, | |||
| 2945 | status = HTTP_STATUS_UNPROCESSABLE_CONTENT; | 3043 | status = HTTP_STATUS_UNPROCESSABLE_CONTENT; |
| 2946 | } | 3044 | } |
| 2947 | } | 3045 | } |
| 3046 | else | ||
| 2948 | if (xs_startswith(cmd, "/v1/lists/")) { /** list maintenance **/ | 3047 | if (xs_startswith(cmd, "/v1/lists/")) { /** list maintenance **/ |
| 2949 | if (logged_in) { | 3048 | if (logged_in) { |
| 2950 | xs *l = xs_split(cmd, "/"); | 3049 | xs *l = xs_split(cmd, "/"); |
| @@ -2972,9 +3071,35 @@ int mastoapi_post_handler(const xs_dict *req, const char *q_path, | |||
| 2972 | } | 3071 | } |
| 2973 | } | 3072 | } |
| 2974 | } | 3073 | } |
| 3074 | } | ||
| 3075 | else if (strcmp(cmd, "/v1/markers") == 0) { /** **/ | ||
| 3076 | xs_str *json = NULL; | ||
| 3077 | if (logged_in) { | ||
| 3078 | const xs_str *home_marker = xs_dict_get(args, "home[last_read_id]"); | ||
| 3079 | if (xs_is_null(home_marker)) { | ||
| 3080 | const xs_dict *home = xs_dict_get(args, "home"); | ||
| 3081 | if (!xs_is_null(home)) | ||
| 3082 | home_marker = xs_dict_get(home, "last_read_id"); | ||
| 3083 | } | ||
| 3084 | |||
| 3085 | const xs_str *notify_marker = xs_dict_get(args, "notifications[last_read_id]"); | ||
| 3086 | if (xs_is_null(notify_marker)) { | ||
| 3087 | const xs_dict *notify = xs_dict_get(args, "notifications"); | ||
| 3088 | if (!xs_is_null(notify)) | ||
| 3089 | notify_marker = xs_dict_get(notify, "last_read_id"); | ||
| 3090 | } | ||
| 3091 | json = xs_json_dumps(markers_set(&snac, home_marker, notify_marker), 4); | ||
| 3092 | } | ||
| 3093 | if (!xs_is_null(json)) | ||
| 3094 | *body = json; | ||
| 2975 | else | 3095 | else |
| 2976 | status = HTTP_STATUS_UNPROCESSABLE_CONTENT; | 3096 | *body = xs_dup("{}"); |
| 3097 | |||
| 3098 | *ctype = "application/json"; | ||
| 3099 | status = HTTP_STATUS_OK; | ||
| 2977 | } | 3100 | } |
| 3101 | else | ||
| 3102 | status = HTTP_STATUS_UNPROCESSABLE_CONTENT; | ||
| 2978 | 3103 | ||
| 2979 | /* user cleanup */ | 3104 | /* user cleanup */ |
| 2980 | if (logged_in) | 3105 | if (logged_in) |