summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar grunfink2023-06-11 07:05:07 +0000
committerGravatar grunfink2023-06-11 07:05:07 +0000
commit422b3148aecc5e3fdd94f5a9655de191766e10f6 (patch)
tree70b00c4361a45f223dc2c7a2acfa2697e446c0a4
parentUpdated TODO. (diff)
parentOnly allow logged-in user to use statuses API (diff)
downloadsnac2-422b3148aecc5e3fdd94f5a9655de191766e10f6.tar.gz
snac2-422b3148aecc5e3fdd94f5a9655de191766e10f6.tar.xz
snac2-422b3148aecc5e3fdd94f5a9655de191766e10f6.zip
Merge pull request 'Mastodon API private timeline fixes' (#44) from poesty/snac2:master into master
Reviewed-on: https://codeberg.org/grunfink/snac2/pulls/44
-rw-r--r--mastoapi.c211
1 files changed, 112 insertions, 99 deletions
diff --git a/mastoapi.c b/mastoapi.c
index a76a6ab..acefe57 100644
--- a/mastoapi.c
+++ b/mastoapi.c
@@ -1172,7 +1172,7 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path,
1172 1172
1173 /* only return entries older that max_id */ 1173 /* only return entries older that max_id */
1174 if (max_id) { 1174 if (max_id) {
1175 if (strcmp(v, max_id) == 0) 1175 if (strcmp(v, MID_TO_MD5(max_id)) == 0)
1176 max_id = NULL; 1176 max_id = NULL;
1177 1177
1178 continue; 1178 continue;
@@ -1180,14 +1180,14 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path,
1180 1180
1181 /* only returns entries newer than since_id */ 1181 /* only returns entries newer than since_id */
1182 if (since_id) { 1182 if (since_id) {
1183 if (strcmp(v, since_id) == 0) 1183 if (strcmp(v, MID_TO_MD5(since_id)) == 0)
1184 break; 1184 break;
1185 } 1185 }
1186 1186
1187 /* only returns entries newer than min_id */ 1187 /* only returns entries newer than min_id */
1188 /* what does really "Return results immediately newer than ID" mean? */ 1188 /* what does really "Return results immediately newer than ID" mean? */
1189 if (min_id) { 1189 if (min_id) {
1190 if (strcmp(v, min_id) == 0) 1190 if (strcmp(v, MID_TO_MD5(min_id)) == 0)
1191 break; 1191 break;
1192 } 1192 }
1193 1193
@@ -1200,6 +1200,11 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path,
1200 if (strcmp(type, "Note") != 0 && strcmp(type, "Question") != 0) 1200 if (strcmp(type, "Note") != 0 && strcmp(type, "Question") != 0)
1201 continue; 1201 continue;
1202 1202
1203 /* discard notes from people we don't follow with no boosts */
1204 if (!following_check(&snac1, xs_dict_get(msg, "attributedTo")) &&
1205 object_announces_len(xs_dict_get(msg, "id")) == 0)
1206 continue;
1207
1203 /* discard notes from muted morons */ 1208 /* discard notes from muted morons */
1204 if (is_muted(&snac1, xs_dict_get(msg, "attributedTo"))) 1209 if (is_muted(&snac1, xs_dict_get(msg, "attributedTo")))
1205 continue; 1210 continue;
@@ -1505,102 +1510,106 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path,
1505 else 1510 else
1506 if (xs_startswith(cmd, "/v1/statuses/")) { /** **/ 1511 if (xs_startswith(cmd, "/v1/statuses/")) { /** **/
1507 /* information about a status */ 1512 /* information about a status */
1508 xs *l = xs_split(cmd, "/"); 1513 if (logged_in) {
1509 const char *id = xs_list_get(l, 3); 1514 xs *l = xs_split(cmd, "/");
1510 const char *op = xs_list_get(l, 4); 1515 const char *id = xs_list_get(l, 3);
1516 const char *op = xs_list_get(l, 4);
1511 1517
1512 if (!xs_is_null(id)) { 1518 if (!xs_is_null(id)) {
1513 xs *msg = NULL; 1519 xs *msg = NULL;
1514 xs *out = NULL; 1520 xs *out = NULL;
1515 1521
1516 /* skip the 'fake' part of the id */ 1522 /* skip the 'fake' part of the id */
1517 id = MID_TO_MD5(id); 1523 id = MID_TO_MD5(id);
1518 1524
1519 if (valid_status(object_get_by_md5(id, &msg))) { 1525 if (valid_status(object_get_by_md5(id, &msg))) {
1520 if (op == NULL) { 1526 if (op == NULL) {
1521 if (!is_muted(&snac1, xs_dict_get(msg, "attributedTo"))) { 1527 if (!is_muted(&snac1, xs_dict_get(msg, "attributedTo"))) {
1522 /* return the status itself */ 1528 /* return the status itself */
1523 out = mastoapi_status(&snac1, msg); 1529 out = mastoapi_status(&snac1, msg);
1530 }
1524 } 1531 }
1525 } 1532 else
1526 else 1533 if (strcmp(op, "context") == 0) { /** **/
1527 if (strcmp(op, "context") == 0) { /** **/ 1534 /* return ancestors and children */
1528 /* return ancestors and children */ 1535 xs *anc = xs_list_new();
1529 xs *anc = xs_list_new(); 1536 xs *des = xs_list_new();
1530 xs *des = xs_list_new(); 1537 xs_list *p;
1531 xs_list *p; 1538 xs_str *v;
1532 xs_str *v; 1539 char pid[64];
1533 char pid[64];
1534 1540
1535 /* build the [grand]parent list, moving up */ 1541 /* build the [grand]parent list, moving up */
1536 strncpy(pid, id, sizeof(pid)); 1542 strncpy(pid, id, sizeof(pid));
1537 1543
1538 while (object_parent(pid, pid, sizeof(pid))) { 1544 while (object_parent(pid, pid, sizeof(pid))) {
1539 xs *m2 = NULL; 1545 xs *m2 = NULL;
1540 1546
1541 if (valid_status(timeline_get_by_md5(&snac1, pid, &m2))) { 1547 if (valid_status(timeline_get_by_md5(&snac1, pid, &m2))) {
1542 xs *st = mastoapi_status(&snac1, m2); 1548 xs *st = mastoapi_status(&snac1, m2);
1543 anc = xs_list_insert(anc, 0, st); 1549 anc = xs_list_insert(anc, 0, st);
1550 }
1551 else
1552 break;
1544 } 1553 }
1545 else
1546 break;
1547 }
1548 1554
1549 /* build the children list */ 1555 /* build the children list */
1550 xs *children = object_children(xs_dict_get(msg, "id")); 1556 xs *children = object_children(xs_dict_get(msg, "id"));
1551 p = children; 1557 p = children;
1552 1558
1553 while (xs_list_iter(&p, &v)) { 1559 while (xs_list_iter(&p, &v)) {
1554 xs *m2 = NULL; 1560 xs *m2 = NULL;
1555 1561
1556 if (valid_status(timeline_get_by_md5(&snac1, v, &m2))) { 1562 if (valid_status(timeline_get_by_md5(&snac1, v, &m2))) {
1557 if (xs_is_null(xs_dict_get(m2, "name"))) { 1563 if (xs_is_null(xs_dict_get(m2, "name"))) {
1558 xs *st = mastoapi_status(&snac1, m2); 1564 xs *st = mastoapi_status(&snac1, m2);
1559 des = xs_list_append(des, st); 1565 des = xs_list_append(des, st);
1566 }
1560 } 1567 }
1561 } 1568 }
1562 }
1563 1569
1564 out = xs_dict_new(); 1570 out = xs_dict_new();
1565 out = xs_dict_append(out, "ancestors", anc); 1571 out = xs_dict_append(out, "ancestors", anc);
1566 out = xs_dict_append(out, "descendants", des); 1572 out = xs_dict_append(out, "descendants", des);
1567 } 1573 }
1568 else 1574 else
1569 if (strcmp(op, "reblogged_by") == 0 || /** **/ 1575 if (strcmp(op, "reblogged_by") == 0 || /** **/
1570 strcmp(op, "favourited_by") == 0) { /** **/ 1576 strcmp(op, "favourited_by") == 0) { /** **/
1571 /* return the list of people who liked or boosted this */ 1577 /* return the list of people who liked or boosted this */
1572 out = xs_list_new(); 1578 out = xs_list_new();
1573 1579
1574 xs *l = NULL; 1580 xs *l = NULL;
1575 1581
1576 if (op[0] == 'r') 1582 if (op[0] == 'r')
1577 l = object_announces(xs_dict_get(msg, "id")); 1583 l = object_announces(xs_dict_get(msg, "id"));
1578 else 1584 else
1579 l = object_likes(xs_dict_get(msg, "id")); 1585 l = object_likes(xs_dict_get(msg, "id"));
1580 1586
1581 xs_list *p = l; 1587 xs_list *p = l;
1582 xs_str *v; 1588 xs_str *v;
1583 1589
1584 while (xs_list_iter(&p, &v)) { 1590 while (xs_list_iter(&p, &v)) {
1585 xs *actor2 = NULL; 1591 xs *actor2 = NULL;
1586 1592
1587 if (valid_status(object_get_by_md5(v, &actor2))) { 1593 if (valid_status(object_get_by_md5(v, &actor2))) {
1588 xs *acct2 = mastoapi_account(actor2); 1594 xs *acct2 = mastoapi_account(actor2);
1589 1595
1590 out = xs_list_append(out, acct2); 1596 out = xs_list_append(out, acct2);
1597 }
1591 } 1598 }
1592 } 1599 }
1593 } 1600 }
1594 } 1601 else
1595 else 1602 srv_debug(1, xs_fmt("mastoapi status: bad id %s", id));
1596 srv_debug(1, xs_fmt("mastoapi status: bad id %s", id));
1597 1603
1598 if (out != NULL) { 1604 if (out != NULL) {
1599 *body = xs_json_dumps_pp(out, 4); 1605 *body = xs_json_dumps_pp(out, 4);
1600 *ctype = "application/json"; 1606 *ctype = "application/json";
1601 status = 200; 1607 status = 200;
1608 }
1602 } 1609 }
1603 } 1610 }
1611 else
1612 status = 401;
1604 } 1613 }
1605 else 1614 else
1606 if (strcmp(cmd, "/v1/preferences") == 0) { /** **/ 1615 if (strcmp(cmd, "/v1/preferences") == 0) { /** **/
@@ -1622,43 +1631,47 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path,
1622 } 1631 }
1623 else 1632 else
1624 if (strcmp(cmd, "/v2/search") == 0) { /** **/ 1633 if (strcmp(cmd, "/v2/search") == 0) { /** **/
1625 const char *q = xs_dict_get(args, "q"); 1634 if (logged_in) {
1626 const char *type = xs_dict_get(args, "type"); 1635 const char *q = xs_dict_get(args, "q");
1627 const char *offset = xs_dict_get(args, "offset"); 1636 const char *type = xs_dict_get(args, "type");
1637 const char *offset = xs_dict_get(args, "offset");
1628 1638
1629 xs *acl = xs_list_new(); 1639 xs *acl = xs_list_new();
1630 xs *stl = xs_list_new(); 1640 xs *stl = xs_list_new();
1631 xs *htl = xs_list_new(); 1641 xs *htl = xs_list_new();
1632 xs *res = xs_dict_new(); 1642 xs *res = xs_dict_new();
1633 1643
1634 if (xs_is_null(offset) || strcmp(offset, "0") == 0) { 1644 if (xs_is_null(offset) || strcmp(offset, "0") == 0) {
1635 /* reply something only for offset 0; otherwise, 1645 /* reply something only for offset 0; otherwise,
1636 apps like Tusky keep asking again and again */ 1646 apps like Tusky keep asking again and again */
1637 1647
1638 if (!xs_is_null(q) && !xs_is_null(type) && strcmp(type, "accounts") == 0) { 1648 if (!xs_is_null(q) && !xs_is_null(type) && strcmp(type, "accounts") == 0) {
1639 /* do a webfinger query */ 1649 /* do a webfinger query */
1640 char *actor = NULL; 1650 char *actor = NULL;
1641 char *user = NULL; 1651 char *user = NULL;
1642 1652
1643 if (valid_status(webfinger_request(q, &actor, &user))) { 1653 if (valid_status(webfinger_request(q, &actor, &user))) {
1644 xs *actor_o = NULL; 1654 xs *actor_o = NULL;
1645 1655
1646 if (valid_status(actor_request(&snac1, actor, &actor_o))) { 1656 if (valid_status(actor_request(&snac1, actor, &actor_o))) {
1647 xs *acct = mastoapi_account(actor_o); 1657 xs *acct = mastoapi_account(actor_o);
1648 1658
1649 acl = xs_list_append(acl, acct); 1659 acl = xs_list_append(acl, acct);
1660 }
1650 } 1661 }
1651 } 1662 }
1652 } 1663 }
1653 }
1654 1664
1655 res = xs_dict_append(res, "accounts", acl); 1665 res = xs_dict_append(res, "accounts", acl);
1656 res = xs_dict_append(res, "statuses", stl); 1666 res = xs_dict_append(res, "statuses", stl);
1657 res = xs_dict_append(res, "hashtags", htl); 1667 res = xs_dict_append(res, "hashtags", htl);
1658 1668
1659 *body = xs_json_dumps_pp(res, 4); 1669 *body = xs_json_dumps_pp(res, 4);
1660 *ctype = "application/json"; 1670 *ctype = "application/json";
1661 status = 200; 1671 status = 200;
1672 }
1673 else
1674 status = 401;
1662 } 1675 }
1663 1676
1664 /* user cleanup */ 1677 /* user cleanup */