53 lines
1.2 kB
1
package knotserver
2
3
import (
4
"crypto/hmac"
5
"crypto/sha256"
6
"encoding/hex"
7
"net/http"
8
"time"
9
)
10
11
func (h *Handle) VerifySignature(next http.Handler) http.Handler {
12
if h.c.Server.Dev {
13
return next
14
}
15
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
16
signature := r.Header.Get("X-Signature")
17
if signature == "" || !h.verifyHMAC(signature, r) {
18
writeError(w, "signature verification failed", http.StatusForbidden)
19
return
20
}
21
next.ServeHTTP(w, r)
22
})
23
}
24
25
func (h *Handle) verifyHMAC(signature string, r *http.Request) bool {
26
secret := h.c.Server.Secret
27
timestamp := r.Header.Get("X-Timestamp")
28
if timestamp == "" {
29
return false
30
}
31
32
// Verify that the timestamp is not older than a minute
33
reqTime, err := time.Parse(time.RFC3339, timestamp)
34
if err != nil {
35
return false
36
}
37
if time.Since(reqTime) > time.Minute {
38
return false
39
}
40
41
message := r.Method + r.URL.Path + timestamp
42
43
mac := hmac.New(sha256.New, []byte(secret))
44
mac.Write([]byte(message))
45
expectedMAC := mac.Sum(nil)
46
47
signatureBytes, err := hex.DecodeString(signature)
48
if err != nil {
49
return false
50
}
51
52
return hmac.Equal(signatureBytes, expectedMAC)
53
}
54