-
Notifications
You must be signed in to change notification settings - Fork 0
/
djsession.go
78 lines (69 loc) · 1.89 KB
/
djsession.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
package DjangoSession
import (
"bytes"
"compress/zlib"
"crypto/hmac"
"crypto/sha1"
"crypto/subtle"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"strings"
)
const salt = "django.contrib.sessionsSessionStore"
var defaultSep = []byte{':'}
func djangoSignature(salt string, value []byte, secret string) []byte {
key := make([]byte, 0, len(salt)+len(secret))
key = append(key, salt...)
key = append(key, secret...)
mac := hmac.New(sha1.New, key)
mac.Write(value)
return []byte(hex.EncodeToString(mac.Sum(nil)))
}
func unsign(secret string, cookie []byte) ([]byte, error) {
splitted := strings.SplitN(string(cookie), string(defaultSep), 2)
sig := splitted[0]
val := []byte(splitted[1])
expectedSig := djangoSignature(salt, val, secret)
if subtle.ConstantTimeCompare([]byte(sig), expectedSig) != 1 {
return nil, fmt.Errorf("signature mismatch: '%s' != '%s'", sig, string(expectedSig))
}
return val, nil
}
func timestampUnsign(secret string, cookie []byte) ([]byte, error) {
val, err := unsign(secret, cookie)
if err != nil {
return nil, fmt.Errorf("unsign('%s'): %s", string(cookie), err)
}
return val, nil
}
func signingLoads(secret, cookie string) (map[string]interface{}, error) {
c := []byte(cookie) // XXX: does this escape?
payload, err := timestampUnsign(secret, c)
if err != nil {
return nil, fmt.Errorf("timestampUnsign: %s", err)
}
decompress := false
if payload[0] == '.' {
decompress = true
payload = payload[1:]
}
if decompress {
r, err := zlib.NewReader(bytes.NewReader(payload))
if err != nil {
return nil, fmt.Errorf("zlib.NewReader: %s", err)
}
payload, err = ioutil.ReadAll(r)
r.Close()
if err != nil {
return nil, fmt.Errorf("ReadAll(zlib): %s", err)
}
}
o := make(map[string]interface{})
json.Unmarshal(payload, &o)
return o, nil
}
func Decode(secret, cookie string) (map[string]interface{}, error) {
return signingLoads(secret, cookie)
}