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