1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
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)
}
|