From 8aeddf1795ba813690061fabe5df259af8fa73af Mon Sep 17 00:00:00 2001 From: Kailash Nadh Date: Thu, 9 May 2024 13:20:15 +0530 Subject: [PATCH] Remove `simplession.Session` dependency from `Store` interface{} to /v2. This is a breaking change. It removes the superfluous dependency stores had on the simplesessions package solely for accessing string generation functions, which are not needed in sessions. ID generation is the purview of individual store implementations. It also adds a go.mod to the `conv` package as its referenced by several stores. --- conv/go.mod | 5 ++++ go.mod | 2 +- session.go | 70 +++++++++++++------------------------------------ session_test.go | 61 ------------------------------------------ store.go | 19 ++++++-------- store_test.go | 20 ++++++-------- 6 files changed, 40 insertions(+), 137 deletions(-) create mode 100644 conv/go.mod diff --git a/conv/go.mod b/conv/go.mod new file mode 100644 index 0000000..cab6c20 --- /dev/null +++ b/conv/go.mod @@ -0,0 +1,5 @@ +module github.com/vividvilla/simplesessions/conv + +go 1.14 + +require github.com/stretchr/testify v1.9.0 diff --git a/go.mod b/go.mod index a58de16..3aa6170 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/vividvilla/simplesessions +module github.com/vividvilla/simplesessions/v2 require github.com/stretchr/testify v1.9.0 diff --git a/session.go b/session.go index 0ea0b50..d9aa116 100644 --- a/session.go +++ b/session.go @@ -1,11 +1,9 @@ package simplesessions import ( - "crypto/rand" "errors" "net/http" "time" - "unicode" ) // Session is utility for get, set or clear session. @@ -34,20 +32,25 @@ type Session struct { var ( // ErrInvalidSession is raised when session is tried to access before setting it or its not set in store. // Handle this and create new session. + // Store code = 1 ErrInvalidSession = errors.New("simplesession: invalid session") + // ErrFieldNotFound is raised when given key is not found in store + // Store code = 2 ErrFieldNotFound = errors.New("simplesession: session field not found in store") + // ErrAssertType is raised when type assertion fails + // Store code = 3 ErrAssertType = errors.New("simplesession: invalid type assertion") + // ErrNil is raised when returned value is nil. + // Store code = 4 ErrNil = errors.New("simplesession: nil returned") - // Dictionary for generating random string - dictionary = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" ) -// NewSession creates a new session. Reads cookie info from `GetCookie`` callback +// NewSession creates a new session. Reads cookie info from `GetCookie“ callback // and validate the session with current store. If cookie not set then it creates -// new session and calls `SetCookie`` callback. If `DisableAutoSet` is set then it +// new session and calls `SetCookie“ callback. If `DisableAutoSet` is set then it // skips new session creation and should be manually done using `Create` method. // If a cookie is found but its invalid in store then `ErrInvalidSession` error is returned. func NewSession(m *Manager, r, w interface{}) (*Session, error) { @@ -73,7 +76,7 @@ func NewSession(m *Manager, r, w interface{}) (*Session, error) { // Create new cookie in store and write to front // Store also calls `WriteCookie`` to write to http interface - cv, err := m.store.Create(sess) + cv, err := m.store.Create() if err != nil { return nil, err } @@ -89,49 +92,12 @@ func NewSession(m *Manager, r, w interface{}) (*Session, error) { return nil, err } - if isValid, err := m.store.IsValid(sess, sess.cookie.Value); err != nil { - return nil, err - } else if !isValid { - return nil, ErrInvalidSession - } - // Set isSet flag sess.isSet = true return sess, nil } -// GenerateRandomString is a utility method which can be used by store to -// generate cryptographically random alphanumeric string of length n. -func (s *Session) GenerateRandomString(n int) (string, error) { - var bytes = make([]byte, n) - if _, err := rand.Read(bytes); err != nil { - return "", err - } - - for k, v := range bytes { - bytes[k] = dictionary[v%byte(len(dictionary))] - } - - return string(bytes), nil -} - -// IsValidRandomString validates the random string generated by `GenerateRandomString` method. -func (s *Session) IsValidRandomString(val string) bool { - return s.isAlphaNum(val) -} - -// isAlphaNum checks if the provided string is Alphanumeric -func (s *Session) isAlphaNum(val string) bool { - for _, r := range val { - if !unicode.IsDigit(r) && !unicode.IsLetter(r) { - return false - } - } - - return true -} - // WriteCookie updates the cookie and calls `SetCookie` callback. // This method can also be used by store to update cookie whenever the cookie value changes. func (s *Session) WriteCookie(cv string) error { @@ -171,7 +137,7 @@ func (s *Session) clearCookie() error { // else session has to be manually created before setting or getting values. func (s *Session) Create() error { // Create new cookie in store and write to front. - cv, err := s.manager.store.Create(s) + cv, err := s.manager.store.Create() if err != nil { return err } @@ -221,7 +187,7 @@ func (s *Session) GetAll() (map[string]interface{}, error) { return s.values, nil } - return s.manager.store.GetAll(s, s.cookie.Value) + return s.manager.store.GetAll(s.cookie.Value) } // GetMulti gets a map of values for multiple session keys. @@ -243,7 +209,7 @@ func (s *Session) GetMulti(keys ...string) (map[string]interface{}, error) { return vals, nil } - return s.manager.store.GetMulti(s, s.cookie.Value, keys...) + return s.manager.store.GetMulti(s.cookie.Value, keys...) } // Get gets a value for given key in session. @@ -263,7 +229,7 @@ func (s *Session) Get(key string) (interface{}, error) { } // Get from backend if not found in previous step - return s.manager.store.Get(s, s.cookie.Value, key) + return s.manager.store.Get(s.cookie.Value, key) } // Set sets a value for given key in session. Its up to store to commit @@ -274,7 +240,7 @@ func (s *Session) Set(key string, val interface{}) error { return ErrInvalidSession } - return s.manager.store.Set(s, s.cookie.Value, key, val) + return s.manager.store.Set(s.cookie.Value, key, val) } // Commit commits all set to store. Its up to store to commit @@ -285,7 +251,7 @@ func (s *Session) Commit() error { return ErrInvalidSession } - return s.manager.store.Commit(s, s.cookie.Value) + return s.manager.store.Commit(s.cookie.Value) } // Delete deletes a field from session. @@ -295,7 +261,7 @@ func (s *Session) Delete(key string) error { return ErrInvalidSession } - return s.manager.store.Delete(s, s.cookie.Value, key) + return s.manager.store.Delete(s.cookie.Value, key) } // Clear clears session data from store and clears the cookie @@ -305,7 +271,7 @@ func (s *Session) Clear() error { return ErrInvalidSession } - if err := s.manager.store.Clear(s, s.cookie.Value); err != nil { + if err := s.manager.store.Clear(s.cookie.Value); err != nil { return err } diff --git a/session_test.go b/session_test.go index 903604f..d85d45e 100644 --- a/session_test.go +++ b/session_test.go @@ -2,7 +2,6 @@ package simplesessions import ( "errors" - "math/rand" "net/http" "testing" "time" @@ -83,43 +82,6 @@ func TestSessionHelpers(t *testing.T) { assert.Error(err, "test error") } -func TestSessionGenerateRandomString(t *testing.T) { - assert := assert.New(t) - sess := Session{} - - // Create random length string - rand.Seed(time.Now().Unix()) - strLen := rand.Intn(1000-1) + 1 - randStr, err := sess.GenerateRandomString(strLen) - assert.NoError(err) - assert.Equal(strLen, len(randStr)) - - // Check if it doesn't generate same id - randStr1, err := sess.GenerateRandomString(100) - assert.NoError(err) - randStr2, err := sess.GenerateRandomString(100) - assert.NoError(err) - assert.NotEqual(randStr1, randStr2) -} - -func TestSessionisAlphaNum(t *testing.T) { - assert := assert.New(t) - sess := Session{} - - assert.Equal(sess.isAlphaNum("thisisvalidstring"), true) - assert.Equal(sess.isAlphaNum("thisisNot$ a .validstring"), false) -} - -func TestSessionIsValidRandomString(t *testing.T) { - assert := assert.New(t) - sess := Session{} - - randStr, err := sess.GenerateRandomString(100) - assert.NoError(err) - assert.Equal(sess.IsValidRandomString(randStr), true) - assert.Equal(sess.IsValidRandomString(dictionary), true) -} - func TestSessionNewSession(t *testing.T) { reader := "some reader" writer := "some writer" @@ -140,16 +102,6 @@ func TestSessionNewSession(t *testing.T) { assert.True(sess.isSet) } -func TestSessionNewSessionInvalidSession(t *testing.T) { - assert := assert.New(t) - mockStore := newMockStore() - mockManager := newMockManager(mockStore) - - sess, err := NewSession(mockManager, nil, nil) - assert.Error(err, ErrInvalidSession.Error()) - assert.Nil(sess) -} - func TestSessionNewSessionErrorStoreCreate(t *testing.T) { assert := assert.New(t) mockStore := newMockStore() @@ -190,19 +142,6 @@ func TestSessionNewSessionErrorWriteCookie(t *testing.T) { assert.Nil(sess) } -func TestSessionNewSessionErrorStoreIsValid(t *testing.T) { - assert := assert.New(t) - mockStore := newMockStore() - mockManager := newMockManager(mockStore) - - testError := errors.New("this is test error") - mockStore.err = testError - - sess, err := NewSession(mockManager, nil, nil) - assert.Error(err, testError.Error()) - assert.Nil(sess) -} - func TestSessionNewSessionInvalidGetCookie(t *testing.T) { assert := assert.New(t) mockStore := newMockStore() diff --git a/store.go b/store.go index 6d15c3a..5f22791 100644 --- a/store.go +++ b/store.go @@ -3,33 +3,30 @@ package simplesessions // Store represents store interface. This interface can be // implemented to create various backend stores for session. type Store interface { - // IsExist checks if session is set in store. - IsValid(session *Session, cookieValue string) (isExist bool, err error) - // Create creates new session in store and returns the cookie value. - Create(session *Session) (cookieValue string, err error) + Create() (cookieValue string, err error) // Get gets a value for given key from session. - Get(session *Session, cookieValue, key string) (value interface{}, err error) + Get(cookieValue, key string) (value interface{}, err error) // GetMulti gets a maps of multiple values for given keys. - GetMulti(session *Session, cookieValue string, keys ...string) (values map[string]interface{}, err error) + GetMulti(cookieValue string, keys ...string) (values map[string]interface{}, err error) // GetAll gets all key and value from session, - GetAll(session *Session, cookieValue string) (values map[string]interface{}, err error) + GetAll(cookieValue string) (values map[string]interface{}, err error) // Set sets an value for a field in session. // Its up to store to either store it in session right after set or after commit. - Set(session *Session, cookieValue, key string, value interface{}) error + Set(cookieValue, key string, value interface{}) error // Commit commits all the previously set values to store. - Commit(session *Session, cookieValue string) error + Commit(cookieValue string) error // Delete a field from session. - Delete(session *Session, cookieValue string, key string) error + Delete(cookieValue string, key string) error // Clear clears the session key from backend if exists. - Clear(session *Session, cookieValue string) error + Clear(cookieValue string) error // Helper method for typecasting/asserting. Int(interface{}, error) (int, error) diff --git a/store_test.go b/store_test.go index e58cfa7..4eba6fe 100644 --- a/store_test.go +++ b/store_test.go @@ -17,46 +17,42 @@ func (s *MockStore) reset() { s.isCommited = false } -func (s *MockStore) IsValid(ss *Session, cv string) (isExist bool, err error) { - return s.isValid, s.err -} - -func (s *MockStore) Create(ss *Session) (cv string, err error) { +func (s *MockStore) Create() (cv string, err error) { return s.val.(string), s.err } -func (s *MockStore) Get(ss *Session, cv, key string) (value interface{}, err error) { +func (s *MockStore) Get(cv, key string) (value interface{}, err error) { return s.val, s.err } -func (s *MockStore) GetMulti(ss *Session, cv string, keys ...string) (values map[string]interface{}, err error) { +func (s *MockStore) GetMulti(cv string, keys ...string) (values map[string]interface{}, err error) { vals := make(map[string]interface{}) vals["val"] = s.val return vals, s.err } -func (s *MockStore) GetAll(ss *Session, cv string) (values map[string]interface{}, err error) { +func (s *MockStore) GetAll(cv string) (values map[string]interface{}, err error) { vals := make(map[string]interface{}) vals["val"] = s.val return vals, s.err } -func (s *MockStore) Set(ss *Session, cv, key string, value interface{}) error { +func (s *MockStore) Set(cv, key string, value interface{}) error { s.val = value return s.err } -func (s *MockStore) Commit(ss *Session, cv string) error { +func (s *MockStore) Commit(cv string) error { s.isCommited = true return s.err } -func (s *MockStore) Delete(ss *Session, cv string, key string) error { +func (s *MockStore) Delete(cv string, key string) error { s.val = nil return s.err } -func (s *MockStore) Clear(ss *Session, cv string) error { +func (s *MockStore) Clear(cv string) error { s.val = nil return s.err }