From 37d76d8f266f40801f4f7c3eaff3adaebb81ef31 Mon Sep 17 00:00:00 2001 From: Julio Capote Date: Wed, 4 Jan 2023 22:59:56 -0500 Subject: try signing and sending accept --- registry/registry.go | 57 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/registry/registry.go b/registry/registry.go index 1c8c9b3..5376f80 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -7,9 +7,12 @@ import ( "encoding/gob" "encoding/json" "encoding/pem" + "fmt" + "io" "net/http" "net/url" "strings" + "sync" "git.capotej.com/capotej/communique/config" "git.capotej.com/capotej/communique/models" @@ -18,6 +21,7 @@ import ( "git.capotej.com/capotej/communique/views" "github.com/go-fed/activity/streams" "github.com/go-fed/activity/streams/vocab" + "github.com/go-fed/httpsig" "go.uber.org/zap" ) @@ -31,6 +35,8 @@ type Registry struct { persister *models.Persister handlerMap map[string]Handler log *zap.SugaredLogger + signer httpsig.Signer + mu *sync.Mutex } func NewRegistry(cfg config.Config, persister *models.Persister, log *zap.SugaredLogger) (*Registry, error) { @@ -198,7 +204,7 @@ func (r *Registry) Inbox(name string, req *http.Request, payload []byte) error { url := inboxProp.GetIRI() logger.With("actor", idPropUrl).With("inbox", url).Debugf("follow") - deliverAcceptToInbox(url, actorUrl, follow, handler.handlerCfg, r.log) + r.deliverAcceptToInbox(url, actorUrl, follow, handler.handlerCfg) // subscribeActorToHandler() return nil }, func(c context.Context, note vocab.ActivityStreamsUndo) error { @@ -215,7 +221,7 @@ func (r *Registry) Inbox(name string, req *http.Request, payload []byte) error { return err } -func deliverAcceptToInbox(url, actorUrl *url.URL, follow vocab.ActivityStreamsFollow, handler config.Handler, log *zap.SugaredLogger) error { +func (r *Registry) deliverAcceptToInbox(url, actorUrl *url.URL, follow vocab.ActivityStreamsFollow, handler config.Handler) error { accept := streams.NewActivityStreamsAccept() actorProp := streams.NewActivityStreamsActorProperty() actorProp.AppendIRI(actorUrl) @@ -227,8 +233,51 @@ func deliverAcceptToInbox(url, actorUrl *url.URL, follow vocab.ActivityStreamsFo if err != nil { return err } - log.With("type", "delivery").With("payload", payload).Debugf("sending accept") - return nil + jsonData, err := json.Marshal(payload) + + aso := models.NewKeypair(handler) + result, err := r.persister.Find(aso) + if err != nil { + return err + } + buf := bytes.NewBuffer(result) + dec := gob.NewDecoder(buf) + var keypair models.Keypair + err = dec.Decode(&keypair) + if err != nil { + return err + } + privKey := &keypair.PrivateKey + + request, err := http.NewRequest("POST", url.String(), bytes.NewBuffer(jsonData)) + + r.log.With("type", "delivery").With("payload", payload).Debugf("signing") + r.mu.Lock() + defer r.mu.Unlock() + prefs := []httpsig.Algorithm{httpsig.RSA_SHA512, httpsig.RSA_SHA256} + digestAlgorithm := httpsig.DigestSha256 + // The "Date" and "Digest" headers must already be set on r, as well as r.URL. + headersToSign := []string{httpsig.RequestTarget, "date", "digest"} + signer, _, err := httpsig.NewSigner(prefs, digestAlgorithm, headersToSign, httpsig.Signature, 0) + if err != nil { + return err + } + // To sign the digest, we need to give the signer a copy of the body... + // ...but it is optional, no digest will be signed if given "nil" + // body := nil + // If r were a http.ResponseWriter, call SignResponse instead. + err = signer.SignRequest(privKey, actorUrl.String(), request, jsonData) + + r.log.With("type", "delivery").With("payload", payload).Debugf("sending accept") + client := &http.Client{} + response, err := client.Do(request) + if err != nil { + return fmt.Errorf("could not send accept request: %w", err) + } + responseBody, err := io.ReadAll(response.Body) + defer response.Body.Close() + r.log.With("type", "delivery").With("response", responseBody).Debugf("received") + return err } func (r *Registry) ActivityOrNote(activityOrNote, name, id string) (map[string]interface{}, error) { -- cgit v1.2.3