From 6e8aeef10db2a60595a2f5ffdd6dd9add1bd7055 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Else Date: Fri, 19 Nov 2021 18:21:09 +0100 Subject: [PATCH] Accept webmentions with old target paths --- testdata/wmtest.html | 2 +- webmentionVerification.go | 38 ++++++++++++++++++++++++++++---------- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/testdata/wmtest.html b/testdata/wmtest.html index e634f29..d2e0857 100644 --- a/testdata/wmtest.html +++ b/testdata/wmtest.html @@ -19,7 +19,7 @@ By On
-

I’ve previously talked about how I crosspost from this blog to my Mastodon account without the need for a third-party service, and how I leverage WordPress’s hook system to even enable toot threading.

In this post, I’m going to really quickly explain my (extremely similar) Twitter setup. (Note: I don’t actually syndicate this blog’s posts to Twitter, but I do use this very setup on another site of mine.)

+

I’ve previously talked about how I crosspost from this blog to my Mastodon account without the need for a third-party service, and how I leverage WordPress’s hook system to even enable toot threading.

In this post, I’m going to really quickly explain my (extremely similar) Twitter setup. (Note: I don’t actually syndicate this blog’s posts to Twitter, but I do use this very setup on another site of mine.)

I liked the idea of a dead-simple Twitter plugin, so I forked my Mastodon plugin and tweaked a few things here and there. Once I’ve installed it, and created a developer account, generated the necessary keys, and let WordPress know about them, things look, well, very familiar. In fact, crossposting should now just work.

Now, to enable this when posting through Micropub rather than WordPress’s admin interface! Again, since posting through Micropub means no WordPress interface, and thus no “meta box” and no checkbox, and no way for WordPress to know if I wanted to crosspost a certain article or not, I’m going to have to use … syndication targets (which were invented precisely for this reason).

diff --git a/webmentionVerification.go b/webmentionVerification.go index 164dbc5..2228f45 100644 --- a/webmentionVerification.go +++ b/webmentionVerification.go @@ -74,12 +74,10 @@ func (a *goBlog) verifyMention(m *mention) error { } // Check if target has a valid status code if targetResp.StatusCode != http.StatusOK { - // Ignore for now - // TODO: Reject if target is not found - // return a.db.deleteWebmention(m) if a.cfg.Debug { - log.Printf("Webmention for unknown path: %s\n", m.Target) + a.debug("Webmention for unknown path: %s\n", m.Target) } + return a.db.deleteWebmention(m) } // Check if target has a redirect if respReq := targetResp.Request; respReq != nil { @@ -108,7 +106,7 @@ func (a *goBlog) verifyMention(m *mention) error { // Check if source has a valid status code if sourceResp.StatusCode != http.StatusOK { if a.cfg.Debug { - log.Printf("Delete webmention because source doesn't have valid status code: %s\n", m.Source) + a.debug("Delete webmention because source doesn't have valid status code: %s\n", m.Source) } return a.db.deleteWebmention(m) } @@ -119,11 +117,11 @@ func (a *goBlog) verifyMention(m *mention) error { } } // Parse response body - err = m.verifyReader(sourceResp.Body) + err = a.verifyReader(m, sourceResp.Body) _ = sourceResp.Body.Close() if err != nil { if a.cfg.Debug { - log.Printf("Delete webmention because verifying %s threw error: %s\n", m.Source, err.Error()) + a.debug("Delete webmention because verifying %s threw error: %s\n", m.Source, err.Error()) } return a.db.deleteWebmention(m) } @@ -137,7 +135,7 @@ func (a *goBlog) verifyMention(m *mention) error { // Update or insert webmention if a.db.webmentionExists(m) { if a.cfg.Debug { - log.Printf("Update webmention: %s => %s\n", m.Source, m.Target) + a.debug("Update webmention: %s => %s\n", m.Source, m.Target) } // Update webmention err = a.db.updateWebmention(m, newStatus) @@ -160,7 +158,7 @@ func (a *goBlog) verifyMention(m *mention) error { return err } -func (m *mention) verifyReader(body io.Reader) error { +func (a *goBlog) verifyReader(m *mention, body io.Reader) error { var linksBuffer, gqBuffer, mfBuffer bytes.Buffer if _, err := io.Copy(io.MultiWriter(&linksBuffer, &gqBuffer, &mfBuffer), body); err != nil { return err @@ -171,7 +169,27 @@ func (m *mention) verifyReader(body io.Reader) error { return err } if _, hasLink := funk.FindString(links, func(s string) bool { - return unescapedPath(s) == unescapedPath(m.Target) || unescapedPath(s) == unescapedPath(defaultIfEmpty(m.NewTarget, m.Target)) + // Check if link belongs to installation + hasShortPrefix := a.cfg.Server.ShortPublicAddress != "" && strings.HasPrefix(s, a.cfg.Server.ShortPublicAddress) + hasLongPrefix := strings.HasPrefix(s, a.cfg.Server.PublicAddress) + if !hasShortPrefix && !hasLongPrefix { + return false + } + // Check if link is or redirects to target + req, err := http.NewRequest(http.MethodGet, m.Target, nil) + if err != nil { + return false + } + req.Header.Set("Accept", contenttype.HTMLUTF8) + setLoggedIn(req, true) + resp, err := doHandlerRequest(req, a.getAppRouter()) + if err != nil { + return false + } + if resp.StatusCode == http.StatusOK && unescapedPath(resp.Request.URL.String()) == unescapedPath(defaultIfEmpty(m.NewTarget, m.Target)) { + return true + } + return false }); !hasLink { return errors.New("target not found in source") }