summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar grunfink2025-06-24 14:06:41 +0200
committerGravatar grunfink2025-06-24 14:06:41 +0200
commitf88bdd796045dd206b38e07adb13b5af4489b4c5 (patch)
treec7796a9d7a2ff7b7cfa40e3b9df3f09f999f57fa
parentSome JSON code tweaks. (diff)
downloadsnac2-f88bdd796045dd206b38e07adb13b5af4489b4c5.tar.gz
snac2-f88bdd796045dd206b38e07adb13b5af4489b4c5.tar.xz
snac2-f88bdd796045dd206b38e07adb13b5af4489b4c5.zip
Added a webmention hook.
-rw-r--r--html.c20
-rw-r--r--httpd.c62
-rw-r--r--xs_webmention.h42
3 files changed, 119 insertions, 5 deletions
diff --git a/html.c b/html.c
index c472e3b..672ea44 100644
--- a/html.c
+++ b/html.c
@@ -868,6 +868,14 @@ xs_html *html_user_head(snac *user, const char *desc, const char *url)
868 xs_html_attr("type", "application/activity+json"), 868 xs_html_attr("type", "application/activity+json"),
869 xs_html_attr("href", url ? url : user->actor))); 869 xs_html_attr("href", url ? url : user->actor)));
870 870
871 /* webmention hook */
872 xs *wbh = xs_fmt("%s/webmention-hook", srv_baseurl);
873
874 xs_html_add(head,
875 xs_html_sctag("link",
876 xs_html_attr("rel", "webmention"),
877 xs_html_attr("href", wbh)));
878
871 return head; 879 return head;
872} 880}
873 881
@@ -3407,13 +3415,15 @@ xs_str *html_notifications(snac *user, int skip, int show)
3407 3415
3408 const char *actor_id = xs_dict_get(noti, "actor"); 3416 const char *actor_id = xs_dict_get(noti, "actor");
3409 xs *actor = NULL; 3417 xs *actor = NULL;
3418 xs *a_name = NULL;
3410 3419
3411 if (!valid_status(actor_get(actor_id, &actor))) 3420 if (valid_status(actor_get(actor_id, &actor)))
3412 continue; 3421 a_name = actor_name(actor, proxy);
3422 else
3423 a_name = xs_dup(actor_id);
3413 3424
3414 xs *a_name = actor_name(actor, proxy); 3425 xs *label_sanitized = sanitize(type);
3415 xs *label_sanatized = sanitize(type); 3426 const char *label = label_sanitized;
3416 const char *label = label_sanatized;
3417 3427
3418 if (strcmp(type, "Create") == 0) 3428 if (strcmp(type, "Create") == 0)
3419 label = L("Mention"); 3429 label = L("Mention");
diff --git a/httpd.c b/httpd.c
index 15634d1..af78e09 100644
--- a/httpd.c
+++ b/httpd.c
@@ -12,6 +12,7 @@
12#include "xs_openssl.h" 12#include "xs_openssl.h"
13#include "xs_fcgi.h" 13#include "xs_fcgi.h"
14#include "xs_html.h" 14#include "xs_html.h"
15#include "xs_webmention.h"
15 16
16#include "snac.h" 17#include "snac.h"
17 18
@@ -373,6 +374,63 @@ int server_get_handler(xs_dict *req, const char *q_path,
373} 374}
374 375
375 376
377int server_post_handler(const xs_dict *req, const char *q_path,
378 char *payload, int p_size,
379 char **body, int *b_size, char **ctype)
380{
381 int status = 0;
382
383 if (strcmp(q_path, "/webmention-hook") == 0) {
384 status = HTTP_STATUS_BAD_REQUEST;
385
386 const xs_dict *p_vars = xs_dict_get(req, "p_vars");
387
388 if (!xs_is_dict(p_vars))
389 return status;
390
391 const char *source = xs_dict_get(p_vars, "source");
392 const char *target = xs_dict_get(p_vars, "target");
393
394 if (!xs_is_string(source) || !xs_is_string(target)) {
395 srv_debug(1, xs_fmt("webmention-hook bad source or target"));
396 return status;
397 }
398
399 if (!xs_startswith(target, srv_baseurl)) {
400 srv_debug(1, xs_fmt("webmention-hook unknown target %s", target));
401 return status;
402 }
403
404 if (!object_here(target)) {
405 srv_debug(0, xs_fmt("webmention-hook target %s not / no longer here", target));
406 return status;
407 }
408
409 /* get the user */
410 xs *s1 = xs_replace(target, srv_baseurl, "");
411
412 xs *l1 = xs_split(s1, "/");
413 const char *uid = xs_list_get(l1, 1);
414 snac user;
415
416 if (!xs_is_string(uid) || !user_open(&user, uid))
417 return status;
418
419 int r = xs_webmention_hook(source, target, USER_AGENT);
420
421 if (r > 0)
422 notify_add(&user, "Webmention", NULL, source, target, xs_stock(XSTYPE_DICT));
423
424 srv_log(xs_fmt("webmention-hook source=%s target=%s %d", source, target, r));
425
426 user_free(&user);
427 status = HTTP_STATUS_OK;
428 }
429
430 return status;
431}
432
433
376void httpd_connection(FILE *f) 434void httpd_connection(FILE *f)
377/* the connection processor */ 435/* the connection processor */
378{ 436{
@@ -444,6 +502,10 @@ void httpd_connection(FILE *f)
444 else 502 else
445 if (strcmp(method, "POST") == 0) { 503 if (strcmp(method, "POST") == 0) {
446 504
505 if (status == 0)
506 status = server_post_handler(req, q_path,
507 payload, p_size, &body, &b_size, &ctype);
508
447#ifndef NO_MASTODON_API 509#ifndef NO_MASTODON_API
448 if (status == 0) 510 if (status == 0)
449 status = oauth_post_handler(req, q_path, 511 status = oauth_post_handler(req, q_path,
diff --git a/xs_webmention.h b/xs_webmention.h
index 8415629..e177573 100644
--- a/xs_webmention.h
+++ b/xs_webmention.h
@@ -5,6 +5,7 @@
5#define _XS_WEBMENTION_H 5#define _XS_WEBMENTION_H
6 6
7int xs_webmention_send(const char *source, const char *target, const char *user_agent); 7int xs_webmention_send(const char *source, const char *target, const char *user_agent);
8int xs_webmention_hook(const char *source, const char *target, const char *user_agent);
8 9
9 10
10#ifdef XS_IMPLEMENTATION 11#ifdef XS_IMPLEMENTATION
@@ -118,6 +119,47 @@ int xs_webmention_send(const char *source, const char *target, const char *user_
118} 119}
119 120
120 121
122int xs_webmention_hook(const char *source, const char *target, const char *user_agent)
123/* a Webmention has been received for a target that is ours; check if the source
124 really contains a link to our target */
125{
126 int status = 0;
127
128 xs *ua = xs_fmt("%s (Webmention)", user_agent ? user_agent : "xs_webmention");
129 xs *headers = xs_dict_new();
130 headers = xs_dict_set(headers, "accept", "text/html");
131 headers = xs_dict_set(headers, "user-agent", ua);
132
133 xs *g_req = NULL;
134 xs *payload = NULL;
135 int p_size = 0;
136
137 g_req = xs_http_request("GET", source, headers, NULL, 0, &status, &payload, &p_size, 0);
138
139 if (status < 200 || status > 299)
140 return -1;
141
142 if (!xs_is_string(payload))
143 return -2;
144
145 /* note: a "rogue" webmention can include a link to our target in commented-out HTML code */
146
147 xs *links = xs_regex_select(payload, "<(a +|link +)[^>]+>");
148 const char *link;
149
150 status = 0;
151 xs_list_foreach(links, link) {
152 /* if the link contains our target, it's valid */
153 if (xs_str_in(link, target) != -1) {
154 status = 1;
155 break;
156 }
157 }
158
159 return status;
160}
161
162
121#endif /* XS_IMPLEMENTATION */ 163#endif /* XS_IMPLEMENTATION */
122 164
123#endif /* _XS_WEBMENTION_H */ 165#endif /* _XS_WEBMENTION_H */