commit f88bdd7
grunfink
·
2025-06-24 12:06:41 +0000 UTC
parent 238c5c5
Added a webmention hook.
3 files changed,
+119,
-5
M
html.c
+15,
-5
1@@ -868,6 +868,14 @@ xs_html *html_user_head(snac *user, const char *desc, const char *url)
2 xs_html_attr("type", "application/activity+json"),
3 xs_html_attr("href", url ? url : user->actor)));
4
5+ /* webmention hook */
6+ xs *wbh = xs_fmt("%s/webmention-hook", srv_baseurl);
7+
8+ xs_html_add(head,
9+ xs_html_sctag("link",
10+ xs_html_attr("rel", "webmention"),
11+ xs_html_attr("href", wbh)));
12+
13 return head;
14 }
15
16@@ -3407,13 +3415,15 @@ xs_str *html_notifications(snac *user, int skip, int show)
17
18 const char *actor_id = xs_dict_get(noti, "actor");
19 xs *actor = NULL;
20+ xs *a_name = NULL;
21
22- if (!valid_status(actor_get(actor_id, &actor)))
23- continue;
24+ if (valid_status(actor_get(actor_id, &actor)))
25+ a_name = actor_name(actor, proxy);
26+ else
27+ a_name = xs_dup(actor_id);
28
29- xs *a_name = actor_name(actor, proxy);
30- xs *label_sanatized = sanitize(type);
31- const char *label = label_sanatized;
32+ xs *label_sanitized = sanitize(type);
33+ const char *label = label_sanitized;
34
35 if (strcmp(type, "Create") == 0)
36 label = L("Mention");
M
httpd.c
+62,
-0
1@@ -12,6 +12,7 @@
2 #include "xs_openssl.h"
3 #include "xs_fcgi.h"
4 #include "xs_html.h"
5+#include "xs_webmention.h"
6
7 #include "snac.h"
8
9@@ -373,6 +374,63 @@ int server_get_handler(xs_dict *req, const char *q_path,
10 }
11
12
13+int server_post_handler(const xs_dict *req, const char *q_path,
14+ char *payload, int p_size,
15+ char **body, int *b_size, char **ctype)
16+{
17+ int status = 0;
18+
19+ if (strcmp(q_path, "/webmention-hook") == 0) {
20+ status = HTTP_STATUS_BAD_REQUEST;
21+
22+ const xs_dict *p_vars = xs_dict_get(req, "p_vars");
23+
24+ if (!xs_is_dict(p_vars))
25+ return status;
26+
27+ const char *source = xs_dict_get(p_vars, "source");
28+ const char *target = xs_dict_get(p_vars, "target");
29+
30+ if (!xs_is_string(source) || !xs_is_string(target)) {
31+ srv_debug(1, xs_fmt("webmention-hook bad source or target"));
32+ return status;
33+ }
34+
35+ if (!xs_startswith(target, srv_baseurl)) {
36+ srv_debug(1, xs_fmt("webmention-hook unknown target %s", target));
37+ return status;
38+ }
39+
40+ if (!object_here(target)) {
41+ srv_debug(0, xs_fmt("webmention-hook target %s not / no longer here", target));
42+ return status;
43+ }
44+
45+ /* get the user */
46+ xs *s1 = xs_replace(target, srv_baseurl, "");
47+
48+ xs *l1 = xs_split(s1, "/");
49+ const char *uid = xs_list_get(l1, 1);
50+ snac user;
51+
52+ if (!xs_is_string(uid) || !user_open(&user, uid))
53+ return status;
54+
55+ int r = xs_webmention_hook(source, target, USER_AGENT);
56+
57+ if (r > 0)
58+ notify_add(&user, "Webmention", NULL, source, target, xs_stock(XSTYPE_DICT));
59+
60+ srv_log(xs_fmt("webmention-hook source=%s target=%s %d", source, target, r));
61+
62+ user_free(&user);
63+ status = HTTP_STATUS_OK;
64+ }
65+
66+ return status;
67+}
68+
69+
70 void httpd_connection(FILE *f)
71 /* the connection processor */
72 {
73@@ -444,6 +502,10 @@ void httpd_connection(FILE *f)
74 else
75 if (strcmp(method, "POST") == 0) {
76
77+ if (status == 0)
78+ status = server_post_handler(req, q_path,
79+ payload, p_size, &body, &b_size, &ctype);
80+
81 #ifndef NO_MASTODON_API
82 if (status == 0)
83 status = oauth_post_handler(req, q_path,
+42,
-0
1@@ -5,6 +5,7 @@
2 #define _XS_WEBMENTION_H
3
4 int xs_webmention_send(const char *source, const char *target, const char *user_agent);
5+int xs_webmention_hook(const char *source, const char *target, const char *user_agent);
6
7
8 #ifdef XS_IMPLEMENTATION
9@@ -118,6 +119,47 @@ int xs_webmention_send(const char *source, const char *target, const char *user_
10 }
11
12
13+int xs_webmention_hook(const char *source, const char *target, const char *user_agent)
14+/* a Webmention has been received for a target that is ours; check if the source
15+ really contains a link to our target */
16+{
17+ int status = 0;
18+
19+ xs *ua = xs_fmt("%s (Webmention)", user_agent ? user_agent : "xs_webmention");
20+ xs *headers = xs_dict_new();
21+ headers = xs_dict_set(headers, "accept", "text/html");
22+ headers = xs_dict_set(headers, "user-agent", ua);
23+
24+ xs *g_req = NULL;
25+ xs *payload = NULL;
26+ int p_size = 0;
27+
28+ g_req = xs_http_request("GET", source, headers, NULL, 0, &status, &payload, &p_size, 0);
29+
30+ if (status < 200 || status > 299)
31+ return -1;
32+
33+ if (!xs_is_string(payload))
34+ return -2;
35+
36+ /* note: a "rogue" webmention can include a link to our target in commented-out HTML code */
37+
38+ xs *links = xs_regex_select(payload, "<(a +|link +)[^>]+>");
39+ const char *link;
40+
41+ status = 0;
42+ xs_list_foreach(links, link) {
43+ /* if the link contains our target, it's valid */
44+ if (xs_str_in(link, target) != -1) {
45+ status = 1;
46+ break;
47+ }
48+ }
49+
50+ return status;
51+}
52+
53+
54 #endif /* XS_IMPLEMENTATION */
55
56 #endif /* _XS_WEBMENTION_H */