diff options
author | Julio Capote <jcapote@gmail.com> | 2023-01-05 02:15:57 +0000 |
---|---|---|
committer | Julio Capote <jcapote@gmail.com> | 2023-01-05 02:15:57 +0000 |
commit | e9124914cd6b05502cb5dd7f34720b27657560aa (patch) | |
tree | 72c68e673a88e8bd88d02ff22c80d0d17ccb8b88 /tools | |
parent | 6736b04552c582ab5a07556ba20eca92612daf51 (diff) | |
download | communique-e9124914cd6b05502cb5dd7f34720b27657560aa.tar.gz |
refactor verification into verifier tool, start follow/undo
Diffstat (limited to 'tools')
-rw-r--r-- | tools/verifier.go | 81 |
1 files changed, 81 insertions, 0 deletions
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) +} |