generated from datumforge/go-template
-
Notifications
You must be signed in to change notification settings - Fork 7
/
cookiestore.go
135 lines (112 loc) · 4.14 KB
/
cookiestore.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
124
125
126
127
128
129
130
131
132
133
134
135
package sessions
import (
"net/http"
"net/url"
"github.com/gorilla/securecookie"
)
const (
UserIDKey = "userID"
ExternalUserIDKey = "externalUserID"
SessionNameKey = "name"
UserTypeKey = "userType"
UsernameKey = "username"
EmailKey = "email"
WebAuthnKey = "webauthn"
)
type Store[T any] interface {
// New returns a new named Session
New(name string) *Session[T]
// Get a named Session from the request
Get(req *http.Request, name string) (*Session[T], error)
// Save writes a Session to the ResponseWriter
Save(w http.ResponseWriter, session *Session[T]) error
// Destroy removes (expires) a named Session
Destroy(w http.ResponseWriter, name string)
// GetSessionIDFromCookie returns the key, which should be the sessionID, in the map
GetSessionIDFromCookie(sess *Session[T]) string
// GetSessionDataFromCookie returns the value stored map
GetSessionDataFromCookie(sess *Session[T]) any
// EncodeCookie encodes the cookie
EncodeCookie(session *Session[T]) (string, error)
}
var _ Store[any] = &cookieStore[any]{}
// cookieStore stores Sessions in secure cookies (i.e. client-side)
type cookieStore[T any] struct {
config *CookieConfig
// encodes and decodes signed and optionally encrypted cookie values
codecs []securecookie.Codec
}
// NewCookieStore returns a new Store that signs and optionally encrypts
// session state in http cookies.
func NewCookieStore[T any](config *CookieConfig, keyPairs ...[]byte) Store[T] {
if config == nil {
config = DefaultCookieConfig
}
return &cookieStore[T]{
config: config,
codecs: securecookie.CodecsFromPairs(keyPairs...),
}
}
// New returns a new named Session
func (s *cookieStore[T]) New(name string) *Session[T] {
return NewSession[T](s, name)
}
// Get returns the named Session from the Request. Returns an error if the
// session cookie cannot be found, the cookie verification fails, or an error
// occurs decoding the cookie value.
func (s *cookieStore[T]) Get(req *http.Request, name string) (session *Session[T], err error) {
cookie, err := req.Cookie(name)
if err == nil {
// decode the session cookie, UIs like to encode the cookie value
decodedSession, err := url.QueryUnescape(cookie.Value)
if err != nil {
return nil, err
}
session = s.New(name)
if err = securecookie.DecodeMulti(name, decodedSession, &session.values, s.codecs...); err != nil {
return nil, err
}
}
return session, err
}
// GetSessionIDFromCookie gets the cookies from the http.Request and gets the key (session ID) from the values
func (s *cookieStore[T]) GetSessionIDFromCookie(sess *Session[T]) string {
for k := range sess.values {
return k
}
return ""
}
// GetSessionDataFromCookie gets the cookies from the http.Request and gets session values
func (s *cookieStore[T]) GetSessionDataFromCookie(sess *Session[T]) any {
for _, v := range sess.values {
return v
}
return ""
}
// Save adds or updates the Session on the response via a signed and optionally
// encrypted session cookie. Session Values are encoded into the cookie value
// and the session Config sets cookie properties.
func (s *cookieStore[T]) Save(w http.ResponseWriter, session *Session[T]) error {
cookieValue, err := securecookie.EncodeMulti(session.Name(), &session.values, s.codecs...)
if err != nil {
return err
}
http.SetCookie(w, NewCookie(session.Name(), cookieValue, s.config))
return nil
}
func (s *cookieStore[T]) EncodeCookie(session *Session[T]) (string, error) {
return securecookie.EncodeMulti(session.Name(), &session.values, s.codecs...)
}
// Destroy deletes the Session with the given name by issuing an expired
// session cookie with the same name.
func (s *cookieStore[T]) Destroy(w http.ResponseWriter, name string) {
http.SetCookie(w, NewCookie(name, "", &CookieConfig{MaxAge: -1, Path: s.config.Path}))
}
// NewSessionCookie creates a cookie from a session id
func NewSessionCookie(session string) *http.Cookie {
return NewCookie(DefaultCookieName, session, DefaultCookieConfig)
}
// NewDevSessionCookie creates a cookie from a session id using the dev cookie name
func NewDevSessionCookie(session string) *http.Cookie {
return NewCookie(DevCookieName, session, DefaultCookieConfig)
}