Accept webmentions with old target paths

This commit is contained in:
Jan-Lukas Else 2021-11-19 18:21:09 +01:00
parent e0728e2ba0
commit 6e8aeef10d
2 changed files with 29 additions and 11 deletions

View File

@ -19,7 +19,7 @@ By <a class="u-uid u-url url" href="https://example.net/" rel="me"><img class="u
<div class="entry-meta">On <a class="u-url" href="https://example.net/articles/micropub-crossposting-to-twitter-and-enabling-tweetstorms" rel="bookmark"><time datetime="2021-02-22T19:17:05+01:00" class="dt-published">Feb 22, 2021</time></a></div>
</header>
<div class="e-content">
<p>I&#8217;ve previously talked about how I <a href="https://example.org/articles/micropub-syndication-targets-and-crossposting-to-mastodon">crosspost from this blog to my Mastodon account</a> without the need for a third-party service, and how I leverage WordPress&#8217;s hook system to even enable toot threading.</p><p>In this post, I&#8217;m going to really quickly explain my (extremely similar) Twitter setup. (Note: I don&#8217;t actually syndicate <em>this</em> blog&#8217;s posts to Twitter, but I <em>do</em> use this very setup on another site of mine.)</p>
<p>I&#8217;ve previously talked about how I <a href="https://example.org/articles/micropub-syndication-targets-and-crossposting-to-mastodon/">crosspost from this blog to my Mastodon account</a> without the need for a third-party service, and how I leverage WordPress&#8217;s hook system to even enable toot threading.</p><p>In this post, I&#8217;m going to really quickly explain my (extremely similar) Twitter setup. (Note: I don&#8217;t actually syndicate <em>this</em> blog&#8217;s posts to Twitter, but I <em>do</em> use this very setup on another site of mine.)</p>
<p>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&#8217;ve installed it, and created a developer account, generated the necessary keys, and let WordPress know about them, things look, well, <em>very</em> familiar. In fact, crossposting should now <em>just work</em>.</p>
<p>Now, to enable this when posting through Micropub rather than WordPress&#8217;s admin interface! Again, since posting through Micropub means no WordPress interface, and thus no &#8220;meta box&#8221; and no checkbox, and no way for WordPress to know if I wanted to crosspost a certain article or not, I&#8217;m going to have to use &#8230; <em>syndication targets</em> (which were invented precisely for this reason).</p>
</div>

View File

@ -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")
}