From e9124914cd6b05502cb5dd7f34720b27657560aa Mon Sep 17 00:00:00 2001 From: Julio Capote Date: Wed, 4 Jan 2023 21:15:57 -0500 Subject: refactor verification into verifier tool, start follow/undo --- tools/verifier.go | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 tools/verifier.go (limited to 'tools') diff --git a/tools/verifier.go b/tools/verifier.go new file mode 100644 index 0000000..4063ccf --- /dev/null +++ b/tools/verifier.go @@ -0,0 +1,81 @@ +package tools + +import ( + "context" + "crypto/x509" + "encoding/json" + "encoding/pem" + "fmt" + "io" + "net/http" + + "github.com/go-fed/activity/streams" + "github.com/go-fed/activity/streams/vocab" + "github.com/go-fed/httpsig" + "go.uber.org/zap" +) + +func VerifyRequest(ctx context.Context, req *http.Request, log *zap.SugaredLogger) (vocab.ActivityStreamsPerson, error) { + logger := log.With("type", "verifier") + verifier, err := httpsig.NewVerifier(req) + if err != nil { + return nil, err + } + + keyId := verifier.KeyId() + logger.With("keyId", keyId).Debugf("fetching key page") + req, err = http.NewRequest("GET", keyId, nil) + req.Header.Set("Accept", "application/json; charset=UTF-8") + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + keyPage, err := io.ReadAll(resp.Body) + logger.With("keyId", keyId).With("response", string(keyPage)).Debugf("received response") + var keyPageData map[string]interface{} + err = json.Unmarshal(keyPage, &keyPageData) + if err != nil { + return nil, err + } + + var person vocab.ActivityStreamsPerson + + resolver, err := streams.NewJSONResolver(func(c context.Context, p vocab.ActivityStreamsPerson) error { + // Store the person in the enclosing scope, for later. + person = p + return nil + }, func(c context.Context, note vocab.ActivityStreamsNote) error { + //TODO not needed, need to figure out how to only pass one func + return nil + }) + + err = resolver.Resolve(ctx, keyPageData) + if err != nil { + return nil, err + } + + pubKeyProp := person.GetW3IDSecurityV1PublicKey() + iter := pubKeyProp.At(0) // TODO not safe, use a for instead + pubKey := iter.Get() + pemProp := pubKey.GetW3IDSecurityV1PublicKeyPem() + pemStr := pemProp.Get() + logger.With("keyId", keyId).With("pem", pemStr).Debugf("extracted pem") + pemObj, _ := pem.Decode([]byte(pemStr)) + if pemObj == nil { + return nil, fmt.Errorf("no PEM block found") + } + if pemObj.Type != "PUBLIC KEY" { + return nil, fmt.Errorf("no public key found in PEM block") + } + + decodedKey, err := x509.ParsePKIXPublicKey(pemObj.Bytes) + if err != nil { + return nil, err + } + logger.With("keyId", keyId).With("pem", pemStr).Debugf("got %T", decodedKey) + algo := httpsig.RSA_SHA256 + return person, verifier.Verify(decodedKey, algo) +} -- cgit v1.2.3