Improve ActivityPub and Webmention verification

This commit is contained in:
Jan-Lukas Else 2021-06-15 22:20:54 +02:00
parent 32339e5c41
commit 1ef5b11310
3 changed files with 38 additions and 22 deletions

View File

@ -17,6 +17,7 @@ import (
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/go-fed/httpsig" "github.com/go-fed/httpsig"
"github.com/spf13/cast"
) )
func (a *goBlog) initActivityPub() error { func (a *goBlog) initActivityPub() error {
@ -167,17 +168,22 @@ func (a *goBlog) apHandleInbox(w http.ResponseWriter, r *http.Request) {
case "Create": case "Create":
{ {
if object, ok := activity["object"].(map[string]interface{}); ok { if object, ok := activity["object"].(map[string]interface{}); ok {
inReplyTo, hasReplyToString := object["inReplyTo"].(string) inReplyTo := cast.ToString(object["inReplyTo"])
id, hasID := object["id"].(string) objectId := cast.ToString(object["id"])
if hasReplyToString && hasID && len(inReplyTo) > 0 && len(id) > 0 && strings.Contains(inReplyTo, blogIri) { objectUrl := cast.ToString(object["url"])
baseUrl := objectId
if objectUrl != "" {
baseUrl = objectUrl
}
if inReplyTo != "" && objectId != "" && strings.Contains(inReplyTo, blogIri) {
// It's an ActivityPub reply; save reply as webmention // It's an ActivityPub reply; save reply as webmention
_ = a.createWebmention(id, inReplyTo) _ = a.createWebmention(baseUrl, inReplyTo)
} else if content, hasContent := object["content"].(string); hasContent && hasID && len(id) > 0 { } else if content, hasContent := object["content"].(string); hasContent && objectId != "" {
// May be a mention; find links to blog and save them as webmentions // May be a mention; find links to blog and save them as webmentions
if links, err := allLinksFromHTMLString(content, id); err == nil { if links, err := allLinksFromHTMLString(content, baseUrl); err == nil {
for _, link := range links { for _, link := range links {
if strings.Contains(link, blogIri) { if strings.Contains(link, blogIri) {
_ = a.createWebmention(id, link) _ = a.createWebmention(baseUrl, link)
} }
} }
} }

View File

@ -614,17 +614,22 @@ func noIndexHeader(next http.Handler) http.Handler {
} }
type dynamicHandler struct { type dynamicHandler struct {
router *chi.Mux router *chi.Mux
mutex sync.RWMutex mutex sync.RWMutex
initialized bool
} }
func (d *dynamicHandler) swapHandler(h *chi.Mux) { func (d *dynamicHandler) swapHandler(h *chi.Mux) {
d.mutex.Lock() d.mutex.Lock()
d.router = h d.router = h
d.initialized = true
d.mutex.Unlock() d.mutex.Unlock()
} }
func (d *dynamicHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (d *dynamicHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
for !d.initialized {
time.Sleep(1 * time.Second)
}
// Fix to use Path routing instead of RawPath routing in Chi // Fix to use Path routing instead of RawPath routing in Chi
r.URL.RawPath = "" r.URL.RawPath = ""
// Serve request // Serve request

View File

@ -72,7 +72,7 @@ func (a *goBlog) verifyMention(m *mention) error {
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
for a.d == nil { for a.d == nil {
// Server not yet started // Server not yet started
time.Sleep(10 * time.Second) time.Sleep(1 * time.Second)
} }
a.d.ServeHTTP(rec, req.WithContext(context.WithValue(req.Context(), loggedInKey, true))) a.d.ServeHTTP(rec, req.WithContext(context.WithValue(req.Context(), loggedInKey, true)))
resp = rec.Result() resp = rec.Result()
@ -89,11 +89,11 @@ func (a *goBlog) verifyMention(m *mention) error {
_, err := a.db.exec("delete from webmentions where source = @source and target = @target", sql.Named("source", m.Source), sql.Named("target", m.Target)) _, err := a.db.exec("delete from webmentions where source = @source and target = @target", sql.Named("source", m.Source), sql.Named("target", m.Target))
return err return err
} }
if len(m.Content) > 500 { if cr := []rune(m.Content); len(cr) > 500 {
m.Content = m.Content[0:497] + "…" m.Content = string(cr[0:497]) + "…"
} }
if len(m.Title) > 60 { if tr := []rune(m.Title); len(tr) > 60 {
m.Title = m.Title[0:57] + "…" m.Title = string(tr[0:57]) + "…"
} }
newStatus := webmentionStatusVerified newStatus := webmentionStatusVerified
if a.db.webmentionExists(m.Source, m.Target) { if a.db.webmentionExists(m.Source, m.Target) {
@ -122,20 +122,25 @@ func (m *mention) verifyReader(body io.Reader) error {
}); !hasLink { }); !hasLink {
return errors.New("target not found in source") return errors.New("target not found in source")
} }
// Set title
doc, err := goquery.NewDocumentFromReader(&gqBuffer)
if err != nil {
return err
}
if title := doc.Find("title"); title != nil {
m.Title = title.Text()
}
// Fill mention attributes // Fill mention attributes
sourceURL, err := url.Parse(m.Source) sourceURL, err := url.Parse(m.Source)
if err != nil { if err != nil {
return err return err
} }
m.Title = ""
m.Content = ""
m.Author = ""
m.fillFromData(microformats.Parse(&mfBuffer, sourceURL)) m.fillFromData(microformats.Parse(&mfBuffer, sourceURL))
// Set title when content is empty as well
if m.Title == "" && m.Content == "" {
doc, err := goquery.NewDocumentFromReader(&gqBuffer)
if err != nil {
return err
}
if title := doc.Find("title"); title != nil {
m.Title = title.Text()
}
}
return nil return nil
} }