-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcookies.go
123 lines (108 loc) · 2.88 KB
/
cookies.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
119
120
121
122
123
package oauth
import (
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"fmt"
"path/filepath"
"io/ioutil"
"os"
"net/http"
"github.com/gorilla/securecookie"
"github.com/mholt/caddy"
)
type cookieManager struct {
sc *securecookie.SecureCookie
}
func getCookie(given string) (*cookieManager, error) {
var hashKey, blockKey []byte
//given in caddyfile
if len(given) > 0 {
if len(given) < 10 {
return nil, fmt.Errorf("cookie_secret is too short")
}
hashKey, blockKey = getKeys(given)
} else {
//ok, lets make one and store it in the .caddy dir then
dir := filepath.Join(caddy.AssetsPath(), "oauth")
if err := os.MkdirAll(dir, 0600); err != nil {
return nil, err
}
fpath := filepath.Join(dir, "secret.key")
dat, err := ioutil.ReadFile(fpath)
//not there. make it.
if os.IsNotExist(err) {
dat = make([]byte, 64)
rand.Read(dat)
err = ioutil.WriteFile(fpath, dat, 0600)
if err != nil {
return nil, fmt.Errorf("writing cookie_secret: %s", err)
}
} else if err != nil {
return nil, err
}
if len(dat) != 64 {
return nil, fmt.Errorf("Stored cookie_secret is wrong length. Expect exactly 64 bytes")
}
hashKey, blockKey = dat[:32], dat[32:]
}
return &cookieManager{sc: securecookie.New(hashKey, blockKey)}, nil
}
func getKeys(s string) ([]byte, []byte) {
var dat []byte
var err error
//if valid b64, use that. best practice is a 64 byte random base 64 string
if dat, err = base64.StdEncoding.DecodeString(s); err != nil {
dat = []byte(s)
}
var hashKey, blockKey []byte
//exactly 64 bytes, awesome
if len(dat) == 64 {
hashKey, blockKey = dat[:32], dat[32:]
} else {
//otherwise hash each half
split := len(dat) / 2
h, e := sha256.Sum256(dat[split:]), sha256.Sum256(dat[:split])
hashKey, blockKey = h[:], e[:]
}
return hashKey, blockKey
}
func (cm *cookieManager) ReadCookie(r *http.Request, name string, maxAge int, dst interface{}) error {
val, err := cm.ReadCookiePlain(r, name)
if err != nil {
return err
}
if err = cm.sc.MaxAge(maxAge).Decode(name, val, dst); err != nil {
return err
}
return nil
}
func (cm *cookieManager) SetCookie(w http.ResponseWriter, name string, maxAge int, dat interface{}) error {
val, err := cm.sc.MaxAge(maxAge).Encode(name, dat)
if err != nil {
return err
}
cm.SetCookiePlain(w, name, maxAge, val)
return nil
}
func (cm *cookieManager) SetCookiePlain(w http.ResponseWriter, name string, maxAge int, value string) {
cookie := &http.Cookie{
MaxAge: maxAge,
HttpOnly: true,
Name: name,
Path: "/",
Secure: true,
Value: value,
}
http.SetCookie(w, cookie)
}
func (cm *cookieManager) ReadCookiePlain(r *http.Request, name string) (string, error) {
cookie, err := r.Cookie(name)
if err != nil {
return "", err //cookie no exist
}
return cookie.Value, nil
}
func (cm *cookieManager) ClearCookie(w http.ResponseWriter, name string) {
cm.SetCookiePlain(w, name, -1, "")
}