Quellcode durchsuchen

Added a webmention hook.

grunfink vor 1 Jahr
Ursprung
Commit
f88bdd7960
3 geänderte Dateien mit 119 neuen und 5 gelöschten Zeilen
  1. 15 5
      html.c
  2. 62 0
      httpd.c
  3. 42 0
      xs_webmention.h

+ 15 - 5
html.c

@@ -868,6 +868,14 @@ xs_html *html_user_head(snac *user, const char *desc, const char *url)
             xs_html_attr("type", "application/activity+json"),
             xs_html_attr("href", url ? url : user->actor)));
 
+    /* webmention hook */
+    xs *wbh = xs_fmt("%s/webmention-hook", srv_baseurl);
+
+    xs_html_add(head,
+        xs_html_sctag("link",
+            xs_html_attr("rel", "webmention"),
+            xs_html_attr("href", wbh)));
+
     return head;
 }
 
@@ -3407,13 +3415,15 @@ xs_str *html_notifications(snac *user, int skip, int show)
 
         const char *actor_id = xs_dict_get(noti, "actor");
         xs *actor = NULL;
+        xs *a_name = NULL;
 
-        if (!valid_status(actor_get(actor_id, &actor)))
-            continue;
+        if (valid_status(actor_get(actor_id, &actor)))
+            a_name = actor_name(actor, proxy);
+        else
+            a_name = xs_dup(actor_id);
 
-        xs *a_name = actor_name(actor, proxy);
-        xs *label_sanatized = sanitize(type);
-        const char *label = label_sanatized;
+        xs *label_sanitized = sanitize(type);
+        const char *label = label_sanitized;
 
         if (strcmp(type, "Create") == 0)
             label = L("Mention");

+ 62 - 0
httpd.c

@@ -12,6 +12,7 @@
 #include "xs_openssl.h"
 #include "xs_fcgi.h"
 #include "xs_html.h"
+#include "xs_webmention.h"
 
 #include "snac.h"
 
@@ -373,6 +374,63 @@ int server_get_handler(xs_dict *req, const char *q_path,
 }
 
 
+int server_post_handler(const xs_dict *req, const char *q_path,
+                      char *payload, int p_size,
+                      char **body, int *b_size, char **ctype)
+{
+    int status = 0;
+
+    if (strcmp(q_path, "/webmention-hook") == 0) {
+        status = HTTP_STATUS_BAD_REQUEST;
+
+        const xs_dict *p_vars = xs_dict_get(req, "p_vars");
+
+        if (!xs_is_dict(p_vars))
+            return status;
+
+        const char *source = xs_dict_get(p_vars, "source");
+        const char *target = xs_dict_get(p_vars, "target");
+
+        if (!xs_is_string(source) || !xs_is_string(target)) {
+            srv_debug(1, xs_fmt("webmention-hook bad source or target"));
+            return status;
+        }
+
+        if (!xs_startswith(target, srv_baseurl)) {
+            srv_debug(1, xs_fmt("webmention-hook unknown target %s", target));
+            return status;
+        }
+
+        if (!object_here(target)) {
+            srv_debug(0, xs_fmt("webmention-hook target %s not / no longer here", target));
+            return status;
+        }
+
+        /* get the user */
+        xs *s1 = xs_replace(target, srv_baseurl, "");
+
+        xs *l1 = xs_split(s1, "/");
+        const char *uid = xs_list_get(l1, 1);
+        snac user;
+
+        if (!xs_is_string(uid) || !user_open(&user, uid))
+            return status;
+
+        int r = xs_webmention_hook(source, target, USER_AGENT);
+
+        if (r > 0)
+            notify_add(&user, "Webmention", NULL, source, target, xs_stock(XSTYPE_DICT));
+
+        srv_log(xs_fmt("webmention-hook source=%s target=%s %d", source, target, r));
+
+        user_free(&user);
+        status = HTTP_STATUS_OK;
+    }
+
+    return status;
+}
+
+
 void httpd_connection(FILE *f)
 /* the connection processor */
 {
@@ -444,6 +502,10 @@ void httpd_connection(FILE *f)
     else
     if (strcmp(method, "POST") == 0) {
 
+        if (status == 0)
+            status = server_post_handler(req, q_path,
+                        payload, p_size, &body, &b_size, &ctype);
+
 #ifndef NO_MASTODON_API
         if (status == 0)
             status = oauth_post_handler(req, q_path,

+ 42 - 0
xs_webmention.h

@@ -5,6 +5,7 @@
 #define _XS_WEBMENTION_H
 
 int xs_webmention_send(const char *source, const char *target, const char *user_agent);
+int xs_webmention_hook(const char *source, const char *target, const char *user_agent);
 
 
 #ifdef XS_IMPLEMENTATION
@@ -118,6 +119,47 @@ int xs_webmention_send(const char *source, const char *target, const char *user_
 }
 
 
+int xs_webmention_hook(const char *source, const char *target, const char *user_agent)
+/* a Webmention has been received for a target that is ours; check if the source
+   really contains a link to our target */
+{
+    int status = 0;
+
+    xs *ua = xs_fmt("%s (Webmention)", user_agent ? user_agent : "xs_webmention");
+    xs *headers = xs_dict_new();
+    headers = xs_dict_set(headers, "accept", "text/html");
+    headers = xs_dict_set(headers, "user-agent", ua);
+
+    xs *g_req = NULL;
+    xs *payload = NULL;
+    int p_size = 0;
+
+    g_req = xs_http_request("GET", source, headers, NULL, 0, &status, &payload, &p_size, 0);
+
+    if (status < 200 || status > 299)
+        return -1;
+
+    if (!xs_is_string(payload))
+        return -2;
+
+    /* note: a "rogue" webmention can include a link to our target in commented-out HTML code */
+
+    xs *links = xs_regex_select(payload, "<(a +|link +)[^>]+>");
+    const char *link;
+
+    status = 0;
+    xs_list_foreach(links, link) {
+        /* if the link contains our target, it's valid */
+        if (xs_str_in(link, target) != -1) {
+            status = 1;
+            break;
+        }
+    }
+
+    return status;
+}
+
+
 #endif /* XS_IMPLEMENTATION */
 
 #endif /* _XS_WEBMENTION_H */