@@ -7,18 +7,19 @@ import (
7
7
"encoding/base64"
8
8
"fmt"
9
9
"io/ioutil"
10
- "math"
11
10
"net/http"
12
11
"net/url"
13
12
"strconv"
14
13
"time"
15
14
)
16
15
17
- const tsHeader = "MessageBird-Request-Timestamp"
18
- const sHeader = "MessageBird-Signature"
16
+ const (
17
+ tsHeader = "MessageBird-Request-Timestamp"
18
+ sHeader = "MessageBird-Signature"
19
+ )
19
20
20
- // ValidityPeriod is the time in hours after which a request is descarded
21
- type ValidityPeriod * float64
21
+ // Window of acceptance for a request, if the time stamp is within this time, it will evaluated as valid
22
+ var ValidityWindow = 5 * time . Second
22
23
23
24
// StringToTime converts from Unicod Epoch enconded timestamps to time.Time Go objects
24
25
func stringToTime (s string ) (time.Time , error ) {
@@ -42,58 +43,52 @@ func hMACSHA256(message, key []byte) ([]byte, error) {
42
43
// Validator type represents a MessageBird signature validator
43
44
type Validator struct {
44
45
SigningKey string // Signing Key provided by MessageBird
45
- Period ValidityPeriod // Period in hours for a message to be accepted as real, set to nil to bypass the timestamp validator
46
- }
46
+ Period * time. Duration // Period for a message to be accepted as real, set no nil to bypass the time validator
47
+ } // Five seconds by default
47
48
48
49
// NewValidator returns a signature validator object
49
- func NewValidator (signingKey string , period ValidityPeriod ) * Validator {
50
+ func NewValidator (signingKey string ) * Validator {
50
51
return & Validator {
51
52
SigningKey : signingKey ,
52
- Period : period ,
53
+ Period : & ValidityWindow ,
53
54
}
54
55
}
55
56
56
- // ValidTimestamp validates if the MessageBird-Request-Timestamp is a valid
57
+ // validTimestamp validates if the MessageBird-Request-Timestamp is a valid
57
58
// date and if the request is older than the validator Period.
58
- func (v * Validator ) ValidTimestamp (ts string ) bool {
59
+ func (v * Validator ) validTimestamp (ts string ) bool {
59
60
t , err := stringToTime (ts )
60
61
if err != nil {
61
62
return false
62
63
}
63
- if v .Period != nil {
64
- now := time .Now ()
65
- diff := now .Sub (t )
66
- if math .Abs (diff .Hours ()) > * v .Period {
67
- return false
68
- }
64
+ if v .Period == nil {
65
+ return true
69
66
}
70
- return true
67
+
68
+ diff := time .Now ().Add (* v .Period / 2 ).Sub (t )
69
+ return diff < * v .Period && diff > 0
71
70
}
72
71
73
- // CalculateSignature calculates the MessageBird-Signature using HMAC_SHA_256
72
+ // calculateSignature calculates the MessageBird-Signature using HMAC_SHA_256
74
73
// encoding and the timestamp, query params and body from the request:
75
74
// signature = HMAC_SHA_256(
76
75
// TIMESTAMP + \n + QUERY_PARAMS + \n + SHA_256_SUM(BODY),
77
76
// signing_key)
78
- func (v * Validator ) CalculateSignature (ts , qp string , b []byte ) ([]byte , error ) {
77
+ func (v * Validator ) calculateSignature (ts , qp string , b []byte ) ([]byte , error ) {
79
78
var m bytes.Buffer
80
79
bh := sha256 .Sum256 (b )
81
80
fmt .Fprintf (& m , "%s\n %s\n %s" , ts , qp , bh [:])
82
- s , err := hMACSHA256 (m .Bytes (), []byte (v .SigningKey ))
83
- if err != nil {
84
- return nil , err
85
- }
86
- return s , nil
81
+ return hMACSHA256 (m .Bytes (), []byte (v .SigningKey ))
87
82
}
88
83
89
- // ValidSignature takes the timestamp, query params and body from the request,
84
+ // validSignature takes the timestamp, query params and body from the request,
90
85
// calculates the expected signature and compares it to the one sent by MessageBird.
91
- func (v * Validator ) ValidSignature (ts , rqp string , b []byte , rs string ) bool {
86
+ func (v * Validator ) validSignature (ts , rqp string , b []byte , rs string ) bool {
92
87
uqp , err := url .Parse ("?" + rqp )
93
88
if err != nil {
94
89
return false
95
90
}
96
- es , err := v .CalculateSignature (ts , uqp .Query ().Encode (), b )
91
+ es , err := v .calculateSignature (ts , uqp .Query ().Encode (), b )
97
92
if err != nil {
98
93
return false
99
94
}
@@ -115,7 +110,7 @@ func (v *Validator) ValidRequest(r *http.Request) error {
115
110
return fmt .Errorf ("Unknown host: %s" , r .Host )
116
111
}
117
112
b , _ := ioutil .ReadAll (r .Body )
118
- if v .ValidTimestamp (ts ) == false || v .ValidSignature (ts , r .URL .RawQuery , b , rs ) == false {
113
+ if v .validTimestamp (ts ) == false || v .validSignature (ts , r .URL .RawQuery , b , rs ) == false {
119
114
return fmt .Errorf ("Unknown host: %s" , r .Host )
120
115
}
121
116
r .Body = ioutil .NopCloser (bytes .NewBuffer (b ))
0 commit comments