forked from zerodha/simplesessions
-
Notifications
You must be signed in to change notification settings - Fork 0
/
manager.go
125 lines (99 loc) · 3.83 KB
/
manager.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
package simplesessions
import (
"context"
"fmt"
"net/http"
"time"
)
const (
// Default cookie name used to store session.
defaultCookieName = "session"
// ContextName is the key used to store session in context passed to acquire method.
ContextName = "_simple_session"
)
// Manager is a utility to scaffold session and store.
type Manager struct {
// Store to be used.
store Store
// Store basic cookie details.
opts *Options
// Callback to get http cookie.
getCookieCb func(name string, r interface{}) (*http.Cookie, error)
// Callback to set http cookie.
setCookieCb func(cookie *http.Cookie, w interface{}) error
}
// Options are available options to configure Manager.
type Options struct {
// DisableAutoSet skips creation of session cookie in frontend and new session in store if session is not already set.
DisableAutoSet bool
// CookieName sets http cookie name. This is also sent as cookie name in `GetCookie` callback.
CookieName string
// CookieDomain sets hostname for the cookie. Domain specifies allowed hosts to receive the cookie.
CookieDomain string
// CookiePath sets path for the cookie. Path indicates a URL path that must exist in the requested URL in order to send the cookie header.
CookiePath string
// IsSecureCookie marks the cookie as secure cookie (only sent in HTTPS).
IsSecureCookie bool
// IsHTTPOnlyCookie marks the cookie as http only cookie. JS won't be able to access the cookie so prevents XSS attacks.
IsHTTPOnlyCookie bool
// CookieLifeTime sets expiry time for cookie.
// If expiry time is not specified then cookie is set as session cookie which is cleared on browser close.
CookieLifetime time.Duration
}
// New creates a new session manager for given options.
func New(opts Options) *Manager {
m := &Manager{
opts: &opts,
}
// Set default cookie name if not set
if m.opts.CookieName == "" {
m.opts.CookieName = defaultCookieName
}
// If path not given then set to root path
if m.opts.CookiePath == "" {
m.opts.CookiePath = "/"
}
return m
}
// UseStore sets the session store to be used.
func (m *Manager) UseStore(str Store) {
m.store = str
}
// RegisterGetCookie sets a callback to get http cookie from any reader interface which
// is sent on session acquisition using `Acquire` method.
func (m *Manager) RegisterGetCookie(cb func(string, interface{}) (*http.Cookie, error)) {
m.getCookieCb = cb
}
// RegisterSetCookie sets a callback to set cookie from http writer interface which
// is sent on session acquisition using `Acquire` method.
func (m *Manager) RegisterSetCookie(cb func(*http.Cookie, interface{}) error) {
m.setCookieCb = cb
}
// Acquire gets a `Session` for current session cookie from store.
// If `Session` is not found on store then it creates a new session and sets on store.
// If 'DisableAutoSet` is set in options then session has to be explicitly created before
// using `Session` for getting or setting.
// `r` and `w` is request and response interfaces which are sent back in GetCookie and SetCookie callbacks respectively.
// In case of net/http `r` will be r`
// Optionally context can be passed around which is used to get already loaded session. This is useful when
// handler is wrapped with multiple middlewares and `Acquire` is already called in any of the middleware.
func (m *Manager) Acquire(r, w interface{}, c context.Context) (*Session, error) {
// Check if any store is set
if m.store == nil {
return nil, fmt.Errorf("session store is not set")
}
// Check if callbacks are set
if m.getCookieCb == nil {
return nil, fmt.Errorf("callback `GetCookie` not set")
}
if m.setCookieCb == nil {
return nil, fmt.Errorf("callback `SetCookie` not set")
}
// If a session was already set in the context by a middleware somewhere, return that.
if c != nil {
if v, ok := c.Value(ContextName).(*Session); ok {
return v, nil
}
}
return NewSession(m, r, w)
}