forked from browseraudit/browseraudit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsession.go
More file actions
160 lines (134 loc) · 5.23 KB
/
session.go
File metadata and controls
160 lines (134 loc) · 5.23 KB
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package main
import (
"crypto/rand"
"crypto/sha1"
"fmt"
"github.com/bradfitz/gomemcache/memcache"
"github.com/gorilla/mux"
"net"
"net/http"
//"log"
"regexp"
"strconv"
"time"
)
const SESSION_ID_COOKIE_NAME = "sessid"
// =======================ß======================================================
// BASessionStore
// =============================================================================
type BASessionStore struct {
MemcachedClient *memcache.Client
}
// Creates a new BASessionStore, backed by a Memcached server running on the
// given host and listening on the given port number
func NewBASessionStore(memcachedHost string, memcachedPort int) *BASessionStore {
client := memcache.New(memcachedHost + ":" + strconv.Itoa(memcachedPort))
return &BASessionStore{MemcachedClient: client}
}
// Creates a new session
func (store *BASessionStore) New(w http.ResponseWriter, r *http.Request) *BASession {
random := make([]byte, 16)
rand.Read(random)
currentTime := strconv.FormatInt(time.Now().UnixNano(), 10)
ip := net.ParseIP(r.Header["X-Real-Ip"][0]).String()
userAgent := r.UserAgent()
plaintext := []byte(cfg.HTTPServer.SessionIDSalt + "|" + fmt.Sprintf("%x", string(random[:])) + "|" + currentTime + "|" + ip + "|" + userAgent)
sessionID := fmt.Sprintf("%x", sha1.Sum(plaintext))
//log.Printf("BASessionStore New(): generated session ID: %s", sessionID)
cookie := &http.Cookie{
Name: SESSION_ID_COOKIE_NAME,
Value: sessionID,
Domain: "." + cfg.Domain.Domain1,
Path: "/",
Expires: time.Now().Add(24 * time.Hour),
}
http.SetCookie(w, cookie)
return &BASession{
MemcachedClient: store.MemcachedClient,
Id: sessionID,
}
}
// Loads a session based on the session ID in the Cookie HTTP header or URL
// query string, or creates a new session if neither exists
func (store *BASessionStore) Get(w http.ResponseWriter, r *http.Request) *BASession {
// Find the session ID:
var sessionID string
// - #1: look at the value of the "sessid" cookie in the Cookie HTTP header
if c, err := r.Cookie(SESSION_ID_COOKIE_NAME); err == nil && regexp.MustCompile("^[0-9a-f]{40}").MatchString(c.Value) {
sessionID = c.Value
//log.Printf("BASessionStore Get(): got session ID from cookie: %s", sessionID)
// - #2: look at the value of the "sessid" key in the URL query string
} else if r.ParseForm(); r.Form[SESSION_ID_COOKIE_NAME] != nil && regexp.MustCompile("^[0-9a-f]{40}").MatchString(r.Form.Get(SESSION_ID_COOKIE_NAME)) {
sessionID = r.Form.Get(SESSION_ID_COOKIE_NAME)
//log.Printf("BASessionStore Get(): got session ID from query string: %s", sessionID)
// - Otherwise, no session ID was sent with this request: generate a new one
// based on the session ID salt in server.cfg, the remote IP and user agent
// string, and set it as the value of the "sessid" cookie
} else {
newSession := store.New(w, r)
//log.Printf("BASessionStore Get(): no session ID found, set new: %s", newSession.Id)
return newSession
}
return &BASession{
MemcachedClient: store.MemcachedClient,
Id: sessionID,
}
}
// =============================================================================
// BASession
// =============================================================================
type BASession struct {
MemcachedClient *memcache.Client
Id string
}
// Gets the value associated with the given key for this session; reading this
// value also implicitly deletes the key
func (session *BASession) Get(key string) (string, error) {
item, err := session.MemcachedClient.Get(session.Id + "|" + key)
if err != nil {
//log.Printf("BASession Get(): %s: error getting '%s': %s", session.Id, key, err)
return "", err
}
value := string(item.Value[:])
//log.Printf("BASession Get(): %s: value of key '%s' is '%s'", session.Id, key, value)
session.Delete(key)
return value, nil
}
// Sets the value associated with the given key for this session
func (session *BASession) Set(key string, value string) error {
item := memcache.Item{
Key: session.Id + "|" + key,
Value: []byte(value),
Expiration: 30,
}
if err := session.MemcachedClient.Set(&item); err != nil {
//log.Printf("BASession Set(): %s: error setting '%s': %s", session.Id, key, err)
return err
}
//log.Printf("BASession Set(): %s: value of key '%s' set to '%s'", session.Id, key, value)
return nil
}
// Deletes the value associated with the given key for this session
func (session *BASession) Delete(key string) error {
if err := session.MemcachedClient.Delete(session.Id + "|" + key); err != nil {
//log.Printf("BASession Delete(): %s: error deleting '%s': '%s'", session.Id, key, err)
return err
}
//log.Printf("BASession Delete(): %s: deleted key '%s'", session.Id, key)
return nil
}
// =============================================================================
// Miscellaneous functions
// =============================================================================
func SetSessionIDCookieHandler(w http.ResponseWriter, r *http.Request) {
DontCache(&w)
cookie := &http.Cookie{
Name: SESSION_ID_COOKIE_NAME,
Value: mux.Vars(r)["sessionID"],
Domain: r.Header["X-Host"][0],
Path: "/",
Expires: time.Now().Add(24 * time.Hour),
}
http.SetCookie(w, cookie)
http.ServeFile(w, r, "./static/pixel.png")
}