From 4e3d596bee1cee2c4146265eb6ac827f09820c53 Mon Sep 17 00:00:00 2001 From: shtrophic Date: Mon, 20 Jan 2025 19:43:42 +0100 Subject: add xs_smtp_request --- activitypub.c | 48 +++++++++++++++++++----------------------------- 1 file changed, 19 insertions(+), 29 deletions(-) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index 8b44dc8..ca5cc3e 100644 --- a/activitypub.c +++ b/activitypub.c @@ -962,17 +962,20 @@ void notify(snac *snac, const char *type, const char *utype, const char *actor, xs *subject = xs_fmt("snac notify for @%s@%s", xs_dict_get(snac->config, "uid"), xs_dict_get(srv_config, "host")); - xs *from = xs_fmt("snac-daemon ", xs_dict_get(srv_config, "host")); + xs *from = xs_fmt("", xs_dict_get(srv_config, "host")); xs *header = xs_fmt( - "From: %s\n" + "From: snac-daemon %s\n" "To: %s\n" "Subject: %s\n" "\n", from, email, subject); - xs *email_body = xs_fmt("%s%s", header, body); + xs_dict *mailinfo = xs_dict_new(); + xs_dict_append(mailinfo, "from", from); + xs_dict_append(mailinfo, "to", email); + xs_dict_append(mailinfo, "body", xs_fmt("%s%s", header, body)); - enqueue_email(email_body, 0); + enqueue_email(mailinfo, 0); } /* telegram */ @@ -2461,32 +2464,19 @@ int process_input_message(snac *snac, const xs_dict *msg, const xs_dict *req) } -int send_email(const char *msg) +int send_email(const xs_dict *mailinfo) /* invoke sendmail with email headers and body in msg */ { - FILE *f; - int status; - int fds[2]; - pid_t pid; - if (pipe(fds) == -1) return -1; - pid = vfork(); - if (pid == -1) return -1; - else if (pid == 0) { - dup2(fds[0], 0); - close(fds[0]); - close(fds[1]); - execl("/usr/sbin/sendmail", "sendmail", "-t", (char *) NULL); - _exit(1); - } - close(fds[0]); - if ((f = fdopen(fds[1], "w")) == NULL) { - close(fds[1]); - return -1; - } - fprintf(f, "%s\n", msg); - fclose(f); - if (waitpid(pid, &status, 0) == -1) return -1; - return status; + const xs_dict *smtp_cfg = xs_dict_get(srv_config, "smtp"); + const char + *url = xs_dict_get(smtp_cfg, "url"), + *user = xs_dict_get(smtp_cfg, "username"), + *pass = xs_dict_get(smtp_cfg, "password"), + *from = xs_dict_get(mailinfo, "from"), + *to = xs_dict_get(mailinfo, "to"), + *body = xs_dict_get(mailinfo, "body"); + + return xs_smtp_request(url, user, pass, from, to, body); } @@ -2749,7 +2739,7 @@ void process_queue_item(xs_dict *q_item) else if (strcmp(type, "email") == 0) { /* send this email */ - const xs_str *msg = xs_dict_get(q_item, "message"); + const xs_dict *msg = xs_dict_get(q_item, "message"); int retries = xs_number_get(xs_dict_get(q_item, "retries")); if (!send_email(msg)) -- cgit From 4c1a2d24d374d00c656c4489db7d28f80d64f9dc Mon Sep 17 00:00:00 2001 From: shtrophic Date: Mon, 20 Jan 2025 22:59:30 +0100 Subject: add port parsing for sandboxing --- activitypub.c | 4 ++-- sandbox.c | 31 +++++++++++++++---------------- snac.h | 1 + utils.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 70 insertions(+), 18 deletions(-) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index ca5cc3e..e5fc715 100644 --- a/activitypub.c +++ b/activitypub.c @@ -2465,9 +2465,9 @@ int process_input_message(snac *snac, const xs_dict *msg, const xs_dict *req) int send_email(const xs_dict *mailinfo) -/* invoke sendmail with email headers and body in msg */ +/* invoke curl */ { - const xs_dict *smtp_cfg = xs_dict_get(srv_config, "smtp"); + const xs_dict *smtp_cfg = xs_dict_get(srv_config, "email_notifications"); const char *url = xs_dict_get(smtp_cfg, "url"), *user = xs_dict_get(smtp_cfg, "username"), diff --git a/sandbox.c b/sandbox.c index cbe0043..875ae4e 100644 --- a/sandbox.c +++ b/sandbox.c @@ -8,8 +8,6 @@ void sbox_enter(const char *basedir) { const char *address = xs_dict_get(srv_config, "address"); - int smail = !xs_is_true(xs_dict_get(srv_config, "disable_email_notifications")); - if (xs_is_true(xs_dict_get(srv_config, "disable_openbsd_security"))) { srv_log(xs_dup("OpenBSD security disabled by admin")); return; @@ -24,9 +22,6 @@ void sbox_enter(const char *basedir) unveil("/etc/ssl/cert.pem", "r"); unveil("/usr/share/zoneinfo", "r"); - if (smail) - unveil("/usr/sbin/sendmail", "x"); - if (*address == '/') unveil(address, "rwc"); @@ -36,9 +31,6 @@ void sbox_enter(const char *basedir) xs *p = xs_str_new("stdio rpath wpath cpath flock inet proc dns fattr"); - if (smail) - p = xs_str_cat(p, " exec"); - if (*address == '/') p = xs_str_cat(p, " unix"); @@ -55,7 +47,7 @@ void sbox_enter(const char *basedir) #include "landloc.h" static -LL_BEGIN(sbox_enter_linux_, const char* basedir, const char *address, int smail) { +LL_BEGIN(sbox_enter_linux_, const char* basedir, const char *address, int smtp_port) { const unsigned long long rd = LANDLOCK_ACCESS_FS_READ_DIR, @@ -94,9 +86,6 @@ LL_BEGIN(sbox_enter_linux_, const char* basedir, const char *address, int smail) LL_PATH(sdir, s); } - if (smail && mtime("/usr/sbin/sendmail") > 0) - LL_PATH("/usr/sbin/sendmail", x); - if (*address != '/') { unsigned short listen_port = xs_number_get(xs_dict_get(srv_config, "port")); LL_PORT(listen_port, LANDLOCK_ACCESS_NET_BIND_TCP_COMPAT); @@ -104,24 +93,34 @@ LL_BEGIN(sbox_enter_linux_, const char* basedir, const char *address, int smail) LL_PORT(80, LANDLOCK_ACCESS_NET_CONNECT_TCP_COMPAT); LL_PORT(443, LANDLOCK_ACCESS_NET_CONNECT_TCP_COMPAT); + if (smtp_port > 0) + LL_PORT((unsigned short)smtp_port, LANDLOCK_ACCESS_NET_CONNECT_TCP_COMPAT); } LL_END void sbox_enter(const char *basedir) { + const xs_val *v; + const char *errstr; const char *address = xs_dict_get(srv_config, "address"); - - int smail = !xs_is_true(xs_dict_get(srv_config, "disable_email_notifications")); + int smtp_port = -1; if (xs_is_true(xs_dict_get(srv_config, "disable_sandbox"))) { srv_debug(1, xs_dup("Linux sandbox disabled by admin")); return; } - if (sbox_enter_linux_(basedir, address, smail) == 0) + if ((v = xs_dict_get(srv_config, "email_notifications")) && + (v = xs_dict_get(v, "url"))) { + smtp_port = parse_port((const char *)v, &errstr); + if (errstr) + srv_debug(0, xs_fmt("Couldn't determine port from '%s': %s", (const char *)v, errstr)); + } + + if (sbox_enter_linux_(basedir, address, smtp_port) == 0) srv_debug(1, xs_dup("Linux sandbox enabled")); else - srv_debug(1, xs_dup("Linux sandbox failed")); + srv_debug(0, xs_dup("Linux sandbox failed")); } #else /* defined(WITH_LINUX_SANDBOX) */ diff --git a/snac.h b/snac.h index 65ece5d..3db7b63 100644 --- a/snac.h +++ b/snac.h @@ -417,6 +417,7 @@ void import_blocked_accounts_csv(snac *user, const char *fn); void import_following_accounts_csv(snac *user, const char *fn); void import_list_csv(snac *user, const char *fn); void import_csv(snac *user); +int parse_port(const char *url, const char **errstr); typedef enum { #define HTTP_STATUS(code, name, text) HTTP_STATUS_ ## name = code, diff --git a/utils.c b/utils.c index a5b1124..3b0a78f 100644 --- a/utils.c +++ b/utils.c @@ -904,3 +904,55 @@ void import_csv(snac *user) else snac_log(user, xs_fmt("Cannot open file %s", fn)); } + +static const struct { + const char *proto; + unsigned short default_port; +} FALLBACK_PORTS[] = { + /* caution: https > http, smpts > smtp */ + {"https", 443}, + {"http", 80}, + {"smtps", 465}, + {"smtp", 25} +}; + +int parse_port(const char *url, const char **errstr) +{ + const char *col, *rcol; + int tmp, ret = -1; + + if (errstr) + *errstr = NULL; + + if (!(col = strchr(url, ':'))) { + if (errstr) + *errstr = "bad url"; + return -1; + } + + for (size_t i = 0; i < sizeof(FALLBACK_PORTS) / sizeof(*FALLBACK_PORTS); ++i) { + if (memcmp(url, FALLBACK_PORTS[i].proto, strlen(FALLBACK_PORTS[i].proto)) == 0) { + ret = FALLBACK_PORTS[i].default_port; + break; + } + } + + if (!(rcol = strchr(col + 1, ':'))) + rcol = col; + + if (rcol) { + tmp = atoi(rcol + 1); + if (tmp == 0) { + if (ret != -1) + return ret; + + *errstr = strerror(errno); + return -1; + } + + return tmp; + } + + *errstr = "unknown protocol"; + return -1; +} -- cgit From 13e4a7cda59db29063efc5dad0823fe99ec7b764 Mon Sep 17 00:00:00 2001 From: shtrophic Date: Mon, 20 Jan 2025 23:03:27 +0100 Subject: fix memory leak --- activitypub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index e5fc715..2b10435 100644 --- a/activitypub.c +++ b/activitypub.c @@ -970,7 +970,7 @@ void notify(snac *snac, const char *type, const char *utype, const char *actor, "\n", from, email, subject); - xs_dict *mailinfo = xs_dict_new(); + xs *mailinfo = xs_dict_new(); xs_dict_append(mailinfo, "from", from); xs_dict_append(mailinfo, "to", email); xs_dict_append(mailinfo, "body", xs_fmt("%s%s", header, body)); -- cgit From 3d96c576287736ebdf87e4a7b956842a6c6e055f Mon Sep 17 00:00:00 2001 From: shtrophic Date: Fri, 24 Jan 2025 22:24:05 +0100 Subject: enforce tls when supported && add tests --- .gitignore | 3 ++- activitypub.c | 3 ++- tests/smtp.c | 24 ++++++++++++++++++++++++ utils.c | 9 +++++++-- xs_curl.h | 22 ++++++++++++++++------ 5 files changed, 51 insertions(+), 10 deletions(-) create mode 100644 tests/smtp.c (limited to 'activitypub.c') diff --git a/.gitignore b/.gitignore index 7ead966..6ebb150 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ -*.o +**/*.o +tests/smtp snac diff --git a/activitypub.c b/activitypub.c index 4cb779a..f3b2bae 100644 --- a/activitypub.c +++ b/activitypub.c @@ -2538,8 +2538,9 @@ int send_email(const xs_dict *mailinfo) *from = xs_dict_get(mailinfo, "from"), *to = xs_dict_get(mailinfo, "to"), *body = xs_dict_get(mailinfo, "body"); + int smtp_port = parse_port(url, NULL); - return xs_smtp_request(url, user, pass, from, to, body); + return xs_smtp_request(url, user, pass, from, to, body, smtp_port == 465 || smtp_port == 587); } diff --git a/tests/smtp.c b/tests/smtp.c new file mode 100644 index 0000000..1100a9d --- /dev/null +++ b/tests/smtp.c @@ -0,0 +1,24 @@ +/* snac - A simple, minimalistic ActivityPub instance */ +/* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ + +#define XS_IMPLEMENTATION +#include "../xs.h" +#include "../xs_curl.h" + +#define FROM "" + +int main(void) { + xs *to = xs_fmt("<%s@localhost>", getenv("USER")), + *body = xs_fmt("" + "To: %s \r\n" + "From: " FROM "\r\n" + "Subject: snac smtp test\r\n" + "\r\n" + "If you read this as an email, it probably worked!\r\n", + to); + + return xs_smtp_request("smtp://localhost", NULL, NULL, + FROM, + to, + body, 0); +} \ No newline at end of file diff --git a/utils.c b/utils.c index faf6d12..dbf798a 100644 --- a/utils.c +++ b/utils.c @@ -931,6 +931,7 @@ int parse_port(const char *url, const char **errstr) if (!(col = strchr(url, ':'))) { if (errstr) *errstr = "bad url"; + return -1; } @@ -950,13 +951,17 @@ int parse_port(const char *url, const char **errstr) if (ret != -1) return ret; - *errstr = strerror(errno); + if (errstr) + *errstr = strerror(errno); + return -1; } return tmp; } - *errstr = "unknown protocol"; + if (errstr) + *errstr = "unknown protocol"; + return -1; } diff --git a/xs_curl.h b/xs_curl.h index 886aee0..d98ac4c 100644 --- a/xs_curl.h +++ b/xs_curl.h @@ -10,7 +10,8 @@ xs_dict *xs_http_request(const char *method, const char *url, xs_str **payload, int *p_size, int timeout); int xs_smtp_request(const char *url, const char *user, const char *pass, - const char *from, const char *to, const xs_str *body); + const char *from, const char *to, const xs_str *body, + int use_ssl); #ifdef XS_IMPLEMENTATION @@ -198,7 +199,8 @@ xs_dict *xs_http_request(const char *method, const char *url, } int xs_smtp_request(const char *url, const char *user, const char *pass, - const char *from, const char *to, const xs_str *body) + const char *from, const char *to, const xs_str *body, + int use_ssl) { CURL *curl; CURLcode res = CURLE_OK; @@ -212,11 +214,19 @@ int xs_smtp_request(const char *url, const char *user, const char *pass, curl = curl_easy_init(); curl_easy_setopt(curl, CURLOPT_URL, url); - curl_easy_setopt(curl, CURLOPT_USERNAME, user); - curl_easy_setopt(curl, CURLOPT_PASSWORD, pass); + if (user && pass) { + /* allow authless connections, to, e.g. localhost */ + curl_easy_setopt(curl, CURLOPT_USERNAME, user); + curl_easy_setopt(curl, CURLOPT_PASSWORD, pass); + } + + if (use_ssl) + curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL); curl_easy_setopt(curl, CURLOPT_MAIL_FROM, from); - curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, rcpt = curl_slist_append(rcpt, to)); + + rcpt = curl_slist_append(rcpt, to); + curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, rcpt); curl_easy_setopt(curl, CURLOPT_READDATA, &pd); curl_easy_setopt(curl, CURLOPT_READFUNCTION, _post_callback); @@ -224,8 +234,8 @@ int xs_smtp_request(const char *url, const char *user, const char *pass, res = curl_easy_perform(curl); - curl_slist_free_all(rcpt); curl_easy_cleanup(curl); + curl_slist_free_all(rcpt); return (int)res; } -- cgit From 2ca7735779e79dbe6fe62f0111a12c145f428d8f Mon Sep 17 00:00:00 2001 From: shtrophic Date: Wed, 19 Feb 2025 08:56:14 +0100 Subject: fix ownership-problem of mailinfo --- activitypub.c | 2 +- data.c | 5 +++-- snac.h | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index e2519e6..a91821d 100644 --- a/activitypub.c +++ b/activitypub.c @@ -1025,7 +1025,7 @@ void notify(snac *snac, const char *type, const char *utype, const char *actor, "\n", from, email, subject); - xs *mailinfo = xs_dict_new(); + xs_dict *mailinfo = xs_dict_new(); xs_dict_append(mailinfo, "from", from); xs_dict_append(mailinfo, "to", email); xs_dict_append(mailinfo, "body", xs_fmt("%s%s", header, body)); diff --git a/data.c b/data.c index ae85aaf..d25a5d7 100644 --- a/data.c +++ b/data.c @@ -3174,7 +3174,7 @@ static xs_dict *_enqueue_put(const char *fn, xs_dict *msg) } -static xs_dict *_new_qmsg(const char *type, const xs_val *msg, int retries) +static xs_dict *_new_qmsg(const char *type, xs_dict *msg, int retries) /* creates a queue message */ { int qrt = xs_number_get(xs_dict_get(srv_config, "queue_retry_minutes")); @@ -3276,9 +3276,10 @@ void enqueue_output_by_actor(snac *snac, const xs_dict *msg, } -void enqueue_email(const xs_dict *msg, int retries) +void enqueue_email(xs_dict *msg, int retries) /* enqueues an email message to be sent */ { + /* qmsg owns msg */ xs *qmsg = _new_qmsg("email", msg, retries); const char *ntid = xs_dict_get(qmsg, "ntid"); xs *fn = xs_fmt("%s/queue/%s.json", srv_basedir, ntid); diff --git a/snac.h b/snac.h index 92ffb3f..545df74 100644 --- a/snac.h +++ b/snac.h @@ -274,7 +274,7 @@ void enqueue_output(snac *snac, const xs_dict *msg, const xs_str *inbox, int retries, int p_status); void enqueue_output_by_actor(snac *snac, const xs_dict *msg, const xs_str *actor, int retries); -void enqueue_email(const xs_str *msg, int retries); +void enqueue_email(xs_dict *msg, int retries); void enqueue_telegram(const xs_str *msg, const char *bot, const char *chat_id); void enqueue_ntfy(const xs_str *msg, const char *ntfy_server, const char *ntfy_token); void enqueue_message(snac *snac, const xs_dict *msg); -- cgit From 59a34a9646e28cc9a63194ff55547de0005d0110 Mon Sep 17 00:00:00 2001 From: shtrophic Date: Thu, 20 Feb 2025 17:13:12 +0100 Subject: Revert "fix ownership-problem of mailinfo" This reverts commit 2ca7735779e79dbe6fe62f0111a12c145f428d8f. --- activitypub.c | 2 +- data.c | 5 ++--- snac.h | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index a91821d..e2519e6 100644 --- a/activitypub.c +++ b/activitypub.c @@ -1025,7 +1025,7 @@ void notify(snac *snac, const char *type, const char *utype, const char *actor, "\n", from, email, subject); - xs_dict *mailinfo = xs_dict_new(); + xs *mailinfo = xs_dict_new(); xs_dict_append(mailinfo, "from", from); xs_dict_append(mailinfo, "to", email); xs_dict_append(mailinfo, "body", xs_fmt("%s%s", header, body)); diff --git a/data.c b/data.c index d25a5d7..ae85aaf 100644 --- a/data.c +++ b/data.c @@ -3174,7 +3174,7 @@ static xs_dict *_enqueue_put(const char *fn, xs_dict *msg) } -static xs_dict *_new_qmsg(const char *type, xs_dict *msg, int retries) +static xs_dict *_new_qmsg(const char *type, const xs_val *msg, int retries) /* creates a queue message */ { int qrt = xs_number_get(xs_dict_get(srv_config, "queue_retry_minutes")); @@ -3276,10 +3276,9 @@ void enqueue_output_by_actor(snac *snac, const xs_dict *msg, } -void enqueue_email(xs_dict *msg, int retries) +void enqueue_email(const xs_dict *msg, int retries) /* enqueues an email message to be sent */ { - /* qmsg owns msg */ xs *qmsg = _new_qmsg("email", msg, retries); const char *ntid = xs_dict_get(qmsg, "ntid"); xs *fn = xs_fmt("%s/queue/%s.json", srv_basedir, ntid); diff --git a/snac.h b/snac.h index 545df74..92ffb3f 100644 --- a/snac.h +++ b/snac.h @@ -274,7 +274,7 @@ void enqueue_output(snac *snac, const xs_dict *msg, const xs_str *inbox, int retries, int p_status); void enqueue_output_by_actor(snac *snac, const xs_dict *msg, const xs_str *actor, int retries); -void enqueue_email(xs_dict *msg, int retries); +void enqueue_email(const xs_str *msg, int retries); void enqueue_telegram(const xs_str *msg, const char *bot, const char *chat_id); void enqueue_ntfy(const xs_str *msg, const char *ntfy_server, const char *ntfy_token); void enqueue_message(snac *snac, const xs_dict *msg); -- cgit From d19fe4157ced8789e43b7c061b11fcc7baf91c78 Mon Sep 17 00:00:00 2001 From: shtrophic Date: Thu, 20 Feb 2025 18:15:48 +0100 Subject: use xs_dict_append correctly --- activitypub.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index e2519e6..a209abd 100644 --- a/activitypub.c +++ b/activitypub.c @@ -1026,9 +1026,9 @@ void notify(snac *snac, const char *type, const char *utype, const char *actor, from, email, subject); xs *mailinfo = xs_dict_new(); - xs_dict_append(mailinfo, "from", from); - xs_dict_append(mailinfo, "to", email); - xs_dict_append(mailinfo, "body", xs_fmt("%s%s", header, body)); + mailinfo = xs_dict_append(mailinfo, "from", from); + mailinfo = xs_dict_append(mailinfo, "to", email); + mailinfo = xs_dict_append(mailinfo, "body", xs_fmt("%s%s", header, body)); enqueue_email(mailinfo, 0); } -- cgit From 9b2d0381ba734102c20d2111f0a2b64a3c438ef7 Mon Sep 17 00:00:00 2001 From: default Date: Tue, 1 Apr 2025 06:32:53 +0200 Subject: More scheduled post code. --- activitypub.c | 2 ++ data.c | 29 ++++++++++++++++++++++++++++- snac.h | 3 ++- 3 files changed, 32 insertions(+), 2 deletions(-) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index c00c371..4c22c25 100644 --- a/activitypub.c +++ b/activitypub.c @@ -2759,6 +2759,8 @@ int process_user_queue(snac *snac) cnt++; } + scheduled_process(snac); + return cnt; } diff --git a/data.c b/data.c index 8f68ee2..6661472 100644 --- a/data.c +++ b/data.c @@ -1966,6 +1966,33 @@ xs_list *scheduled_list(snac *user) } +void scheduled_process(snac *user) +/* processes the scheduled list, sending those ready to be sent */ +{ + xs *posts = scheduled_list(user); + const char *md5; + xs *right_now = xs_str_utctime(0, ISO_DATE_SPEC); + + xs_list_foreach(posts, md5) { + xs *msg = NULL; + + if (valid_status(object_get_by_md5(md5, &msg))) { + if (strcmp(xs_dict_get(msg, "published"), right_now) < 0) { + /* due date! */ + const char *id = xs_dict_get(msg, "id"); + + timeline_add(user, id, msg); + + xs *c_msg = msg_create(user, msg); + enqueue_message(user, c_msg); + + schedule_del(user, id); + } + } + } +} + + /** hiding **/ xs_str *_hidden_fn(snac *snac, const char *id) @@ -3734,7 +3761,7 @@ void purge_user(snac *snac) _purge_user_subdir(snac, "public", pub_days); const char *idxs[] = { "followers.idx", "private.idx", "public.idx", - "pinned.idx", "bookmark.idx", "draft.idx", NULL }; + "pinned.idx", "bookmark.idx", "draft.idx", "sched.idx", NULL }; for (n = 0; idxs[n]; n++) { xs *idx = xs_fmt("%s/%s", snac->basedir, idxs[n]); diff --git a/snac.h b/snac.h index 7e44039..0d2aafe 100644 --- a/snac.h +++ b/snac.h @@ -1,7 +1,7 @@ /* snac - A simple, minimalistic ActivityPub instance */ /* copyright (c) 2022 - 2025 grunfink et al. / MIT license */ -#define VERSION "2.74" +#define VERSION "2.75-dev" #define USER_AGENT "snac/" VERSION @@ -209,6 +209,7 @@ int is_scheduled(snac *user, const char *id); void schedule_del(snac *user, const char *id); void schedule_add(snac *user, const char *id, const xs_dict *msg); xs_list *scheduled_list(snac *user); +void scheduled_process(snac *user); int limited(snac *user, const char *id, int cmd); #define is_limited(user, id) limited((user), (id), 0) -- cgit From d19806a72db3585048c57f8940a74ec04f16e125 Mon Sep 17 00:00:00 2001 From: green Date: Mon, 24 Mar 2025 02:27:10 +0100 Subject: maybe a fix for username emojis --- activitypub.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index 4c22c25..ee7c9b1 100644 --- a/activitypub.c +++ b/activitypub.c @@ -1327,6 +1327,11 @@ xs_dict *msg_actor(snac *snac) msg = xs_dict_set(msg, "preferredUsername", snac->uid); msg = xs_dict_set(msg, "published", xs_dict_get(snac->config, "published")); + // this exists so we get the emoji tags from our name too. + // and then we just throw away the result, because it's kinda useless to have markdown in the dysplay name. + // right now, only emojies in bio actually work for local users + xs *name_dummy = not_really_markdown(xs_dict_get(snac->config, "name"), NULL, &tags); + xs *f_bio_2 = not_really_markdown(xs_dict_get(snac->config, "bio"), NULL, &tags); f_bio = process_tags(snac, f_bio_2, &tags); msg = xs_dict_set(msg, "summary", f_bio); -- cgit From 0c03e6c9d9a6b65fede94cc9eab34a05746f8d5e Mon Sep 17 00:00:00 2001 From: green Date: Sun, 13 Apr 2025 15:44:24 +0200 Subject: cleaned up old changes and outdated comments --- activitypub.c | 5 ++--- format.c | 1 - html.c | 4 ---- 3 files changed, 2 insertions(+), 8 deletions(-) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index ee7c9b1..2403a62 100644 --- a/activitypub.c +++ b/activitypub.c @@ -34,7 +34,7 @@ const char *susie_cool = "+ZcgN7wF7ZVihXkfSlWIVzIA6dbQzaygllpNuTX" "ZmmFNlvxADX1+o0cUPMbAAAAAElFTkSuQmCC"; -const char *susie_muertos = +const char *susie_muertos = "iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQAAAAC" "CEkxzAAAAV0lEQVQoz4XQsQ0AMQxCUW/A/lv+DT" "ic6zGRolekIMyMELNp8PiCEw6Q4w4NoAt53IH5m" @@ -1328,8 +1328,7 @@ xs_dict *msg_actor(snac *snac) msg = xs_dict_set(msg, "published", xs_dict_get(snac->config, "published")); // this exists so we get the emoji tags from our name too. - // and then we just throw away the result, because it's kinda useless to have markdown in the dysplay name. - // right now, only emojies in bio actually work for local users + // and then we just throw away the result, because it's kinda useless to have markdown in the display name. xs *name_dummy = not_really_markdown(xs_dict_get(snac->config, "name"), NULL, &tags); xs *f_bio_2 = not_really_markdown(xs_dict_get(snac->config, "bio"), NULL, &tags); diff --git a/format.c b/format.c index 1bb2cf1..3089955 100644 --- a/format.c +++ b/format.c @@ -10,7 +10,6 @@ #include "xs_match.h" #include "snac.h" -#include /* emoticons, people laughing and such */ const char *smileys[] = { diff --git a/html.c b/html.c index 1cd9dd9..b9f2419 100644 --- a/html.c +++ b/html.c @@ -3136,10 +3136,6 @@ xs_html *html_people_list(snac *user, xs_list *list, const char *header, const c if (!xs_is_null(c)) { xs *sc = sanitize(c); - - // replace shortnames in bio - // bug: this somehow fires twice on one specific user - // @ielenia@ck.catwithaclari.net sc = replace_shortnames(sc, xs_dict_get(actor, "tag"), 2, proxy); xs_html *snac_content = xs_html_tag("div", -- cgit From 7f936d2d1a88840209895c6091801e8c4cfdaaa1 Mon Sep 17 00:00:00 2001 From: shtrophic Date: Thu, 24 Apr 2025 12:18:23 +0200 Subject: default to `smtp://localhost` --- activitypub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index 061d1f8..df68151 100644 --- a/activitypub.c +++ b/activitypub.c @@ -2571,7 +2571,7 @@ int send_email(const xs_dict *mailinfo) { const xs_dict *smtp_cfg = xs_dict_get(srv_config, "email_notifications"); const char - *url = xs_dict_get(smtp_cfg, "url"), + *url = xs_dict_get_def(smtp_cfg, "url", "smtp://localhost"), *user = xs_dict_get(smtp_cfg, "username"), *pass = xs_dict_get(smtp_cfg, "password"), *from = xs_dict_get(mailinfo, "from"), -- cgit From 3dec7404bf59397452f3cc32fdf33b379f2546fc Mon Sep 17 00:00:00 2001 From: grunfink Date: Sun, 27 Apr 2025 05:15:32 +0200 Subject: Fixed memory leak. --- activitypub.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index df68151..10e5776 100644 --- a/activitypub.c +++ b/activitypub.c @@ -1053,9 +1053,10 @@ void notify(snac *snac, const char *type, const char *utype, const char *actor, from, email, subject); xs *mailinfo = xs_dict_new(); + xs *body = xs_fmt("%s%s", header, body); mailinfo = xs_dict_append(mailinfo, "from", from); mailinfo = xs_dict_append(mailinfo, "to", email); - mailinfo = xs_dict_append(mailinfo, "body", xs_fmt("%s%s", header, body)); + mailinfo = xs_dict_append(mailinfo, "body", body); enqueue_email(mailinfo, 0); } -- cgit From aa15f84b34e51ae8121a8174ea68f105d295699c Mon Sep 17 00:00:00 2001 From: grunfink Date: Sun, 27 Apr 2025 05:23:39 +0200 Subject: Changed server SMTP settings. --- activitypub.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index 10e5776..fd2d81a 100644 --- a/activitypub.c +++ b/activitypub.c @@ -34,7 +34,7 @@ const char *susie_cool = "+ZcgN7wF7ZVihXkfSlWIVzIA6dbQzaygllpNuTX" "ZmmFNlvxADX1+o0cUPMbAAAAAElFTkSuQmCC"; -const char *susie_muertos = +const char *susie_muertos = "iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQAAAAC" "CEkxzAAAAV0lEQVQoz4XQsQ0AMQxCUW/A/lv+DT" "ic6zGRolekIMyMELNp8PiCEw6Q4w4NoAt53IH5m" @@ -2570,14 +2570,17 @@ int process_input_message(snac *snac, const xs_dict *msg, const xs_dict *req) int send_email(const xs_dict *mailinfo) /* invoke curl */ { - const xs_dict *smtp_cfg = xs_dict_get(srv_config, "email_notifications"); - const char - *url = xs_dict_get_def(smtp_cfg, "url", "smtp://localhost"), - *user = xs_dict_get(smtp_cfg, "username"), - *pass = xs_dict_get(smtp_cfg, "password"), + const char + *url = xs_dict_get(srv_config, "smtp_url"), + *user = xs_dict_get(srv_config, "smtp_username"), + *pass = xs_dict_get(srv_config, "smtp_password"), *from = xs_dict_get(mailinfo, "from"), *to = xs_dict_get(mailinfo, "to"), *body = xs_dict_get(mailinfo, "body"); + + if (url == NULL || *url == '\0') + url = "smtp://localhost"; + int smtp_port = parse_port(url, NULL); return xs_smtp_request(url, user, pass, from, to, body, smtp_port == 465 || smtp_port == 587); -- cgit From c27e1aa5a126d6676232e7e3cb7cff95a3661b35 Mon Sep 17 00:00:00 2001 From: grunfink Date: Sun, 27 Apr 2025 05:26:42 +0200 Subject: Fixed typo. --- activitypub.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index fd2d81a..fbf7a1f 100644 --- a/activitypub.c +++ b/activitypub.c @@ -1053,10 +1053,10 @@ void notify(snac *snac, const char *type, const char *utype, const char *actor, from, email, subject); xs *mailinfo = xs_dict_new(); - xs *body = xs_fmt("%s%s", header, body); + xs *bd = xs_fmt("%s%s", header, body); mailinfo = xs_dict_append(mailinfo, "from", from); mailinfo = xs_dict_append(mailinfo, "to", email); - mailinfo = xs_dict_append(mailinfo, "body", body); + mailinfo = xs_dict_append(mailinfo, "body", bd); enqueue_email(mailinfo, 0); } -- cgit From da0ce17f15e3bb0d3b9eb1442f036d8f549ceee8 Mon Sep 17 00:00:00 2001 From: grunfink Date: Mon, 28 Apr 2025 05:15:31 +0200 Subject: Email notifications are sent the old way if 'spawn_sendmail' is set to true. --- activitypub.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index fbf7a1f..92e408b 100644 --- a/activitypub.c +++ b/activitypub.c @@ -2570,6 +2570,34 @@ int process_input_message(snac *snac, const xs_dict *msg, const xs_dict *req) int send_email(const xs_dict *mailinfo) /* invoke curl */ { + if (xs_is_true(xs_dict_get(srv_config, "spawn_sendmail"))) { + const char *msg = xs_dict_get(mailinfo, "body"); + FILE *f; + int status; + int fds[2]; + pid_t pid; + + if (pipe(fds) == -1) return -1; + pid = vfork(); + if (pid == -1) return -1; + else if (pid == 0) { + dup2(fds[0], 0); + close(fds[0]); + close(fds[1]); + execl("/usr/sbin/sendmail", "sendmail", "-t", (char *) NULL); + _exit(1); + } + close(fds[0]); + if ((f = fdopen(fds[1], "w")) == NULL) { + close(fds[1]); + return -1; + } + fprintf(f, "%s\n", msg); + fclose(f); + if (waitpid(pid, &status, 0) == -1) return -1; + return status; + } + const char *url = xs_dict_get(srv_config, "smtp_url"), *user = xs_dict_get(srv_config, "smtp_username"), -- cgit From 8e467684c2d6960d64af9ea3de74ddb30d82302f Mon Sep 17 00:00:00 2001 From: grunfink Date: Mon, 28 Apr 2025 06:12:29 +0200 Subject: Changed email notifications: use SMTP only if configured. --- activitypub.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index 92e408b..98ed6da 100644 --- a/activitypub.c +++ b/activitypub.c @@ -2570,7 +2570,10 @@ int process_input_message(snac *snac, const xs_dict *msg, const xs_dict *req) int send_email(const xs_dict *mailinfo) /* invoke curl */ { - if (xs_is_true(xs_dict_get(srv_config, "spawn_sendmail"))) { + const char *url = xs_dict_get(srv_config, "smtp_url"); + + if (!xs_is_string(url) || *url == '\0') { + /* revert back to old sendmail pipe behaviour */ const char *msg = xs_dict_get(mailinfo, "body"); FILE *f; int status; @@ -2599,7 +2602,6 @@ int send_email(const xs_dict *mailinfo) } const char - *url = xs_dict_get(srv_config, "smtp_url"), *user = xs_dict_get(srv_config, "smtp_username"), *pass = xs_dict_get(srv_config, "smtp_password"), *from = xs_dict_get(mailinfo, "from"), -- cgit From bca51ef5ba10fc38d804d5d83f26575e02190663 Mon Sep 17 00:00:00 2001 From: grunfink Date: Sat, 3 May 2025 19:39:04 +0200 Subject: Preprocess the webmention q_item. Nothing is really done yet. --- activitypub.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index 98ed6da..5ba1f25 100644 --- a/activitypub.c +++ b/activitypub.c @@ -3025,6 +3025,19 @@ void process_queue_item(xs_dict *q_item) } } } + else + if (strcmp(type, "webmention") == 0) { + const xs_dict *msg = xs_dict_get(q_item, "message"); + const char *source = xs_dict_get(msg, "id"); + const xs_list *atts = xs_dict_get(msg, "attachment"); + const xs_dict *att; + + xs_list_foreach(atts, att) { + const char *target = xs_dict_get(att, "url"); + + srv_debug(1, xs_fmt("webmention source=%s target=%s", source, target)); + } + } else srv_log(xs_fmt("unexpected q_item type '%s'", type)); } -- cgit From 7d1b257e4616ff750638b387ae60a128ff0ed43f Mon Sep 17 00:00:00 2001 From: grunfink Date: Sun, 4 May 2025 11:09:07 +0200 Subject: Webmentions are now sent. --- activitypub.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index 5ba1f25..53a1e74 100644 --- a/activitypub.c +++ b/activitypub.c @@ -11,6 +11,7 @@ #include "xs_set.h" #include "xs_match.h" #include "xs_unicode.h" +#include "xs_webmention.h" #include "snac.h" @@ -3035,7 +3036,11 @@ void process_queue_item(xs_dict *q_item) xs_list_foreach(atts, att) { const char *target = xs_dict_get(att, "url"); - srv_debug(1, xs_fmt("webmention source=%s target=%s", source, target)); + if (xs_is_string(source) && xs_is_string(target)) { + int r = xs_webmention_send(source, target, USER_AGENT); + + srv_debug(1, xs_fmt("webmention source=%s target=%s %d", source, target, r)); + } } } else -- cgit From c166e05f7d3ba1efe9b16290bf3da2b06fdae8ea Mon Sep 17 00:00:00 2001 From: grunfink Date: Fri, 9 May 2025 15:31:58 +0200 Subject: As they look ugly in some platforms, links are no longer shown as attachments. --- activitypub.c | 12 +++++++----- format.c | 24 ------------------------ 2 files changed, 7 insertions(+), 29 deletions(-) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index dcbb79f..48a999a 100644 --- a/activitypub.c +++ b/activitypub.c @@ -3034,13 +3034,15 @@ void process_queue_item(xs_dict *q_item) if (strcmp(type, "webmention") == 0) { const xs_dict *msg = xs_dict_get(q_item, "message"); const char *source = xs_dict_get(msg, "id"); - const xs_list *atts = xs_dict_get(msg, "attachment"); - const xs_dict *att; + const char *content = xs_dict_get(msg, "content"); - xs_list_foreach(atts, att) { - const char *target = xs_dict_get(att, "url"); + if (xs_is_string(source) && xs_is_string(content)) { + xs *links = xs_regex_select(content, "\"https?[^\"]+"); + const char *link; + + xs_list_foreach(links, link) { + xs *target = xs_strip_chars_i(xs_dup(link), "\""); - if (xs_is_string(source) && xs_is_string(target)) { int r = xs_webmention_send(source, target, USER_AGENT); srv_debug(1, xs_fmt("webmention source=%s target=%s %d", source, target, r)); diff --git a/format.c b/format.c index b3764ef..2f30a0d 100644 --- a/format.c +++ b/format.c @@ -160,18 +160,6 @@ static xs_str *format_line(const char *line, xs_list **attach) xs *link = xs_fmt("%s", url, name); s = xs_str_cat(s, link); - - if (attach) { - /* also add the link as an attachment */ - xs *d = xs_dict_new(); - - d = xs_dict_append(d, "mediaType", "text/html"); - d = xs_dict_append(d, "url", url); - d = xs_dict_append(d, "name", name); - d = xs_dict_append(d, "type", "Link"); - - *attach = xs_list_append(*attach, d); - } } else s = xs_str_cat(s, v); @@ -255,18 +243,6 @@ static xs_str *format_line(const char *line, xs_list **attach) else { xs *s1 = xs_fmt("%s", v2, u); s = xs_str_cat(s, s1); - - if (attach) { - /* also add the link as an attachment */ - xs *d = xs_dict_new(); - - d = xs_dict_append(d, "mediaType", "text/html"); - d = xs_dict_append(d, "url", v2); - d = xs_dict_append(d, "name", ""); - d = xs_dict_append(d, "type", "Link"); - - *attach = xs_list_append(*attach, d); - } } } else -- cgit From 418581a71dc1a540a4a18b439aa215b143706c80 Mon Sep 17 00:00:00 2001 From: grunfink Date: Sun, 11 May 2025 18:59:28 +0200 Subject: Minor tweak to link extraction regex. --- activitypub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index 48a999a..a7e133a 100644 --- a/activitypub.c +++ b/activitypub.c @@ -3037,7 +3037,7 @@ void process_queue_item(xs_dict *q_item) const char *content = xs_dict_get(msg, "content"); if (xs_is_string(source) && xs_is_string(content)) { - xs *links = xs_regex_select(content, "\"https?[^\"]+"); + xs *links = xs_regex_select(content, "\"https?:/" "/[^\"]+"); const char *link; xs_list_foreach(links, link) { -- cgit From 321f64ed70d039dea510c8a7d7aee7dc9577737a Mon Sep 17 00:00:00 2001 From: green Date: Mon, 19 May 2025 15:25:11 +0200 Subject: performance: use following_list_len in more places --- activitypub.c | 6 ++---- data.c | 2 +- mastoapi.c | 16 ++++++++-------- 3 files changed, 11 insertions(+), 13 deletions(-) (limited to 'activitypub.c') diff --git a/activitypub.c b/activitypub.c index a7e133a..120b4a1 100644 --- a/activitypub.c +++ b/activitypub.c @@ -3204,8 +3204,7 @@ int activitypub_get_handler(const xs_dict *req, const char *q_path, int total = 0; if (show_contact_metrics) { - xs *l = follower_list(&snac); - total = xs_list_len(l); + total = follower_list_len(&snac); } xs *id = xs_fmt("%s/%s", snac.actor, p_path); @@ -3216,8 +3215,7 @@ int activitypub_get_handler(const xs_dict *req, const char *q_path, int total = 0; if (show_contact_metrics) { - xs *l = following_list(&snac); - total = xs_list_len(l); + total = following_list_len(&snac); } xs *id = xs_fmt("%s/%s", snac.actor, p_path); diff --git a/data.c b/data.c index 482a29c..f9d27f9 100644 --- a/data.c +++ b/data.c @@ -1216,7 +1216,7 @@ int follower_check(snac *snac, const char *actor) int follower_list_len(snac *snac) -/* returns the number followers */ +/* returns the number of followers */ { xs *list = object_user_cache_list(snac, "followers", XS_ALL, 0); return xs_list_len(list); diff --git a/mastoapi.c b/mastoapi.c index 7fa0078..a7d9c34 100644 --- a/mastoapi.c +++ b/mastoapi.c @@ -680,10 +680,10 @@ xs_dict *mastoapi_account(snac *logged, const xs_dict *actor) /* does this user want to publish their contact metrics? */ if (xs_is_true(xs_dict_get(user.config, "show_contact_metrics"))) { - xs *fwing = following_list(&user); - xs *fwers = follower_list(&user); - xs *ni = xs_number_new(xs_list_len(fwing)); - xs *ne = xs_number_new(xs_list_len(fwers)); + int fwing = following_list_len(&user); + int fwers = follower_list_len(&user); + xs *ni = xs_number_new(fwing); + xs *ne = xs_number_new(fwers); acct = xs_dict_append(acct, "followers_count", ne); acct = xs_dict_append(acct, "following_count", ni); @@ -1309,10 +1309,10 @@ void credentials_get(char **body, char **ctype, int *status, snac snac) /* does this user want to publish their contact metrics? */ if (xs_is_true(xs_dict_get(snac.config, "show_contact_metrics"))) { - xs *fwing = following_list(&snac); - xs *fwers = follower_list(&snac); - xs *ni = xs_number_new(xs_list_len(fwing)); - xs *ne = xs_number_new(xs_list_len(fwers)); + int fwing = following_list_len(&snac); + int fwers = follower_list_len(&snac); + xs *ni = xs_number_new(fwing); + xs *ne = xs_number_new(fwers); acct = xs_dict_append(acct, "followers_count", ne); acct = xs_dict_append(acct, "following_count", ni); -- cgit