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

feat: combine two SQL queries into one when logging in user

parent 0c9ab4b9
......@@ -11,7 +11,7 @@ type MyirmaDB interface {
AddEmailLoginToken(email, token string) error
LoginTokenCandidates(token string) ([]LoginCandidate, error)
TryUserLoginToken(token, username string) (bool, error)
TryUserLoginToken(token, username string) (int64, bool, error)
UserInformation(id int64) (UserInformation, error)
Logs(id int64, offset int, amount int) ([]LogEntry, error)
......
......@@ -112,27 +112,27 @@ func (db *myirmaMemoryDB) LoginTokenCandidates(token string) ([]LoginCandidate,
return result, nil
}
func (db *myirmaMemoryDB) TryUserLoginToken(token, username string) (bool, error) {
func (db *myirmaMemoryDB) TryUserLoginToken(token, username string) (int64, bool, error) {
db.lock.Lock()
defer db.lock.Unlock()
email, ok := db.loginEmailTokens[token]
if !ok {
return false, nil
return 0, false, nil
}
user, ok := db.userData[username]
if !ok {
return false, keyshare.ErrUserNotFound
return 0, false, keyshare.ErrUserNotFound
}
for _, userEmail := range user.email {
if userEmail == email {
delete(db.loginEmailTokens, token)
return true, nil
return user.id, true, nil
}
}
return false, nil
return 0, false, nil
}
func (db *myirmaMemoryDB) UserInformation(id int64) (UserInformation, error) {
......
......@@ -82,18 +82,21 @@ func TestMemoryDBLoginToken(t *testing.T) {
_, err = db.LoginTokenCandidates("DNE")
assert.Error(t, err)
_, err = db.TryUserLoginToken("testtoken", "DNE")
_, _, err = db.TryUserLoginToken("testtoken", "DNE")
assert.Error(t, err)
ok, err := db.TryUserLoginToken("testtoken", "noemail")
id, ok, err := db.TryUserLoginToken("testtoken", "noemail")
assert.Equal(t, int64(0), id)
assert.NoError(t, err)
assert.False(t, ok)
ok, err = db.TryUserLoginToken("testtoken", "testuser")
id, ok, err = db.TryUserLoginToken("testtoken", "testuser")
assert.Equal(t, int64(15), id)
assert.NoError(t, err)
assert.True(t, ok)
ok, err = db.TryUserLoginToken("testtoken", "testuser")
id, ok, err = db.TryUserLoginToken("testtoken", "testuser")
assert.Equal(t, int64(0), id)
assert.NoError(t, err)
assert.False(t, ok)
}
......
......@@ -125,25 +125,26 @@ func (db *myirmaPostgresDB) LoginTokenCandidates(token string) ([]LoginCandidate
return candidates, nil
}
func (db *myirmaPostgresDB) TryUserLoginToken(token, username string) (bool, error) {
func (db *myirmaPostgresDB) TryUserLoginToken(token, username string) (int64, bool, error) {
var id int64
err := db.db.QueryUser(
`SELECT 1 FROM irma.users INNER JOIN irma.emails ON users.id = emails.user_id WHERE
`SELECT users.id FROM irma.users INNER JOIN irma.emails ON users.id = emails.user_id WHERE
username = $1 AND (emails.delete_on >= $3 OR emails.delete_on IS NULL) AND
email = (SELECT email FROM irma.email_login_tokens WHERE token = $2 AND expiry >= $3)`,
nil, username, token, time.Now().Unix())
[]interface{}{&id}, username, token, time.Now().Unix())
if err != nil {
return false, err
return 0, false, err
}
// Successfull deletion of the token can only occur once, so we use that to signal ok to login
aff, err := db.db.ExecCount("DELETE FROM irma.email_login_tokens WHERE token = $1", token)
if err != nil {
return false, err
return 0, false, err
}
if aff != 1 {
return false, nil
return 0, false, nil
}
return true, nil
return id, true, nil
}
func (db *myirmaPostgresDB) UserInformation(id int64) (UserInformation, error) {
......
......@@ -93,17 +93,18 @@ func TestPostgresDBLoginToken(t *testing.T) {
_, err = db.LoginTokenCandidates("DNE")
assert.Error(t, err)
_, err = db.TryUserLoginToken("testtoken", "DNE")
_, _, err = db.TryUserLoginToken("testtoken", "DNE")
assert.Error(t, err)
_, err = db.TryUserLoginToken("testtoken", "noemail")
_, _, err = db.TryUserLoginToken("testtoken", "noemail")
assert.Error(t, err)
ok, err := db.TryUserLoginToken("testtoken", "testuser")
id, ok, err := db.TryUserLoginToken("testtoken", "testuser")
assert.NoError(t, err)
assert.Equal(t, int64(15), id)
assert.True(t, ok)
_, err = db.TryUserLoginToken("testtoken", "testuser")
_, _, err = db.TryUserLoginToken("testtoken", "testuser")
assert.Error(t, err)
assert.NoError(t, db.AddEmail(17, "test@test.com"))
......
......@@ -279,7 +279,7 @@ type TokenLoginRequest struct {
}
func (s *Server) processTokenLogin(request TokenLoginRequest) (string, error) {
ok, err := s.db.TryUserLoginToken(request.Token, request.Username)
id, ok, err := s.db.TryUserLoginToken(request.Token, request.Username)
if err != nil && err != keyshare.ErrUserNotFound {
s.conf.Logger.WithField("error", err).Error("Could not login user using token")
return "", err
......@@ -288,11 +288,6 @@ func (s *Server) processTokenLogin(request TokenLoginRequest) (string, error) {
return "", keyshare.ErrUserNotFound
}
id, err := s.db.UserID(request.Username) // username is trusted, since it was validated by s.db.TryUserLoginToken
if err != nil {
s.conf.Logger.WithField("error", err).Error("Could not fetch userid for username validated in earlier step")
return "", err
}
session := s.store.create()
session.userID = &id
......
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