From b4a1972968e64777bcb761ed47649ed607e054c5 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Else Date: Tue, 13 Sep 2022 23:05:53 +0200 Subject: [PATCH] Sign ActivityPub requests to get remote actor --- activityPub.go | 26 ++++++++++++++++++-------- activityPubSending.go | 9 ++------- go.mod | 4 ++-- go.sum | 8 ++++---- 4 files changed, 26 insertions(+), 21 deletions(-) diff --git a/activityPub.go b/activityPub.go index 388cc4c..05017ba 100644 --- a/activityPub.go +++ b/activityPub.go @@ -147,7 +147,7 @@ func (a *goBlog) apHandleInbox(w http.ResponseWriter, r *http.Request) { } blogIri := a.apIri(blog) // Verify request - requestActor, requestKey, requestActorStatus, err := a.apVerifySignature(r) + requestActor, requestKey, requestActorStatus, err := a.apVerifySignature(r, blogIri) if err != nil { // Send 401 because signature could not be verified a.serveError(w, r, err.Error(), http.StatusUnauthorized) @@ -188,7 +188,7 @@ func (a *goBlog) apHandleInbox(w http.ResponseWriter, r *http.Request) { // Do switch activity["type"] { case "Follow": - a.apAccept(blogName, blog, activity) + a.apAccept(blogName, blogIri, blog, activity) case "Undo": if object, ok := activity["object"].(map[string]any); ok { ot := cast.ToString(object["type"]) @@ -234,14 +234,14 @@ func (a *goBlog) apHandleInbox(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) } -func (a *goBlog) apVerifySignature(r *http.Request) (*asPerson, string, int, error) { +func (a *goBlog) apVerifySignature(r *http.Request, blogIri string) (*asPerson, string, int, error) { verifier, err := httpsig.NewVerifier(r) if err != nil { // Error with signature header etc. return nil, "", 0, err } keyID := verifier.KeyId() - actor, statusCode, err := a.apGetRemoteActor(keyID) + actor, statusCode, err := a.apGetRemoteActor(keyID, blogIri) if err != nil || actor == nil || statusCode != 0 { // Actor not found or something else bad return nil, keyID, statusCode, err @@ -267,13 +267,23 @@ func handleWellKnownHostMeta(w http.ResponseWriter, r *http.Request) { _, _ = io.WriteString(w, ``) } -func (a *goBlog) apGetRemoteActor(iri string) (*asPerson, int, error) { - req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, iri, nil) +func (a *goBlog) apGetRemoteActor(iri, ownBlogIri string) (*asPerson, int, error) { + req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, iri, strings.NewReader("")) if err != nil { return nil, 0, err } req.Header.Set("Accept", contenttype.AS) req.Header.Set(userAgent, appUserAgent) + // Sign request + req.Header.Set("Date", time.Now().UTC().Format("Mon, 02 Jan 2006 15:04:05")+" GMT") + req.Header.Set("Host", req.URL.Host) + a.apPostSignMutex.Lock() + err = a.apPostSigner.SignRequest(a.apPrivateKey, ownBlogIri+"#main-key", req, []byte("")) + a.apPostSignMutex.Unlock() + if err != nil { + return nil, 0, err + } + // Do request resp, err := a.httpClient.Do(req) if err != nil { return nil, 0, err @@ -367,7 +377,7 @@ func (a *goBlog) apUndelete(p *post) { a.apPost(p) } -func (a *goBlog) apAccept(blogName string, blog *configBlog, follow map[string]any) { +func (a *goBlog) apAccept(blogName, blogIri string, blog *configBlog, follow map[string]any) { // it's a follow, write it down newFollower := follow["actor"].(string) log.Println("New follow request:", newFollower) @@ -376,7 +386,7 @@ func (a *goBlog) apAccept(blogName string, blog *configBlog, follow map[string]a // actor and object are equal return } - follower, status, err := a.apGetRemoteActor(newFollower) + follower, status, err := a.apGetRemoteActor(newFollower, blogIri) if err != nil || status != 0 { // Couldn't retrieve remote actor info log.Println("Failed to retrieve remote actor info:", newFollower) diff --git a/activityPubSending.go b/activityPubSending.go index 8d7fd71..8dc48f5 100644 --- a/activityPubSending.go +++ b/activityPubSending.go @@ -9,7 +9,6 @@ import ( "io" "log" "net/http" - "net/url" "time" "go.goblog.app/app/pkgs/bufferpool" @@ -77,17 +76,13 @@ func (a *goBlog) apSendSigned(blogIri, to string, activity []byte) error { if err != nil { return err } - iri, err := url.Parse(to) - if err != nil { - return err - } r.Header.Set("Accept-Charset", "utf-8") - r.Header.Set("Date", time.Now().UTC().Format("Mon, 02 Jan 2006 15:04:05")+" GMT") r.Header.Set(userAgent, appUserAgent) r.Header.Set("Accept", contenttype.ASUTF8) r.Header.Set(contentType, contenttype.ASUTF8) - r.Header.Set("Host", iri.Host) // Sign request + r.Header.Set("Date", time.Now().UTC().Format("Mon, 02 Jan 2006 15:04:05")+" GMT") + r.Header.Set("Host", r.URL.Host) a.apPostSignMutex.Lock() err = a.apPostSigner.SignRequest(a.apPrivateKey, blogIri+"#main-key", r, activity) a.apPostSignMutex.Unlock() diff --git a/go.mod b/go.mod index 60a2517..71394ba 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/disintegration/imaging v1.6.2 github.com/dmulholl/mp3lib v1.0.0 github.com/elnormous/contenttype v1.0.3 - github.com/emersion/go-sasl v0.0.0-20211008083017-0b9dcfb154ac + github.com/emersion/go-sasl v0.0.0-20220912192320-0145f2c60ead github.com/emersion/go-smtp v0.15.0 github.com/go-chi/chi/v5 v5.0.7 github.com/go-fed/httpsig v1.1.0 @@ -59,7 +59,7 @@ require ( // master github.com/yuin/goldmark-emoji v1.0.2-0.20210607094911-0487583eca38 golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa - golang.org/x/net v0.0.0-20220907135653-1e95f45603a7 + golang.org/x/net v0.0.0-20220909164309-bea034e7d591 golang.org/x/sync v0.0.0-20220907140024-f12130a52804 golang.org/x/text v0.3.7 gopkg.in/yaml.v3 v3.0.1 diff --git a/go.sum b/go.sum index 918ed23..f23f7cc 100644 --- a/go.sum +++ b/go.sum @@ -140,8 +140,8 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn github.com/elnormous/contenttype v1.0.3 h1:5DrD4LGO3ohab+jPplwE/LlY9JqmkYdssz4Zu7xl8Cs= github.com/elnormous/contenttype v1.0.3/go.mod h1:ngVcyGGU8pnn4QJ5sL4StrNgc/wmXZXy5IQSBuHOFPg= github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ= -github.com/emersion/go-sasl v0.0.0-20211008083017-0b9dcfb154ac h1:tn/OQ2PmwQ0XFVgAHfjlLyqMewry25Rz7jWnVoh4Ggs= -github.com/emersion/go-sasl v0.0.0-20211008083017-0b9dcfb154ac/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ= +github.com/emersion/go-sasl v0.0.0-20220912192320-0145f2c60ead h1:fI1Jck0vUrXT8bnphprS1EoVRe2Q5CKCX8iDlpqjQ/Y= +github.com/emersion/go-sasl v0.0.0-20220912192320-0145f2c60ead/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ= github.com/emersion/go-smtp v0.15.0 h1:3+hMGMGrqP/lqd7qoxZc1hTU8LY8gHV9RFGWlqSDmP8= github.com/emersion/go-smtp v0.15.0/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -624,8 +624,8 @@ golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220907135653-1e95f45603a7 h1:1WGATo9HAhkWMbfyuVU0tEFP88OIkUvwaHFveQPvzCQ= -golang.org/x/net v0.0.0-20220907135653-1e95f45603a7/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591 h1:D0B/7al0LLrVC8aWF4+oxpv/m8bc7ViFfVS8/gXGdqI= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=