Commit 20ab9b42 authored by Sietse Ringers's avatar Sietse Ringers
Browse files

refactor: add session interface and memory-based implementation to keyshare server

For consistency with the irma server and myirma server and for a potential future
redis implementation.
parent 56054464
...@@ -5,7 +5,6 @@ import ( ...@@ -5,7 +5,6 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"strings" "strings"
"sync"
"time" "time"
"github.com/go-errors/errors" "github.com/go-errors/errors"
...@@ -24,12 +23,6 @@ import ( ...@@ -24,12 +23,6 @@ import (
"github.com/go-chi/chi" "github.com/go-chi/chi"
) )
type SessionData struct {
LastKeyID irma.PublicKeyIdentifier // last used key, used in signing the issuance message
LastCommitID uint64
expiry time.Time
}
type Server struct { type Server struct {
// configuration // configuration
conf *Configuration conf *Configuration
...@@ -44,15 +37,14 @@ type Server struct { ...@@ -44,15 +37,14 @@ type Server struct {
stopScheduler chan<- bool stopScheduler chan<- bool
// Session data, keeping track of current keyshare protocol session state for each user // Session data, keeping track of current keyshare protocol session state for each user
sessions map[string]*SessionData store sessionStore
sessionLock sync.Mutex
} }
func New(conf *Configuration) (*Server, error) { func New(conf *Configuration) (*Server, error) {
var err error var err error
s := &Server{ s := &Server{
conf: conf, conf: conf,
sessions: map[string]*SessionData{}, store: newMemorySessionStore(10 * time.Second),
scheduler: gocron.NewScheduler(), scheduler: gocron.NewScheduler(),
} }
...@@ -84,7 +76,7 @@ func New(conf *Configuration) (*Server, error) { ...@@ -84,7 +76,7 @@ func New(conf *Configuration) (*Server, error) {
s.db = conf.DB s.db = conf.DB
// Setup session cache clearing // Setup session cache clearing
s.scheduler.Every(10).Seconds().Do(s.clearSessions) s.scheduler.Every(10).Seconds().Do(s.store.flush)
s.stopScheduler = s.scheduler.Start() s.stopScheduler = s.scheduler.Start()
return s, nil return s, nil
...@@ -95,18 +87,6 @@ func (s *Server) Stop() { ...@@ -95,18 +87,6 @@ func (s *Server) Stop() {
s.sessionserver.Stop() s.sessionserver.Stop()
} }
// clean up any expired sessions
func (s *Server) clearSessions() {
now := time.Now()
s.sessionLock.Lock()
defer s.sessionLock.Unlock()
for k, v := range s.sessions {
if now.After(v.expiry) {
delete(s.sessions, k)
}
}
}
func (s *Server) Handler() http.Handler { func (s *Server) Handler() http.Handler {
router := chi.NewRouter() router := chi.NewRouter()
...@@ -210,21 +190,14 @@ func (s *Server) generateCommitments(user *KeyshareUser, authorization string, k ...@@ -210,21 +190,14 @@ func (s *Server) generateCommitments(user *KeyshareUser, authorization string, k
} }
// Store needed data for later requests. // Store needed data for later requests.
username := user.Username
s.sessionLock.Lock()
session, ok := s.sessions[username]
if !ok {
session = &SessionData{}
s.sessions[username] = session
}
// Of all keys involved in the current session, store the ID of the first one to be used when // Of all keys involved in the current session, store the ID of the first one to be used when
// the user comes back later to retrieve her response. gabi.ProofP.P will depend on this public // the user comes back later to retrieve her response. gabi.ProofP.P will depend on this public
// key, which is used only during issuance. Thus, this assumes that during issuance, the user // key, which is used only during issuance. Thus, this assumes that during issuance, the user
// puts the key ID of the credential(s) being issued at index 0. // puts the key ID of the credential(s) being issued at index 0.
session.LastKeyID = keys[0] s.store.add(user.Username, &SessionData{
session.LastCommitID = commitID LastKeyID: keys[0],
session.expiry = time.Now().Add(10 * time.Second) LastCommitID: commitID,
s.sessionLock.Unlock() })
// And send response // And send response
return &irma.ProofPCommitmentMap{Commitments: mappedCommitments}, nil return &irma.ProofPCommitmentMap{Commitments: mappedCommitments}, nil
...@@ -251,10 +224,8 @@ func (s *Server) handleResponse(w http.ResponseWriter, r *http.Request) { ...@@ -251,10 +224,8 @@ func (s *Server) handleResponse(w http.ResponseWriter, r *http.Request) {
} }
// Get data from session // Get data from session
s.sessionLock.Lock() sessionData := s.store.get(user.Username)
sessionData, ok := s.sessions[user.Username] if sessionData == nil {
s.sessionLock.Unlock()
if !ok {
s.conf.Logger.Warn("Request for response without previous call to get commitments") s.conf.Logger.Warn("Request for response without previous call to get commitments")
server.WriteError(w, server.ErrorInvalidRequest, "Missing previous call to getCommitments") server.WriteError(w, server.ErrorInvalidRequest, "Missing previous call to getCommitments")
return return
......
package keyshareserver
import (
"sync"
"time"
irma "github.com/privacybydesign/irmago"
)
type SessionData struct {
LastKeyID irma.PublicKeyIdentifier // last used key, used in signing the issuance message
LastCommitID uint64
expiry time.Time
}
type sessionStore interface {
add(username string, session *SessionData)
get(username string) *SessionData
flush()
}
type memorySessionStore struct {
sync.Mutex
data map[string]*SessionData
sessionLifetime time.Duration
}
func newMemorySessionStore(sessionLifetime time.Duration) sessionStore {
return &memorySessionStore{
sessionLifetime: sessionLifetime,
data: map[string]*SessionData{},
}
}
func (s *memorySessionStore) add(username string, session *SessionData) {
s.Lock()
defer s.Unlock()
session.expiry = time.Now().Add(s.sessionLifetime)
s.data[username] = session
}
func (s *memorySessionStore) get(username string) *SessionData {
s.Lock()
defer s.Unlock()
return s.data[username]
}
func (s *memorySessionStore) flush() {
now := time.Now()
s.Lock()
defer s.Unlock()
for k, v := range s.data {
if now.After(v.expiry) {
delete(s.data, k)
}
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment