-
Notifications
You must be signed in to change notification settings - Fork 0
/
signatures.go
62 lines (46 loc) · 1.81 KB
/
signatures.go
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
package inbox
import (
"net/http"
"github.com/benpate/derp"
"github.com/benpate/hannibal/sigs"
"github.com/benpate/hannibal/streams"
"github.com/rs/zerolog/log"
)
/******************************************
* HTTP Signatures
*
* https://docs.joinmastodon.org/spec/security/
*
******************************************/
// validateRequest uses the hannibal/sigs library to verify that the HTTP
// request is signed with a valid key.
func validateRequest(request *http.Request, document streams.Document) error {
const location = "hannibal.pub.validateRequest"
// Find the public key for the Actor who signed this request
keyFinder := keyFinder(document)
// Verify the request using the Actor's public key
if err := sigs.Verify(request, keyFinder); err != nil {
return derp.Wrap(err, location, "Unable to verify HTTP signature", document.Value(), derp.WithCode(derp.CodeForbiddenError))
}
return nil
}
// keyFinder looks up the public Key for the provided document/Actor
func keyFinder(document streams.Document) sigs.PublicKeyFinder {
const location = "hannibal.pub.keyFinder"
return func(keyID string) (string, error) {
// Load the Actor from the document
actor, err := document.Actor().Load()
if err != nil {
return "", derp.Wrap(err, location, "Error retrieving Actor from ActivityPub document", document.Value())
}
// Search the Actor's public keys for the one that matches the provided keyID
for key := actor.PublicKey(); key.NotNil(); key = key.Tail() {
if key.ID() == keyID {
log.Trace().Str("keyId", keyID).Msg("Hannibal Inbox: Found Public Key")
return key.PublicKeyPEM(), nil
}
}
// If none match, then return a (hopefully informative) error.
return "", derp.NewBadRequestError(location, "Actor must publish the key used to sign this request", actor.ID(), keyID)
}
}