Commit d6cf7ff0 authored by Sietse Ringers's avatar Sietse Ringers
Browse files

refactor: unexport keyshare server structs, interfaces and members where possible

parent 40ff4726
......@@ -18,7 +18,7 @@ import (
type DBType string
var ErrUnknownDBType = errors.New("Unknown database type")
var errUnknownDBType = errors.New("Unknown database type")
const (
DBTypeMemory = "memory"
......@@ -116,7 +116,7 @@ func processConfiguration(conf *Configuration) (*keysharecore.Core, error) {
return nil, server.LogError(err)
}
default:
return nil, server.LogError(ErrUnknownDBType)
return nil, server.LogError(errUnknownDBType)
}
}
......
......@@ -7,18 +7,18 @@ import (
)
var (
ErrUserAlreadyExists = errors.New("Cannot create user, username already taken")
ErrInvalidRecord = errors.New("Invalid record in database")
errUserAlreadyExists = errors.New("Cannot create user, username already taken")
errInvalidRecord = errors.New("Invalid record in database")
)
type EventType string
type eventType string
const (
EventTypePinCheckRefused EventType = "PIN_CHECK_REFUSED"
EventTypePinCheckSuccess EventType = "PIN_CHECK_SUCCESS"
EventTypePinCheckFailed EventType = "PIN_CHECK_FAILED"
EventTypePinCheckBlocked EventType = "PIN_CHECK_BLOCKED"
EventTypeIRMASession EventType = "IRMA_SESSION"
eventTypePinCheckRefused eventType = "PIN_CHECK_REFUSED"
eventTypePinCheckSuccess eventType = "PIN_CHECK_SUCCESS"
eventTypePinCheckFailed eventType = "PIN_CHECK_FAILED"
eventTypePinCheckBlocked eventType = "PIN_CHECK_BLOCKED"
eventTypeIRMASession eventType = "IRMA_SESSION"
)
// Interface used by server to manage data storage
......@@ -28,29 +28,29 @@ const (
type DB interface {
// User management
AddUser(user *User) error
User(username string) (*User, error)
UpdateUser(user *User) error
user(username string) (*User, error)
updateUser(user *User) error
// ReservePinTry reserves a pin check attempt, and additionally it returns:
// - allowed is whether the user is allowed to do the pin check (false if user is blocked)
// - tries is how many tries are remaining, after this pin check
// - wait is how long the user must wait before the next attempt is allowed if tries is 0
// ResetPinTries increases the user's try count and (if applicable) the date when the user
// resetPinTries increases the user's try count and (if applicable) the date when the user
// is unblocked again in the database, regardless of if the pin check succeeds after this
// invocation.
ReservePinTry(user *User) (allowed bool, tries int, wait int64, err error)
reservePinTry(user *User) (allowed bool, tries int, wait int64, err error)
// ResetPinTries resets the user's pin count and unblock date fields in the database to their
// resetPinTries resets the user's pin count and unblock date fields in the database to their
// default values (0 past attempts, no unblock date).
ResetPinTries(user *User) error
resetPinTries(user *User) error
// User activity registration
// SetSeen calls are used to track when a users account was last active, for deleting old accounts
SetSeen(user *User) error
AddLog(user *User, eventType EventType, param interface{}) error
setSeen(user *User) error
addLog(user *User, eventType eventType, param interface{}) error
// Store email verification tokens on registration
AddEmailVerification(user *User, emailAddress, token string) error
addEmailVerification(user *User, emailAddress, token string) error
}
// Actual data on a user used by this server.
......
......@@ -20,7 +20,7 @@ func NewMemoryDB() DB {
return &memoryDB{users: map[string]keysharecore.User{}}
}
func (db *memoryDB) User(username string) (*User, error) {
func (db *memoryDB) user(username string) (*User, error) {
// Ensure access to database is single-threaded
db.lock.Lock()
defer db.lock.Unlock()
......@@ -41,13 +41,13 @@ func (db *memoryDB) AddUser(user *User) error {
// Check and insert user
_, exists := db.users[user.Username]
if exists {
return ErrUserAlreadyExists
return errUserAlreadyExists
}
db.users[user.Username] = user.UserData
return nil
}
func (db *memoryDB) UpdateUser(user *User) error {
func (db *memoryDB) updateUser(user *User) error {
// Ensure access to database is single-threaded
db.lock.Lock()
defer db.lock.Unlock()
......@@ -61,27 +61,27 @@ func (db *memoryDB) UpdateUser(user *User) error {
return nil
}
func (db *memoryDB) ReservePinTry(user *User) (bool, int, int64, error) {
func (db *memoryDB) reservePinTry(user *User) (bool, int, int64, error) {
// Since this is a testing DB, implementing anything more than always allow creates hastle
return true, 1, 0, nil
}
func (db *memoryDB) ResetPinTries(user *User) error {
func (db *memoryDB) resetPinTries(user *User) error {
// Since this is a testing DB, implementing anything more than always allow creates hastle
return nil
}
func (db *memoryDB) SetSeen(user *User) error {
func (db *memoryDB) setSeen(user *User) error {
// We don't need to do anything here, as this information cannot be extracted locally
return nil
}
func (db *memoryDB) AddLog(user *User, eventType EventType, param interface{}) error {
func (db *memoryDB) addLog(user *User, eventType eventType, param interface{}) error {
// We don't need to do anything here, as this information cannot be extracted locally
return nil
}
func (db *memoryDB) AddEmailVerification(user *User, emailAddress, token string) error {
func (db *memoryDB) addEmailVerification(user *User, emailAddress, token string) error {
// We don't need to do anything here, as this information cannot be extracted locally
return nil
}
......@@ -15,32 +15,32 @@ func TestMemoryDBUserManagement(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, "testuser", user.Username)
nuser, err := db.User("testuser")
nuser, err := db.user("testuser")
require.NoError(t, err)
assert.Equal(t, "testuser", nuser.Username)
_, err = db.User("nonexistent")
_, err = db.user("nonexistent")
assert.Error(t, err)
user = &User{Username: "testuser"}
err = db.AddUser(user)
assert.Error(t, err)
err = db.UpdateUser(nuser)
err = db.updateUser(nuser)
assert.NoError(t, err)
err = db.AddEmailVerification(nuser, "test@test.com", "testtoken")
err = db.addEmailVerification(nuser, "test@test.com", "testtoken")
assert.NoError(t, err)
err = db.AddLog(nuser, EventTypePinCheckSuccess, nil)
err = db.addLog(nuser, eventTypePinCheckSuccess, nil)
assert.NoError(t, err)
ok, tries, wait, err := db.ReservePinTry(nuser)
ok, tries, wait, err := db.reservePinTry(nuser)
assert.NoError(t, err)
assert.True(t, ok)
assert.True(t, tries > 0)
assert.Equal(t, int64(0), wait)
err = db.SetSeen(nuser)
err = db.setSeen(nuser)
assert.NoError(t, err)
}
......@@ -53,7 +53,7 @@ func (db *postgresDB) AddUser(user *User) error {
if err = res.Err(); err != nil {
return err
}
return ErrUserAlreadyExists
return errUserAlreadyExists
}
var id int64
err = res.Scan(&id)
......@@ -64,7 +64,7 @@ func (db *postgresDB) AddUser(user *User) error {
return nil
}
func (db *postgresDB) User(username string) (*User, error) {
func (db *postgresDB) user(username string) (*User, error) {
var result User
var ep []byte
err := db.db.QueryUser(
......@@ -76,13 +76,13 @@ func (db *postgresDB) User(username string) (*User, error) {
return nil, err
}
if len(ep) != len(result.UserData[:]) {
return nil, ErrInvalidRecord
return nil, errInvalidRecord
}
copy(result.UserData[:], ep)
return &result, nil
}
func (db *postgresDB) UpdateUser(user *User) error {
func (db *postgresDB) updateUser(user *User) error {
return db.db.ExecUser(
"UPDATE irma.users SET username = $1, language = $2, coredata = $3 WHERE id=$4",
user.Username,
......@@ -92,7 +92,7 @@ func (db *postgresDB) UpdateUser(user *User) error {
)
}
func (db *postgresDB) ReservePinTry(user *User) (bool, int, int64, error) {
func (db *postgresDB) reservePinTry(user *User) (bool, int, int64, error) {
// Check that account is not blocked already, and if not,
// update pinCounter and pinBlockDate
uprows, err := db.db.Query(`
......@@ -159,14 +159,14 @@ func (db *postgresDB) ReservePinTry(user *User) (bool, int, int64, error) {
return allowed, tries, wait, nil
}
func (db *postgresDB) ResetPinTries(user *User) error {
func (db *postgresDB) resetPinTries(user *User) error {
return db.db.ExecUser(
"UPDATE irma.users SET pin_counter = 0, pin_block_date = 0 WHERE id = $1",
user.id,
)
}
func (db *postgresDB) SetSeen(user *User) error {
func (db *postgresDB) setSeen(user *User) error {
return db.db.ExecUser(
"UPDATE irma.users SET last_seen = $1 WHERE id = $2",
time.Now().Unix(),
......@@ -174,7 +174,7 @@ func (db *postgresDB) SetSeen(user *User) error {
)
}
func (db *postgresDB) AddLog(user *User, eventType EventType, param interface{}) error {
func (db *postgresDB) addLog(user *User, eventType eventType, param interface{}) error {
var encodedParamString *string
if param != nil {
encodedParam, err := json.Marshal(param)
......@@ -193,7 +193,7 @@ func (db *postgresDB) AddLog(user *User, eventType EventType, param interface{})
return err
}
func (db *postgresDB) AddEmailVerification(user *User, emailAddress, token string) error {
func (db *postgresDB) addEmailVerification(user *User, emailAddress, token string) error {
_, err := db.db.Exec("INSERT INTO irma.email_verification_tokens (token, email, user_id, expiry) VALUES ($1, $2, $3, $4)",
token,
emailAddress,
......
......@@ -23,27 +23,27 @@ func TestPostgresDBUserManagement(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, "testuser", user.Username)
nuser, err := db.User("testuser")
nuser, err := db.user("testuser")
require.NoError(t, err)
assert.Equal(t, "testuser", nuser.Username)
_, err = db.User("notexist")
_, err = db.user("notexist")
assert.Error(t, err)
err = db.UpdateUser(nuser)
err = db.updateUser(nuser)
assert.NoError(t, err)
user = &User{Username: "testuser"}
err = db.AddUser(user)
assert.Error(t, err)
err = db.AddLog(nuser, EventTypePinCheckFailed, 15)
err = db.addLog(nuser, eventTypePinCheckFailed, 15)
assert.NoError(t, err)
err = db.AddEmailVerification(nuser, "test@example.com", "testtoken")
err = db.addEmailVerification(nuser, "test@example.com", "testtoken")
assert.NoError(t, err)
err = db.SetSeen(nuser)
err = db.setSeen(nuser)
assert.NoError(t, err)
}
......@@ -60,12 +60,12 @@ func TestPostgresDBPinReservation(t *testing.T) {
err = db.AddUser(user)
require.NoError(t, err)
// ReservePinTry sets user fields in the database as if the attempt was wrong. If the attempt
// reservePinTry sets user fields in the database as if the attempt was wrong. If the attempt
// was in fact correct, then these fields are cleared again later by the keyshare server by
// invoking db.ResetPinTries(user). So below we may think of ReservePinTry invocations as
// invoking db.resetPinTries(user). So below we may think of reservePinTry invocations as
// wrong pin attempts.
ok, tries, wait, err := db.ReservePinTry(user)
ok, tries, wait, err := db.reservePinTry(user)
require.NoError(t, err)
assert.True(t, ok)
assert.Equal(t, maxPinTries-1, tries)
......@@ -73,7 +73,7 @@ func TestPostgresDBPinReservation(t *testing.T) {
// Try until we have no tries left
for tries != 0 {
ok, tries, wait, err = db.ReservePinTry(user)
ok, tries, wait, err = db.reservePinTry(user)
require.NoError(t, err)
assert.True(t, ok)
}
......@@ -84,7 +84,7 @@ func TestPostgresDBPinReservation(t *testing.T) {
time.Sleep(time.Duration(wait-1) * time.Second)
// Try again, not yet allowed
ok, tries, wait, err = db.ReservePinTry(user)
ok, tries, wait, err = db.reservePinTry(user)
assert.NoError(t, err)
assert.False(t, ok)
assert.Equal(t, 0, tries)
......@@ -94,14 +94,14 @@ func TestPostgresDBPinReservation(t *testing.T) {
time.Sleep(2 * time.Second)
// Trying is now allowed
ok, tries, wait, err = db.ReservePinTry(user)
ok, tries, wait, err = db.reservePinTry(user)
assert.NoError(t, err)
assert.True(t, ok)
assert.Equal(t, 0, tries)
assert.Equal(t, 2*backoffStart, wait) // next attempt after doubled timeout
// Since we just used another attempt we are now blocked again
ok, tries, wait, err = db.ReservePinTry(user)
ok, tries, wait, err = db.reservePinTry(user)
assert.NoError(t, err)
assert.False(t, ok)
assert.Equal(t, 0, tries)
......@@ -111,16 +111,16 @@ func TestPostgresDBPinReservation(t *testing.T) {
time.Sleep(time.Duration(wait+1) * time.Second)
// Try a final time
ok, tries, wait, err = db.ReservePinTry(user)
ok, tries, wait, err = db.reservePinTry(user)
assert.NoError(t, err)
assert.True(t, ok)
assert.Equal(t, 0, tries)
assert.Equal(t, 4*backoffStart, wait) // next attempt after again a doubled timeout
err = db.ResetPinTries(user)
err = db.resetPinTries(user)
assert.NoError(t, err)
ok, tries, wait, err = db.ReservePinTry(user)
ok, tries, wait, err = db.reservePinTry(user)
assert.NoError(t, err)
assert.True(t, ok)
assert.True(t, tries > 0)
......
......@@ -62,11 +62,11 @@ func New(conf *Configuration) (*Server, error) {
// Load neccessary idemix keys into core, and ensure that future updates
// to them are processed
if err = s.LoadIdemixKeys(conf.IrmaConfiguration); err != nil {
if err = s.loadIdemixKeys(conf.IrmaConfiguration); err != nil {
return nil, err
}
conf.IrmaConfiguration.UpdateListeners = append(conf.IrmaConfiguration.UpdateListeners, func(conf *irma.Configuration) {
if err := s.LoadIdemixKeys(conf); err != nil {
if err := s.loadIdemixKeys(conf); err != nil {
// run periodically; can only log the error here
_ = server.LogError(err)
}
......@@ -123,7 +123,7 @@ func (s *Server) Handler() http.Handler {
// On configuration changes, inform the keyshare core of any
// new IRMA issuer public keys.
func (s *Server) LoadIdemixKeys(conf *irma.Configuration) error {
func (s *Server) loadIdemixKeys(conf *irma.Configuration) error {
errs := multierror.Error{}
for _, issuer := range conf.Issuers {
keyIDs, err := conf.PublicKeyIndices(issuer.Identifier())
......@@ -194,7 +194,7 @@ func (s *Server) generateCommitments(user *User, authorization string, keys []ir
// 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
// puts the key ID of the credential(s) being issued at index 0.
s.store.add(user.Username, &Session{
s.store.add(user.Username, &session{
KeyID: keys[0],
CommitID: commitID,
})
......@@ -248,14 +248,14 @@ func (s *Server) handleResponse(w http.ResponseWriter, r *http.Request) {
func (s *Server) generateResponses(user *User, authorization string, challenge *big.Int, commitID uint64, keyID irma.PublicKeyIdentifier) (string, error) {
// Indicate activity on user account
err := s.db.SetSeen(user)
err := s.db.setSeen(user)
if err != nil {
s.conf.Logger.WithField("error", err).Error("Could not mark user as seen recently")
// Do not send to user
}
// Make log entry
err = s.db.AddLog(user, EventTypeIRMASession, nil)
err = s.db.addLog(user, eventTypeIRMASession, nil)
if err != nil {
s.conf.Logger.WithField("error", err).Error("Could not add log entry for user")
return "", err
......@@ -289,7 +289,7 @@ func (s *Server) handleVerifyPin(w http.ResponseWriter, r *http.Request) {
}
// Fetch user
user, err := s.db.User(msg.Username)
user, err := s.db.user(msg.Username)
if err != nil {
s.conf.Logger.WithFields(logrus.Fields{"username": msg.Username, "error": err}).Warn("Could not find user in db")
server.WriteError(w, server.ErrorUserNotRegistered, "")
......@@ -327,13 +327,13 @@ func (s *Server) verifyPin(user *User, username, pin string) (irma.KeysharePinSt
if err == keysharecore.ErrInvalidPin {
// Handle invalid pin
err = s.db.AddLog(user, EventTypePinCheckFailed, tries)
err = s.db.addLog(user, eventTypePinCheckFailed, tries)
if err != nil {
s.conf.Logger.WithField("error", err).Error("Could not add log entry for user")
return irma.KeysharePinStatus{}, err
}
if tries == 0 {
err = s.db.AddLog(user, EventTypePinCheckBlocked, wait)
err = s.db.addLog(user, eventTypePinCheckBlocked, wait)
if err != nil {
s.conf.Logger.WithField("error", err).Error("Could not add log entry for user")
return irma.KeysharePinStatus{}, err
......@@ -345,17 +345,17 @@ func (s *Server) verifyPin(user *User, username, pin string) (irma.KeysharePinSt
}
// Handle success
err = s.db.ResetPinTries(user)
err = s.db.resetPinTries(user)
if err != nil {
s.conf.Logger.WithField("error", err).Error("Could not reset users pin check logic")
// Do not send to user
}
err = s.db.SetSeen(user)
err = s.db.setSeen(user)
if err != nil {
s.conf.Logger.WithField("error", err).Error("Could not indicate user activity")
// Do not send to user
}
err = s.db.AddLog(user, EventTypePinCheckSuccess, nil)
err = s.db.addLog(user, eventTypePinCheckSuccess, nil)
if err != nil {
s.conf.Logger.WithField("error", err).Error("Could not add log entry for user")
return irma.KeysharePinStatus{}, err
......@@ -374,7 +374,7 @@ func (s *Server) handleChangePin(w http.ResponseWriter, r *http.Request) {
}
// Fetch user
user, err := s.db.User(msg.Username)
user, err := s.db.user(msg.Username)
if err != nil {
s.conf.Logger.WithFields(logrus.Fields{"username": msg.Username, "error": err}).Warn("Could not find user in db")
server.WriteError(w, server.ErrorUserNotRegistered, "")
......@@ -414,14 +414,14 @@ func (s *Server) updatePin(user *User, oldPin, newPin string) (irma.KeysharePinS
}
// Mark pincheck as success, resetting users wait and count
err = s.db.ResetPinTries(user)
err = s.db.resetPinTries(user)
if err != nil {
s.conf.Logger.WithField("error", err).Error("Could not reset users pin check logic")
// Do not send to user
}
// Write user back
err = s.db.UpdateUser(user)
err = s.db.updateUser(user)
if err != nil {
s.conf.Logger.WithField("error", err).Error("Could not write updated user to database")
return irma.KeysharePinStatus{}, err
......@@ -500,7 +500,7 @@ func (s *Server) sendRegistrationEmail(user *User, language, email string) error
token := common.NewSessionToken()
// Add it to the database
err := s.db.AddEmailVerification(user, email, token)
err := s.db.addEmailVerification(user, email, token)
if err != nil {
s.conf.Logger.WithField("error", err).Error("Could not generate email verification mail record")
return err
......@@ -522,7 +522,7 @@ func (s *Server) userMiddleware(next http.Handler) http.Handler {
username := r.Header.Get("X-IRMA-Keyshare-Username")
// and fetch its information
user, err := s.db.User(username)
user, err := s.db.user(username)
if err != nil {
s.conf.Logger.WithFields(logrus.Fields{"username": username, "error": err}).Warn("Could not find user in db")
server.WriteError(w, server.ErrorUserNotRegistered, err.Error())
......@@ -556,13 +556,13 @@ func (s *Server) authorizationMiddleware(next http.Handler) http.Handler {
}
func (s *Server) reservePinCheck(user *User, pin string) (bool, int, int64, error) {
ok, tries, wait, err := s.db.ReservePinTry(user)
ok, tries, wait, err := s.db.reservePinTry(user)
if err != nil {
s.conf.Logger.WithField("error", err).Error("Could not reserve pin check slot")
return false, 0, 0, err
}
if !ok {
err = s.db.AddLog(user, EventTypePinCheckRefused, nil)
err = s.db.addLog(user, eventTypePinCheckRefused, nil)
if err != nil {
s.conf.Logger.WithField("error", err).Error("Could not add log entry for user")
return false, 0, 0, err
......
......@@ -333,32 +333,32 @@ func (db *testDB) AddUser(user *User) error {
return db.db.AddUser(user)
}
func (db *testDB) User(username string) (*User, error) {
return db.db.User(username)
func (db *testDB) user(username string) (*User, error) {
return db.db.user(username)
}
func (db *testDB) UpdateUser(user *User) error {
return db.db.UpdateUser(user)
func (db *testDB) updateUser(user *User) error {
return db.db.updateUser(user)
}
func (db *testDB) ReservePinTry(user *User) (bool, int, int64, error) {
func (db *testDB) reservePinTry(user *User) (bool, int, int64, error) {
return db.ok, db.tries, db.wait, db.err
}
func (db *testDB) ResetPinTries(user *User) error {
return db.db.ResetPinTries(user)
func (db *testDB) resetPinTries(user *User) error {
return db.db.resetPinTries(user)
}
func (db *testDB) SetSeen(user *User) error {
return db.db.SetSeen(user)
func (db *testDB) setSeen(user *User) error {
return db.db.setSeen(user)
}
func (db *testDB) AddLog(user *User, entrytype EventType, params interface{}) error {
return db.db.AddLog(user, entrytype, params)
func (db *testDB) addLog(user *User, entrytype eventType, params interface{}) error {
return db.db.addLog(user, entrytype, params)
}
func (db *testDB) AddEmailVerification(user *User, email, token string) error {
return db.db.AddEmailVerification(user, email, token)
func (db *testDB) addEmailVerification(user *User, email, token string) error {
return db.db.addEmailVerification(user, email, token)
}
func createDB(t *testing.T) DB {
......
......@@ -7,40 +7,40 @@ import (
irma "github.com/privacybydesign/irmago"
)
type Session struct {
type session struct {
KeyID irma.PublicKeyIdentifier // last used key, used in signing the issuance message
CommitID uint64
expiry time.Time
}
type sessionStore interface {
add(username string, session *Session)
get(username string) *Session
add(username string, session *session)
get(username string) *session
flush()
}
type memorySessionStore struct {
sync.Mutex
sessions map[string]*Session
sessions map[string]*session
sessionLifetime time.Duration
}
func newMemorySessionStore(sessionLifetime time.Duration) sessionStore {
r