-
Notifications
You must be signed in to change notification settings - Fork 62
/
express.go
118 lines (96 loc) 路 3.11 KB
/
express.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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package monster
import (
"bytes"
"encoding/base64"
"fmt"
"strings"
)
type expressParsedData struct {
data string
signature string
decodedSignature []byte
algorithm string
parsed bool
}
func (d *expressParsedData) String() string {
if !d.parsed {
return "Unparsed data"
}
return fmt.Sprintf("Data: %s\nSignature: %s\nAlgorithm: %s\n", d.data, d.signature, d.algorithm)
}
const (
expressDecoder = "express"
expressMinLength = 10
// Express (or cookie-session, rather) sends the signature in another
// cookie, which is rather annoying. We use a distinct separator and
// ask users to manually assemble this.
expressSeparator = `^`
)
var (
expressAlgorithmLength = map[int]string{
20: "sha1",
32: "sha256",
48: "sha384",
64: "sha512",
}
)
func expressDecode(c *Cookie) bool {
if len(c.raw) < expressMinLength {
return false
}
rawData := c.raw
var parsedData expressParsedData
// Break the cookie out into the session data and signature.
components := strings.Split(rawData, expressSeparator)
if len(components) != 2 {
return false
}
parsedData.data = components[0]
parsedData.signature = components[1]
// Express encodes the signature with URL-safe base64
// without padding, so we must use `RawURLEncoding`.
decodedSignature, err := base64.RawURLEncoding.DecodeString(parsedData.signature)
if err != nil {
return false
}
// Determine the algorithm from the digest length, or give up if we can't
// figure it out.
if alg, ok := expressAlgorithmLength[len(decodedSignature)]; ok {
parsedData.algorithm = alg
} else {
return false
}
parsedData.decodedSignature = decodedSignature
parsedData.parsed = true
c.wasDecodedBy(expressDecoder, &parsedData)
return true
}
func expressUnsign(c *Cookie, secret []byte) bool {
// We need to extract `toBeSigned` to prepare what we'll be signing.
parsedData := c.parsedDataFor(expressDecoder).(*expressParsedData)
toBeSigned := parsedData.data
switch parsedData.algorithm {
case "sha1":
// Derive the correct signature, if this was the correct secret key.
computedSignature := sha1HMAC(secret, []byte(toBeSigned))
// Compare this signature to the one in the `Cookie`.
return bytes.Compare(parsedData.decodedSignature, computedSignature) == 0
case "sha256":
// Derive the correct signature, if this was the correct secret key.
computedSignature := sha256HMAC(secret, []byte(toBeSigned))
// Compare this signature to the one in the `Cookie`.
return bytes.Compare(parsedData.decodedSignature, computedSignature) == 0
case "sha384":
// Derive the correct signature, if this was the correct secret key.
computedSignature := sha384HMAC(secret, []byte(toBeSigned))
// Compare this signature to the one in the `Cookie`.
return bytes.Compare(parsedData.decodedSignature, computedSignature) == 0
case "sha512":
// Derive the correct signature, if this was the correct secret key.
computedSignature := sha512HMAC(secret, []byte(toBeSigned))
// Compare this signature to the one in the `Cookie`.
return bytes.Compare(parsedData.decodedSignature, computedSignature) == 0
default:
panic("unknown algorithm")
}
}