Skip to content

Commit dcf45ea

Browse files
committed
First commit
0 parents  commit dcf45ea

10 files changed

Lines changed: 1555 additions & 0 deletions

‎LICENSE‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
Copyright (c) 2016, Session
2+
All rights reserved.
3+
4+
Redistribution and use in source and binary forms, with or without
5+
modification, are permitted provided that the following conditions are met:
6+
7+
* Redistributions of source code must retain the above copyright notice, this
8+
list of conditions and the following disclaimer.
9+
10+
* Redistributions in binary form must reproduce the above copyright notice,
11+
this list of conditions and the following disclaimer in the documentation
12+
and/or other materials provided with the distribution.
13+
14+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

‎README.md‎

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
Session
2+
=======
3+
4+
> A branch is based on [beego session](https://github.com/astaxie/beego/tree/master/session)
5+
6+
[![GoDoc](https://godoc.org/gopkg.in/session.v1?status.svg)](https://godoc.org/gopkg.in/session.v1)
7+
8+
Session is a Go session manager. It can use many session providers. Just like the `database/sql` and `database/sql/driver`.
9+
10+
Get
11+
----
12+
13+
``` bash
14+
$ go get -u gopkg.in/session.v1
15+
```
16+
17+
Usage
18+
-----
19+
20+
``` go
21+
var globalSessions *session.Manager
22+
```
23+
24+
### Memory Store
25+
26+
``` go
27+
func init() {
28+
globalSessions, _ = session.NewManager("memory", `{"cookieName":"gosessionid","gclifetime":3600}`)
29+
go globalSessions.GC()
30+
}
31+
```
32+
33+
### File Store
34+
35+
``` go
36+
func init() {
37+
globalSessions, _ = session.NewManager("file",`{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"./tmp"}`)
38+
go globalSessions.GC()
39+
}
40+
```
41+
42+
### Cookie Store
43+
44+
``` go
45+
func init() {
46+
globalSessions, _ = session.NewManager(
47+
"cookie", `{"cookieName":"gosessionid","enableSetCookie":false,"gclifetime":3600,"ProviderConfig":"{\"cookieName\":\"gosessionid\",\"securityKey\":\"beegocookiehashkey\"}"}`)
48+
go globalSessions.GC()
49+
}
50+
```
51+
52+
License
53+
-------
54+
55+
```
56+
Copyright (c) 2016, Session
57+
All rights reserved.
58+
```

‎sess_cookie.go‎

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
// Copyright 2014 beego Author. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package session
16+
17+
import (
18+
"crypto/aes"
19+
"crypto/cipher"
20+
"encoding/json"
21+
"net/http"
22+
"net/url"
23+
"sync"
24+
)
25+
26+
var cookiepder = &CookieProvider{}
27+
28+
// CookieSessionStore Cookie SessionStore
29+
type CookieSessionStore struct {
30+
sid string
31+
values map[interface{}]interface{} // session data
32+
lock sync.RWMutex
33+
}
34+
35+
// Set value to cookie session.
36+
// the value are encoded as gob with hash block string.
37+
func (st *CookieSessionStore) Set(key, value interface{}) error {
38+
st.lock.Lock()
39+
defer st.lock.Unlock()
40+
st.values[key] = value
41+
return nil
42+
}
43+
44+
// Get value from cookie session
45+
func (st *CookieSessionStore) Get(key interface{}) interface{} {
46+
st.lock.RLock()
47+
defer st.lock.RUnlock()
48+
if v, ok := st.values[key]; ok {
49+
return v
50+
}
51+
return nil
52+
}
53+
54+
// Delete value in cookie session
55+
func (st *CookieSessionStore) Delete(key interface{}) error {
56+
st.lock.Lock()
57+
defer st.lock.Unlock()
58+
delete(st.values, key)
59+
return nil
60+
}
61+
62+
// Flush Clean all values in cookie session
63+
func (st *CookieSessionStore) Flush() error {
64+
st.lock.Lock()
65+
defer st.lock.Unlock()
66+
st.values = make(map[interface{}]interface{})
67+
return nil
68+
}
69+
70+
// SessionID Return id of this cookie session
71+
func (st *CookieSessionStore) SessionID() string {
72+
return st.sid
73+
}
74+
75+
// SessionRelease Write cookie session to http response cookie
76+
func (st *CookieSessionStore) SessionRelease(w http.ResponseWriter) {
77+
str, err := encodeCookie(cookiepder.block,
78+
cookiepder.config.SecurityKey,
79+
cookiepder.config.SecurityName,
80+
st.values)
81+
if err != nil {
82+
return
83+
}
84+
cookie := &http.Cookie{Name: cookiepder.config.CookieName,
85+
Value: url.QueryEscape(str),
86+
Path: "/",
87+
HttpOnly: true,
88+
Secure: cookiepder.config.Secure,
89+
MaxAge: cookiepder.config.Maxage}
90+
http.SetCookie(w, cookie)
91+
return
92+
}
93+
94+
type cookieConfig struct {
95+
SecurityKey string `json:"securityKey"`
96+
BlockKey string `json:"blockKey"`
97+
SecurityName string `json:"securityName"`
98+
CookieName string `json:"cookieName"`
99+
Secure bool `json:"secure"`
100+
Maxage int `json:"maxage"`
101+
}
102+
103+
// CookieProvider Cookie session provider
104+
type CookieProvider struct {
105+
maxlifetime int64
106+
config *cookieConfig
107+
block cipher.Block
108+
}
109+
110+
// SessionInit Init cookie session provider with max lifetime and config json.
111+
// maxlifetime is ignored.
112+
// json config:
113+
// securityKey - hash string
114+
// blockKey - gob encode hash string. it's saved as aes crypto.
115+
// securityName - recognized name in encoded cookie string
116+
// cookieName - cookie name
117+
// maxage - cookie max life time.
118+
func (pder *CookieProvider) SessionInit(maxlifetime int64, config string) error {
119+
pder.config = &cookieConfig{}
120+
err := json.Unmarshal([]byte(config), pder.config)
121+
if err != nil {
122+
return err
123+
}
124+
if pder.config.BlockKey == "" {
125+
pder.config.BlockKey = string(generateRandomKey(16))
126+
}
127+
if pder.config.SecurityName == "" {
128+
pder.config.SecurityName = string(generateRandomKey(20))
129+
}
130+
pder.block, err = aes.NewCipher([]byte(pder.config.BlockKey))
131+
if err != nil {
132+
return err
133+
}
134+
pder.maxlifetime = maxlifetime
135+
return nil
136+
}
137+
138+
// SessionRead Get SessionStore in cooke.
139+
// decode cooke string to map and put into SessionStore with sid.
140+
func (pder *CookieProvider) SessionRead(sid string) (Store, error) {
141+
maps, _ := decodeCookie(pder.block,
142+
pder.config.SecurityKey,
143+
pder.config.SecurityName,
144+
sid, pder.maxlifetime)
145+
if maps == nil {
146+
maps = make(map[interface{}]interface{})
147+
}
148+
rs := &CookieSessionStore{sid: sid, values: maps}
149+
return rs, nil
150+
}
151+
152+
// SessionExist Cookie session is always existed
153+
func (pder *CookieProvider) SessionExist(sid string) bool {
154+
return true
155+
}
156+
157+
// SessionRegenerate Implement method, no used.
158+
func (pder *CookieProvider) SessionRegenerate(oldsid, sid string) (Store, error) {
159+
return nil, nil
160+
}
161+
162+
// SessionDestroy Implement method, no used.
163+
func (pder *CookieProvider) SessionDestroy(sid string) error {
164+
return nil
165+
}
166+
167+
// SessionGC Implement method, no used.
168+
func (pder *CookieProvider) SessionGC() {
169+
return
170+
}
171+
172+
// SessionAll Implement method, return 0.
173+
func (pder *CookieProvider) SessionAll() int {
174+
return 0
175+
}
176+
177+
// SessionUpdate Implement method, no used.
178+
func (pder *CookieProvider) SessionUpdate(sid string) error {
179+
return nil
180+
}
181+
182+
func init() {
183+
Register("cookie", cookiepder)
184+
}

‎sess_cookie_test.go‎

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Copyright 2014 beego Author. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package session
16+
17+
import (
18+
"net/http"
19+
"net/http/httptest"
20+
"strings"
21+
"testing"
22+
)
23+
24+
func TestCookie(t *testing.T) {
25+
config := `{"cookieName":"gosessionid","enableSetCookie":false,"gclifetime":3600,"ProviderConfig":"{\"cookieName\":\"gosessionid\",\"securityKey\":\"beegocookiehashkey\"}"}`
26+
globalSessions, err := NewManager("cookie", config)
27+
if err != nil {
28+
t.Fatal("init cookie session err", err)
29+
}
30+
r, _ := http.NewRequest("GET", "/", nil)
31+
w := httptest.NewRecorder()
32+
sess, err := globalSessions.SessionStart(w, r)
33+
if err != nil {
34+
t.Fatal("set error,", err)
35+
}
36+
err = sess.Set("username", "astaxie")
37+
if err != nil {
38+
t.Fatal("set error,", err)
39+
}
40+
if username := sess.Get("username"); username != "astaxie" {
41+
t.Fatal("get username error")
42+
}
43+
sess.SessionRelease(w)
44+
if cookiestr := w.Header().Get("Set-Cookie"); cookiestr == "" {
45+
t.Fatal("setcookie error")
46+
} else {
47+
parts := strings.Split(strings.TrimSpace(cookiestr), ";")
48+
for k, v := range parts {
49+
nameval := strings.Split(v, "=")
50+
if k == 0 && nameval[0] != "gosessionid" {
51+
t.Fatal("error")
52+
}
53+
}
54+
}
55+
}
56+
57+
func TestDestorySessionCookie(t *testing.T) {
58+
config := `{"cookieName":"gosessionid","enableSetCookie":true,"gclifetime":3600,"ProviderConfig":"{\"cookieName\":\"gosessionid\",\"securityKey\":\"beegocookiehashkey\"}"}`
59+
globalSessions, err := NewManager("cookie", config)
60+
if err != nil {
61+
t.Fatal("init cookie session err", err)
62+
}
63+
64+
r, _ := http.NewRequest("GET", "/", nil)
65+
w := httptest.NewRecorder()
66+
session, err := globalSessions.SessionStart(w, r)
67+
if err != nil {
68+
t.Fatal("session start err,", err)
69+
}
70+
71+
// request again ,will get same sesssion id .
72+
r1, _ := http.NewRequest("GET", "/", nil)
73+
r1.Header.Set("Cookie", w.Header().Get("Set-Cookie"))
74+
w = httptest.NewRecorder()
75+
newSession, err := globalSessions.SessionStart(w, r1)
76+
if err != nil {
77+
t.Fatal("session start err,", err)
78+
}
79+
if newSession.SessionID() != session.SessionID() {
80+
t.Fatal("get cookie session id is not the same again.")
81+
}
82+
83+
// After destroy session , will get a new session id .
84+
globalSessions.SessionDestroy(w, r1)
85+
r2, _ := http.NewRequest("GET", "/", nil)
86+
r2.Header.Set("Cookie", w.Header().Get("Set-Cookie"))
87+
88+
w = httptest.NewRecorder()
89+
newSession, err = globalSessions.SessionStart(w, r2)
90+
if err != nil {
91+
t.Fatal("session start error")
92+
}
93+
if newSession.SessionID() == session.SessionID() {
94+
t.Fatal("after destroy session and reqeust again ,get cookie session id is same.")
95+
}
96+
}

0 commit comments

Comments
 (0)