diff options
| -rw-r--r-- | RELEASE_NOTES.md | 2 | ||||
| -rw-r--r-- | activitypub.c | 18 | ||||
| -rw-r--r-- | examples/snac_netbsd | 6 | ||||
| -rw-r--r-- | html.c | 13 | ||||
| -rw-r--r-- | xs_openssl.h | 18 |
5 files changed, 40 insertions, 17 deletions
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 57102c3..ac40ee9 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md | |||
| @@ -18,6 +18,8 @@ Fixed some crashes (special thanks to Louis Merlin for helping me with this). | |||
| 18 | 18 | ||
| 19 | Updated Docker scripts to avoid generating a useless log file. | 19 | Updated Docker scripts to avoid generating a useless log file. |
| 20 | 20 | ||
| 21 | Fixed some memory leaks, key generation errors and HTML inconsistencies (contributed by dandelions). | ||
| 22 | |||
| 21 | Added a new CONTRIBUTING.md file. Among other guidelines, I explicitly say there that AI contributions are **not** accepted. | 23 | Added a new CONTRIBUTING.md file. Among other guidelines, I explicitly say there that AI contributions are **not** accepted. |
| 22 | 24 | ||
| 23 | snac is now available as a Yunohost [app](https://apps.yunohost.org/app/snac). Thank you very much to Bruno Cesar Rocha for this. | 25 | snac is now available as a Yunohost [app](https://apps.yunohost.org/app/snac). Thank you very much to Bruno Cesar Rocha for this. |
diff --git a/activitypub.c b/activitypub.c index 0535269..ed9acf9 100644 --- a/activitypub.c +++ b/activitypub.c | |||
| @@ -645,12 +645,13 @@ xs_list *recipient_list(snac *snac, const xs_dict *msg, int expand_public) | |||
| 645 | 645 | ||
| 646 | while (xs_list_iter(&l, &v)) { | 646 | while (xs_list_iter(&l, &v)) { |
| 647 | if (expand_public) { | 647 | if (expand_public) { |
| 648 | xs *followers_url = xs_fmt("%s/followers", snac->actor); | ||
| 648 | if (strcmp(v, public_address) == 0 || | 649 | if (strcmp(v, public_address) == 0 || |
| 649 | /* check if it's a followers collection URL */ | 650 | /* check if it's a followers collection URL */ |
| 650 | (xs_type(v) == XSTYPE_STRING && | 651 | (xs_type(v) == XSTYPE_STRING && |
| 651 | strcmp(v, xs_fmt("%s/followers", snac->actor)) == 0) || | 652 | strcmp(v, followers_url) == 0) || |
| 652 | (xs_type(v) == XSTYPE_LIST && | 653 | (xs_type(v) == XSTYPE_LIST && |
| 653 | xs_list_in(v, xs_fmt("%s/followers", snac->actor)) != -1)) { | 654 | xs_list_in(v, followers_url) != -1)) { |
| 654 | /* iterate the followers and add them */ | 655 | /* iterate the followers and add them */ |
| 655 | xs *fwers = follower_list(snac); | 656 | xs *fwers = follower_list(snac); |
| 656 | const char *actor; | 657 | const char *actor; |
| @@ -1624,6 +1625,7 @@ xs_dict *msg_emoji_init(snac *snac, const char *mid, const char *eid_o) | |||
| 1624 | else if (*eid == '%') { | 1625 | else if (*eid == '%') { |
| 1625 | content = xs_url_dec_emoji(xs_dup(eid)); | 1626 | content = xs_url_dec_emoji(xs_dup(eid)); |
| 1626 | if (content == NULL) { | 1627 | if (content == NULL) { |
| 1628 | xs_free(n_msg); | ||
| 1627 | return NULL; | 1629 | return NULL; |
| 1628 | } | 1630 | } |
| 1629 | } | 1631 | } |
| @@ -1631,8 +1633,10 @@ xs_dict *msg_emoji_init(snac *snac, const char *mid, const char *eid_o) | |||
| 1631 | content = xs_fmt(":%s:", eid); | 1633 | content = xs_fmt(":%s:", eid); |
| 1632 | const char *emo = xs_dict_get(emjs, content); | 1634 | const char *emo = xs_dict_get(emjs, content); |
| 1633 | 1635 | ||
| 1634 | if (emo == NULL) | 1636 | if (emo == NULL) { |
| 1637 | xs_free(n_msg); | ||
| 1635 | return NULL; | 1638 | return NULL; |
| 1639 | } | ||
| 1636 | 1640 | ||
| 1637 | if (xs_match(emo, "https://*|http://*")) { /* emoji is an URL to an image */ | 1641 | if (xs_match(emo, "https://*|http://*")) { /* emoji is an URL to an image */ |
| 1638 | icon = xs_dict_set(icon, "type", "Image"); | 1642 | icon = xs_dict_set(icon, "type", "Image"); |
| @@ -1667,9 +1671,10 @@ xs_dict *msg_emoji_init(snac *snac, const char *mid, const char *eid_o) | |||
| 1667 | 1671 | ||
| 1668 | accounts = xs_list_append(accounts, snac->actor); | 1672 | accounts = xs_list_append(accounts, snac->actor); |
| 1669 | 1673 | ||
| 1674 | xs *to_duplicate = xs_dup(xs_list_get(xs_dict_get(n_msg, "to"), 1)); | ||
| 1670 | n_msg = xs_dict_set(n_msg, "content", content); | 1675 | n_msg = xs_dict_set(n_msg, "content", content); |
| 1671 | n_msg = xs_dict_set(n_msg, "accounts", accounts); | 1676 | n_msg = xs_dict_set(n_msg, "accounts", accounts); |
| 1672 | n_msg = xs_dict_set(n_msg, "attributedTo", xs_list_get(xs_dict_get(n_msg, "to"), 1)); | 1677 | n_msg = xs_dict_set(n_msg, "attributedTo", to_duplicate); |
| 1673 | n_msg = xs_dict_set(n_msg, "accountId", snac->uid); | 1678 | n_msg = xs_dict_set(n_msg, "accountId", snac->uid); |
| 1674 | n_msg = xs_dict_set(n_msg, "tag", tag); | 1679 | n_msg = xs_dict_set(n_msg, "tag", tag); |
| 1675 | 1680 | ||
| @@ -1679,6 +1684,7 @@ xs_dict *msg_emoji_init(snac *snac, const char *mid, const char *eid_o) | |||
| 1679 | return n_msg; | 1684 | return n_msg; |
| 1680 | } | 1685 | } |
| 1681 | 1686 | ||
| 1687 | xs_free(n_msg); | ||
| 1682 | return NULL; | 1688 | return NULL; |
| 1683 | } | 1689 | } |
| 1684 | 1690 | ||
| @@ -1710,13 +1716,14 @@ xs_dict *msg_emoji_unreact(snac *user, const char *mid, const char *eid) | |||
| 1710 | if (strlen(eid) == 12 && *eid == '%') { | 1716 | if (strlen(eid) == 12 && *eid == '%') { |
| 1711 | eid = xs_url_dec(eid); | 1717 | eid = xs_url_dec(eid); |
| 1712 | if (eid == NULL) { | 1718 | if (eid == NULL) { |
| 1719 | xs_free(msg); | ||
| 1713 | return NULL; | 1720 | return NULL; |
| 1714 | } | 1721 | } |
| 1715 | } | 1722 | } |
| 1716 | 1723 | ||
| 1717 | /* lets get all emotes for this msg, and compare it to our content */ | 1724 | /* lets get all emotes for this msg, and compare it to our content */ |
| 1718 | while (xs_list_next(emotes, &v, &c)) { | 1725 | while (xs_list_next(emotes, &v, &c)) { |
| 1719 | xs_dict *e = NULL; | 1726 | xs *e = NULL; |
| 1720 | if (valid_status(object_get_by_md5(v, &e))) { | 1727 | if (valid_status(object_get_by_md5(v, &e))) { |
| 1721 | const char *content = xs_dict_get(e, "content"); | 1728 | const char *content = xs_dict_get(e, "content"); |
| 1722 | const char *id = xs_dict_get(e, "id"); | 1729 | const char *id = xs_dict_get(e, "id"); |
| @@ -1730,6 +1737,7 @@ xs_dict *msg_emoji_unreact(snac *user, const char *mid, const char *eid) | |||
| 1730 | } | 1737 | } |
| 1731 | } | 1738 | } |
| 1732 | 1739 | ||
| 1740 | xs_free(msg); | ||
| 1733 | return NULL; | 1741 | return NULL; |
| 1734 | } | 1742 | } |
| 1735 | 1743 | ||
diff --git a/examples/snac_netbsd b/examples/snac_netbsd index 06991b1..19c221a 100644 --- a/examples/snac_netbsd +++ b/examples/snac_netbsd | |||
| @@ -31,4 +31,8 @@ snac_precmd() { | |||
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | load_rc_config $name | 33 | load_rc_config $name |
| 34 | run_rc_command "$1" \ No newline at end of file | 34 | |
| 35 | # increase the number of file descriptors | ||
| 36 | ulimit -n 1024 | ||
| 37 | |||
| 38 | run_rc_command "$1" | ||
| @@ -1451,6 +1451,7 @@ xs_html *html_checkbox(const char *form_name, const char *label, int flag) | |||
| 1451 | xs_html_sctag("input", | 1451 | xs_html_sctag("input", |
| 1452 | xs_html_attr("type", "checkbox"), | 1452 | xs_html_attr("type", "checkbox"), |
| 1453 | xs_html_attr("name", form_name), | 1453 | xs_html_attr("name", form_name), |
| 1454 | xs_html_attr("id", form_name), | ||
| 1454 | xs_html_attr(flag ? "checked" : "", NULL)), | 1455 | xs_html_attr(flag ? "checked" : "", NULL)), |
| 1455 | xs_html_tag("label", | 1456 | xs_html_tag("label", |
| 1456 | xs_html_attr("for", form_name), | 1457 | xs_html_attr("for", form_name), |
| @@ -4111,7 +4112,7 @@ void notify_filter(snac *user, const xs_dict *p_vars) | |||
| 4111 | int folreq_on = (v = xs_dict_get(p_vars, "folreqs_on")) ? strcmp(v, "on") == 0 : 0; | 4112 | int folreq_on = (v = xs_dict_get(p_vars, "folreqs_on")) ? strcmp(v, "on") == 0 : 0; |
| 4112 | int blocks_on = (v = xs_dict_get(p_vars, "blocks_on")) ? strcmp(v, "on") == 0 : 0; | 4113 | int blocks_on = (v = xs_dict_get(p_vars, "blocks_on")) ? strcmp(v, "on") == 0 : 0; |
| 4113 | int polls_on = (v = xs_dict_get(p_vars, "polls_on")) ? strcmp(v, "on") == 0 : 0; | 4114 | int polls_on = (v = xs_dict_get(p_vars, "polls_on")) ? strcmp(v, "on") == 0 : 0; |
| 4114 | xs_dict *filter = xs_dict_new(); | 4115 | xs *filter = xs_dict_new(); |
| 4115 | filter = xs_dict_set(filter, "likes", xs_stock(likes_on ? XSTYPE_TRUE : XSTYPE_FALSE)); | 4116 | filter = xs_dict_set(filter, "likes", xs_stock(likes_on ? XSTYPE_TRUE : XSTYPE_FALSE)); |
| 4116 | filter = xs_dict_set(filter, "reacts", xs_stock(reacts_on ? XSTYPE_TRUE : XSTYPE_FALSE)); | 4117 | filter = xs_dict_set(filter, "reacts", xs_stock(reacts_on ? XSTYPE_TRUE : XSTYPE_FALSE)); |
| 4117 | filter = xs_dict_set(filter, "mentions", xs_stock(ments_on ? XSTYPE_TRUE : XSTYPE_FALSE)); | 4118 | filter = xs_dict_set(filter, "mentions", xs_stock(ments_on ? XSTYPE_TRUE : XSTYPE_FALSE)); |
| @@ -4122,6 +4123,7 @@ void notify_filter(snac *user, const xs_dict *p_vars) | |||
| 4122 | filter = xs_dict_set(filter, "blocks", xs_stock(blocks_on ? XSTYPE_TRUE : XSTYPE_FALSE)); | 4123 | filter = xs_dict_set(filter, "blocks", xs_stock(blocks_on ? XSTYPE_TRUE : XSTYPE_FALSE)); |
| 4123 | filter = xs_dict_set(filter, "polls", xs_stock(polls_on ? XSTYPE_TRUE : XSTYPE_FALSE)); | 4124 | filter = xs_dict_set(filter, "polls", xs_stock(polls_on ? XSTYPE_TRUE : XSTYPE_FALSE)); |
| 4124 | user->config = xs_dict_set(user->config, "notify_filter", filter); | 4125 | user->config = xs_dict_set(user->config, "notify_filter", filter); |
| 4126 | user->tz = xs_dict_get_def(user->config, "tz", "UTC"); // previous line invalidates user->tz | ||
| 4125 | } | 4127 | } |
| 4126 | 4128 | ||
| 4127 | xs_str *html_notifications(snac *user, int skip, int show) | 4129 | xs_str *html_notifications(snac *user, int skip, int show) |
| @@ -4137,7 +4139,9 @@ xs_str *html_notifications(snac *user, int skip, int show) | |||
| 4137 | xs_html *body = html_user_body(user, 0); | 4139 | xs_html *body = html_user_body(user, 0); |
| 4138 | const xs_dict *n_filter = xs_dict_get(user->config, "notify_filter"); | 4140 | const xs_dict *n_filter = xs_dict_get(user->config, "notify_filter"); |
| 4139 | if (!n_filter) { | 4141 | if (!n_filter) { |
| 4140 | user->config = xs_dict_set(user->config, "notify_filter", xs_dict_new()); | 4142 | xs *filter = xs_dict_new(); |
| 4143 | user->config = xs_dict_set(user->config, "notify_filter", filter); | ||
| 4144 | user->tz = xs_dict_get_def(user->config, "tz", "UTC"); // previous line invalidates user->tz | ||
| 4141 | n_filter = xs_dict_get(user->config, "notify_filter"); | 4145 | n_filter = xs_dict_get(user->config, "notify_filter"); |
| 4142 | } | 4146 | } |
| 4143 | xs *n_list = notify_filter_list(user, n_list_unfilt); | 4147 | xs *n_list = notify_filter_list(user, n_list_unfilt); |
| @@ -4158,6 +4162,7 @@ xs_str *html_notifications(snac *user, int skip, int show) | |||
| 4158 | body); | 4162 | body); |
| 4159 | 4163 | ||
| 4160 | xs *filter_notifs_action = xs_fmt("%s/admin/filter-notifications", user->actor); | 4164 | xs *filter_notifs_action = xs_fmt("%s/admin/filter-notifications", user->actor); |
| 4165 | xs *notifs_action = xs_fmt("%s/notifications", user->actor); | ||
| 4161 | xs_html *notifs_form = xs_html_tag("form", | 4166 | xs_html *notifs_form = xs_html_tag("form", |
| 4162 | xs_html_attr("autocomplete", "off"), | 4167 | xs_html_attr("autocomplete", "off"), |
| 4163 | xs_html_attr("method", "post"), | 4168 | xs_html_attr("method", "post"), |
| @@ -4167,7 +4172,7 @@ xs_str *html_notifications(snac *user, int skip, int show) | |||
| 4167 | xs_html_sctag("input", | 4172 | xs_html_sctag("input", |
| 4168 | xs_html_attr("type", "hidden"), | 4173 | xs_html_attr("type", "hidden"), |
| 4169 | xs_html_attr("name", "hard-redir"), | 4174 | xs_html_attr("name", "hard-redir"), |
| 4170 | xs_html_attr("value", xs_fmt("%s/notifications", user->actor))), | 4175 | xs_html_attr("value", notifs_action)), |
| 4171 | html_checkbox("likes_on", L("Likes"), n_likes_on), | 4176 | html_checkbox("likes_on", L("Likes"), n_likes_on), |
| 4172 | html_checkbox("reacts_on", L("Emoji reacts"), n_reacts_on), | 4177 | html_checkbox("reacts_on", L("Emoji reacts"), n_reacts_on), |
| 4173 | html_checkbox("mentions_on", L("Mentions"), n_ments_on), | 4178 | html_checkbox("mentions_on", L("Mentions"), n_ments_on), |
| @@ -5568,7 +5573,7 @@ int html_post_handler(const xs_dict *req, const char *q_path, | |||
| 5568 | 5573 | ||
| 5569 | eid = xs_strip_chars_i(eid, ":"); | 5574 | eid = xs_strip_chars_i(eid, ":"); |
| 5570 | 5575 | ||
| 5571 | const xs_dict *ret = msg_emoji_init(&snac, id, eid); | 5576 | xs *ret = msg_emoji_init(&snac, id, eid); |
| 5572 | /* fails if either invalid or already reacted */ | 5577 | /* fails if either invalid or already reacted */ |
| 5573 | if (!ret) | 5578 | if (!ret) |
| 5574 | ret = msg_emoji_unreact(&snac, id, eid); | 5579 | ret = msg_emoji_unreact(&snac, id, eid); |
diff --git a/xs_openssl.h b/xs_openssl.h index 64b59dd..6d804f7 100644 --- a/xs_openssl.h +++ b/xs_openssl.h | |||
| @@ -38,7 +38,7 @@ xs_str *xs_base64_enc(const xs_val *data, int sz) | |||
| 38 | { | 38 | { |
| 39 | BIO *mem, *b64; | 39 | BIO *mem, *b64; |
| 40 | BUF_MEM *bptr; | 40 | BUF_MEM *bptr; |
| 41 | 41 | ||
| 42 | b64 = BIO_new(BIO_f_base64()); | 42 | b64 = BIO_new(BIO_f_base64()); |
| 43 | mem = BIO_new(BIO_s_mem()); | 43 | mem = BIO_new(BIO_s_mem()); |
| 44 | b64 = BIO_push(b64, mem); | 44 | b64 = BIO_push(b64, mem); |
| @@ -118,16 +118,16 @@ xs_dict *xs_evp_genkey(int bits) | |||
| 118 | /* generates an RSA keypair using the EVP interface */ | 118 | /* generates an RSA keypair using the EVP interface */ |
| 119 | { | 119 | { |
| 120 | xs_dict *keypair = NULL; | 120 | xs_dict *keypair = NULL; |
| 121 | EVP_PKEY_CTX *ctx; | 121 | EVP_PKEY_CTX *ctx = NULL; |
| 122 | EVP_PKEY *pkey = NULL; | 122 | EVP_PKEY *pkey = NULL; |
| 123 | 123 | ||
| 124 | if ((ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL)) == NULL) | 124 | if ((ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL)) == NULL) |
| 125 | goto end; | 125 | return NULL; |
| 126 | 126 | ||
| 127 | if (EVP_PKEY_keygen_init(ctx) <= 0 || | 127 | if (EVP_PKEY_keygen_init(ctx) <= 0 || |
| 128 | EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) <= 0 || | 128 | EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) <= 0 || |
| 129 | EVP_PKEY_keygen(ctx, &pkey) <= 0) | 129 | EVP_PKEY_keygen(ctx, &pkey) <= 0) |
| 130 | goto end; | 130 | return NULL; |
| 131 | 131 | ||
| 132 | BIO *bs = BIO_new(BIO_s_mem()); | 132 | BIO *bs = BIO_new(BIO_s_mem()); |
| 133 | BIO *bp = BIO_new(BIO_s_mem()); | 133 | BIO *bp = BIO_new(BIO_s_mem()); |
| @@ -142,13 +142,17 @@ xs_dict *xs_evp_genkey(int bits) | |||
| 142 | 142 | ||
| 143 | keypair = xs_dict_new(); | 143 | keypair = xs_dict_new(); |
| 144 | 144 | ||
| 145 | keypair = xs_dict_append(keypair, "secret", sptr->data); | 145 | xs *secret = xs_str_new_sz(sptr->data, sptr->length); |
| 146 | keypair = xs_dict_append(keypair, "public", pptr->data); | 146 | xs *public = xs_str_new_sz(pptr->data, pptr->length); |
| 147 | keypair = xs_dict_append(keypair, "secret", secret); | ||
| 148 | keypair = xs_dict_append(keypair, "public", public); | ||
| 147 | 149 | ||
| 148 | BIO_free(bs); | 150 | BIO_free(bs); |
| 149 | BIO_free(bp); | 151 | BIO_free(bp); |
| 150 | 152 | ||
| 151 | end: | 153 | EVP_PKEY_free(pkey); |
| 154 | EVP_PKEY_CTX_free(ctx); | ||
| 155 | |||
| 152 | return keypair; | 156 | return keypair; |
| 153 | } | 157 | } |
| 154 | 158 | ||