aboutsummaryrefslogtreecommitdiff
path: root/registry/registry.go
diff options
context:
space:
mode:
Diffstat (limited to 'registry/registry.go')
-rw-r--r--registry/registry.go57
1 files 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) {