Add timestamps to accounts and wallets tables
To help diagnosing/debugging in the future
This commit is contained in:
parent
448892cd82
commit
08d57db466
5 changed files with 86 additions and 47 deletions
|
@ -20,17 +20,21 @@ func expectAccountMatch(
|
||||||
seed auth.ClientSaltSeed,
|
seed auth.ClientSaltSeed,
|
||||||
expectedVerifyTokenString *auth.VerifyTokenString,
|
expectedVerifyTokenString *auth.VerifyTokenString,
|
||||||
approxVerifyExpiration *time.Time,
|
approxVerifyExpiration *time.Time,
|
||||||
|
approxCreated time.Time,
|
||||||
|
approxUpdated time.Time,
|
||||||
) {
|
) {
|
||||||
var key auth.KDFKey
|
var key auth.KDFKey
|
||||||
var salt auth.ServerSalt
|
var salt auth.ServerSalt
|
||||||
var email auth.Email
|
var email auth.Email
|
||||||
var verifyExpiration *time.Time
|
var verifyExpiration *time.Time
|
||||||
var verifyTokenString *auth.VerifyTokenString
|
var verifyTokenString *auth.VerifyTokenString
|
||||||
|
var created time.Time
|
||||||
|
var updated time.Time
|
||||||
|
|
||||||
err := s.db.QueryRow(
|
err := s.db.QueryRow(
|
||||||
`SELECT key, server_salt, email, verify_token, verify_expiration from accounts WHERE normalized_email=? AND client_salt_seed=?`,
|
`SELECT key, server_salt, email, verify_token, verify_expiration, created, updated from accounts WHERE normalized_email=? AND client_salt_seed=?`,
|
||||||
normEmail, seed,
|
normEmail, seed,
|
||||||
).Scan(&key, &salt, &email, &verifyTokenString, &verifyExpiration)
|
).Scan(&key, &salt, &email, &verifyTokenString, &verifyExpiration, &created, &updated)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error finding account for: %s %s - %+v", normEmail, password, err)
|
t.Fatalf("Error finding account for: %s %s - %+v", normEmail, password, err)
|
||||||
}
|
}
|
||||||
|
@ -73,14 +77,32 @@ func expectAccountMatch(
|
||||||
if time.Second < expDiff || expDiff < -time.Second {
|
if time.Second < expDiff || expDiff < -time.Second {
|
||||||
t.Fatalf(
|
t.Fatalf(
|
||||||
"Verify expiration not as expected. Want approximately: %s Got: %s",
|
"Verify expiration not as expected. Want approximately: %s Got: %s",
|
||||||
verifyExpiration,
|
|
||||||
approxVerifyExpiration,
|
approxVerifyExpiration,
|
||||||
|
verifyExpiration,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if approxVerifyExpiration == nil && verifyExpiration != nil {
|
if approxVerifyExpiration == nil && verifyExpiration != nil {
|
||||||
t.Fatalf("Expected verify expiration to be nil. Got: %+v", verifyExpiration)
|
t.Fatalf("Expected verify expiration to be nil. Got: %+v", verifyExpiration)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expDiff := approxCreated.Sub(created)
|
||||||
|
if time.Second*2 < expDiff || expDiff < -time.Second*2 {
|
||||||
|
t.Fatalf(
|
||||||
|
"Created timestamp not as expected. Want approximately: %s Got: %s",
|
||||||
|
approxCreated,
|
||||||
|
created,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
expDiff = approxUpdated.Sub(updated)
|
||||||
|
if time.Second*2 < expDiff || expDiff < -time.Second*2 {
|
||||||
|
t.Fatalf(
|
||||||
|
"Updated timestamp not as expected. Want approximately: %s Got: %s",
|
||||||
|
approxUpdated,
|
||||||
|
updated,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func expectAccountNotExists(t *testing.T, s *Store, normEmail auth.NormalizedEmail) {
|
func expectAccountNotExists(t *testing.T, s *Store, normEmail auth.NormalizedEmail) {
|
||||||
|
@ -119,7 +141,7 @@ func TestStoreCreateAccount(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get and confirm the account we just put in
|
// Get and confirm the account we just put in
|
||||||
expectAccountMatch(t, &s, normEmail, email, password, seed, nil, nil)
|
expectAccountMatch(t, &s, normEmail, email, password, seed, nil, nil, time.Now().UTC(), time.Now().UTC())
|
||||||
|
|
||||||
newPassword := auth.Password("xyz")
|
newPassword := auth.Password("xyz")
|
||||||
|
|
||||||
|
@ -138,7 +160,7 @@ func TestStoreCreateAccount(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the email and same *first* password we successfully put in
|
// Get the email and same *first* password we successfully put in
|
||||||
expectAccountMatch(t, &s, normEmail, email, password, seed, nil, nil)
|
expectAccountMatch(t, &s, normEmail, email, password, seed, nil, nil, time.Now().UTC(), time.Now().UTC())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that I can use CreateAccount twice for different emails with no veriy token
|
// Test that I can use CreateAccount twice for different emails with no veriy token
|
||||||
|
@ -165,8 +187,8 @@ func TestStoreCreateAccountTwoVerifiedSucceed(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get and confirm the accounts we just put in
|
// Get and confirm the accounts we just put in
|
||||||
expectAccountMatch(t, &s, normEmail1, email1, password1, seed1, nil, nil)
|
expectAccountMatch(t, &s, normEmail1, email1, password1, seed1, nil, nil, time.Now().UTC(), time.Now().UTC())
|
||||||
expectAccountMatch(t, &s, normEmail2, email2, password2, seed2, nil, nil)
|
expectAccountMatch(t, &s, normEmail2, email2, password2, seed2, nil, nil, time.Now().UTC(), time.Now().UTC())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that I cannot use CreateAccount twice with the same verify token, but
|
// Test that I cannot use CreateAccount twice with the same verify token, but
|
||||||
|
@ -204,8 +226,8 @@ func TestStoreCreateAccountTwoSameVerfiyTokenFail(t *testing.T) {
|
||||||
|
|
||||||
// Get and confirm the accounts we just put in
|
// Get and confirm the accounts we just put in
|
||||||
approxVerifyExpiration := time.Now().Add(time.Hour * 24 * 2).UTC()
|
approxVerifyExpiration := time.Now().Add(time.Hour * 24 * 2).UTC()
|
||||||
expectAccountMatch(t, &s, normEmail1, email1, password1, seed1, &verifyToken1, &approxVerifyExpiration)
|
expectAccountMatch(t, &s, normEmail1, email1, password1, seed1, &verifyToken1, &approxVerifyExpiration, time.Now().UTC(), time.Now().UTC())
|
||||||
expectAccountMatch(t, &s, normEmail2, email2, password2, seed2, &verifyToken2, &approxVerifyExpiration)
|
expectAccountMatch(t, &s, normEmail2, email2, password2, seed2, &verifyToken2, &approxVerifyExpiration, time.Now().UTC(), time.Now().UTC())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try CreateAccount with a verification string, thus unverified
|
// Try CreateAccount with a verification string, thus unverified
|
||||||
|
@ -224,7 +246,7 @@ func TestStoreCreateAccountUnverified(t *testing.T) {
|
||||||
|
|
||||||
// Get and confirm the account we just put in
|
// Get and confirm the account we just put in
|
||||||
approxVerifyExpiration := time.Now().Add(time.Hour * 24 * 2).UTC()
|
approxVerifyExpiration := time.Now().Add(time.Hour * 24 * 2).UTC()
|
||||||
expectAccountMatch(t, &s, normEmail, email, password, seed, &verifyToken, &approxVerifyExpiration)
|
expectAccountMatch(t, &s, normEmail, email, password, seed, &verifyToken, &approxVerifyExpiration, time.Now().UTC(), time.Now().UTC())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test GetUserId for nonexisting email
|
// Test GetUserId for nonexisting email
|
||||||
|
@ -380,12 +402,12 @@ func TestUpdateVerifyTokenStringSuccess(t *testing.T) {
|
||||||
if err := s.UpdateVerifyTokenString(lowerEmail, verifyTokenString2); err != nil {
|
if err := s.UpdateVerifyTokenString(lowerEmail, verifyTokenString2); err != nil {
|
||||||
t.Fatalf("Unexpected error in UpdateVerifyTokenString: err: %+v", err)
|
t.Fatalf("Unexpected error in UpdateVerifyTokenString: err: %+v", err)
|
||||||
}
|
}
|
||||||
expectAccountMatch(t, &s, normEmail, email, password, createdSeed, &verifyTokenString2, &approxVerifyExpiration)
|
expectAccountMatch(t, &s, normEmail, email, password, createdSeed, &verifyTokenString2, &approxVerifyExpiration, time.Now().UTC(), time.Now().UTC())
|
||||||
|
|
||||||
if err := s.UpdateVerifyTokenString(upperEmail, verifyTokenString3); err != nil {
|
if err := s.UpdateVerifyTokenString(upperEmail, verifyTokenString3); err != nil {
|
||||||
t.Fatalf("Unexpected error in UpdateVerifyTokenString: err: %+v", err)
|
t.Fatalf("Unexpected error in UpdateVerifyTokenString: err: %+v", err)
|
||||||
}
|
}
|
||||||
expectAccountMatch(t, &s, normEmail, email, password, createdSeed, &verifyTokenString3, &approxVerifyExpiration)
|
expectAccountMatch(t, &s, normEmail, email, password, createdSeed, &verifyTokenString3, &approxVerifyExpiration, time.Now().UTC(), time.Now().UTC())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test UpdateVerifyTokenString for nonexisting email
|
// Test UpdateVerifyTokenString for nonexisting email
|
||||||
|
@ -428,7 +450,7 @@ func TestUpdateVerifyAccountSuccess(t *testing.T) {
|
||||||
if err := s.VerifyAccount(verifyTokenString); err != nil {
|
if err := s.VerifyAccount(verifyTokenString); err != nil {
|
||||||
t.Fatalf("Unexpected error in VerifyAccount: err: %+v", err)
|
t.Fatalf("Unexpected error in VerifyAccount: err: %+v", err)
|
||||||
}
|
}
|
||||||
expectAccountMatch(t, &s, normEmail, email, password, createdSeed, nil, nil)
|
expectAccountMatch(t, &s, normEmail, email, password, createdSeed, nil, nil, time.Now().UTC(), time.Now().UTC())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test VerifyAccount for nonexisting token
|
// Test VerifyAccount for nonexisting token
|
||||||
|
|
|
@ -28,11 +28,11 @@ func TestStoreChangePasswordSuccess(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = s.db.Exec(
|
_, err = s.db.Exec(
|
||||||
"INSERT INTO wallets (user_id, encrypted_wallet, sequence, hmac) VALUES(?,?,?,?)",
|
"INSERT INTO wallets (user_id, encrypted_wallet, sequence, hmac, updated) VALUES(?,?,?,?,datetime('now'))",
|
||||||
userId, "my-enc-wallet", 1, "my-hmac",
|
userId, "my-enc-wallet", 1, "my-hmac",
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error creating test wallet")
|
t.Fatalf("Error creating test wallet: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
newPassword := oldPassword + auth.Password("_new")
|
newPassword := oldPassword + auth.Password("_new")
|
||||||
|
@ -47,8 +47,8 @@ func TestStoreChangePasswordSuccess(t *testing.T) {
|
||||||
t.Errorf("ChangePasswordWithWallet (lower case email): unexpected error: %+v", err)
|
t.Errorf("ChangePasswordWithWallet (lower case email): unexpected error: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expectAccountMatch(t, &s, email.Normalize(), email, newPassword, newSeed, nil, nil)
|
expectAccountMatch(t, &s, email.Normalize(), email, newPassword, newSeed, nil, nil, time.Now().UTC(), time.Now().UTC())
|
||||||
expectWalletExists(t, &s, userId, encryptedWallet, sequence, hmac)
|
expectWalletExists(t, &s, userId, encryptedWallet, sequence, hmac, time.Now().UTC())
|
||||||
expectTokenNotExists(t, &s, token)
|
expectTokenNotExists(t, &s, token)
|
||||||
|
|
||||||
newNewPassword := newPassword + auth.Password("_new")
|
newNewPassword := newPassword + auth.Password("_new")
|
||||||
|
@ -63,7 +63,7 @@ func TestStoreChangePasswordSuccess(t *testing.T) {
|
||||||
t.Errorf("ChangePasswordWithWallet (upper case email): unexpected error: %+v", err)
|
t.Errorf("ChangePasswordWithWallet (upper case email): unexpected error: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expectAccountMatch(t, &s, email.Normalize(), email, newNewPassword, newNewSeed, nil, nil)
|
expectAccountMatch(t, &s, email.Normalize(), email, newNewPassword, newNewSeed, nil, nil, time.Now().UTC(), time.Now().UTC())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStoreChangePasswordErrors(t *testing.T) {
|
func TestStoreChangePasswordErrors(t *testing.T) {
|
||||||
|
@ -152,11 +152,11 @@ func TestStoreChangePasswordErrors(t *testing.T) {
|
||||||
|
|
||||||
if tc.hasWallet {
|
if tc.hasWallet {
|
||||||
_, err := s.db.Exec(
|
_, err := s.db.Exec(
|
||||||
"INSERT INTO wallets (user_id, encrypted_wallet, sequence, hmac) VALUES(?,?,?,?)",
|
"INSERT INTO wallets (user_id, encrypted_wallet, sequence, hmac, updated) VALUES(?,?,?,?,datetime('now'))",
|
||||||
userId, oldEncryptedWallet, oldSequence, oldHmac,
|
userId, oldEncryptedWallet, oldSequence, oldHmac,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error creating test wallet")
|
t.Fatalf("Error creating test wallet: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,9 +173,9 @@ func TestStoreChangePasswordErrors(t *testing.T) {
|
||||||
// This tests the transaction rollbacks in particular, given the errors
|
// This tests the transaction rollbacks in particular, given the errors
|
||||||
// that are at a couple different stages of the txn, triggered by these
|
// that are at a couple different stages of the txn, triggered by these
|
||||||
// tests.
|
// tests.
|
||||||
expectAccountMatch(t, &s, email.Normalize(), email, oldPassword, oldSeed, tc.verifyToken, tc.verifyExpiration)
|
expectAccountMatch(t, &s, email.Normalize(), email, oldPassword, oldSeed, tc.verifyToken, tc.verifyExpiration, time.Now().UTC(), time.Now().UTC())
|
||||||
if tc.hasWallet {
|
if tc.hasWallet {
|
||||||
expectWalletExists(t, &s, userId, oldEncryptedWallet, oldSequence, oldHmac)
|
expectWalletExists(t, &s, userId, oldEncryptedWallet, oldSequence, oldHmac, time.Now().UTC())
|
||||||
} else {
|
} else {
|
||||||
expectWalletNotExists(t, &s, userId)
|
expectWalletNotExists(t, &s, userId)
|
||||||
}
|
}
|
||||||
|
@ -208,7 +208,7 @@ func TestStoreChangePasswordNoWalletSuccess(t *testing.T) {
|
||||||
t.Errorf("ChangePasswordNoWallet (lower case email): unexpected error: %+v", err)
|
t.Errorf("ChangePasswordNoWallet (lower case email): unexpected error: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expectAccountMatch(t, &s, email.Normalize(), email, newPassword, newSeed, nil, nil)
|
expectAccountMatch(t, &s, email.Normalize(), email, newPassword, newSeed, nil, nil, time.Now().UTC(), time.Now().UTC())
|
||||||
expectWalletNotExists(t, &s, userId)
|
expectWalletNotExists(t, &s, userId)
|
||||||
expectTokenNotExists(t, &s, token)
|
expectTokenNotExists(t, &s, token)
|
||||||
|
|
||||||
|
@ -221,7 +221,7 @@ func TestStoreChangePasswordNoWalletSuccess(t *testing.T) {
|
||||||
t.Errorf("ChangePasswordNoWallet (upper case email): unexpected error: %+v", err)
|
t.Errorf("ChangePasswordNoWallet (upper case email): unexpected error: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expectAccountMatch(t, &s, email.Normalize(), email, newNewPassword, newNewSeed, nil, nil)
|
expectAccountMatch(t, &s, email.Normalize(), email, newNewPassword, newNewSeed, nil, nil, time.Now().UTC(), time.Now().UTC())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStoreChangePasswordNoWalletErrors(t *testing.T) {
|
func TestStoreChangePasswordNoWalletErrors(t *testing.T) {
|
||||||
|
@ -295,11 +295,11 @@ func TestStoreChangePasswordNoWalletErrors(t *testing.T) {
|
||||||
|
|
||||||
if tc.hasWallet {
|
if tc.hasWallet {
|
||||||
_, err := s.db.Exec(
|
_, err := s.db.Exec(
|
||||||
"INSERT INTO wallets (user_id, encrypted_wallet, sequence, hmac) VALUES(?,?,?,?)",
|
"INSERT INTO wallets (user_id, encrypted_wallet, sequence, hmac, updated) VALUES(?,?,?,?,datetime('now'))",
|
||||||
userId, encryptedWallet, sequence, hmac,
|
userId, encryptedWallet, sequence, hmac,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error creating test wallet")
|
t.Fatalf("Error creating test wallet: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,9 +316,9 @@ func TestStoreChangePasswordNoWalletErrors(t *testing.T) {
|
||||||
// deleted. This tests the transaction rollbacks in particular, given the
|
// deleted. This tests the transaction rollbacks in particular, given the
|
||||||
// errors that are at a couple different stages of the txn, triggered by
|
// errors that are at a couple different stages of the txn, triggered by
|
||||||
// these tests.
|
// these tests.
|
||||||
expectAccountMatch(t, &s, email.Normalize(), email, oldPassword, oldSeed, tc.verifyToken, tc.verifyExpiration)
|
expectAccountMatch(t, &s, email.Normalize(), email, oldPassword, oldSeed, tc.verifyToken, tc.verifyExpiration, time.Now().UTC(), time.Now().UTC())
|
||||||
if tc.hasWallet {
|
if tc.hasWallet {
|
||||||
expectWalletExists(t, &s, userId, encryptedWallet, sequence, hmac)
|
expectWalletExists(t, &s, userId, encryptedWallet, sequence, hmac, time.Now().UTC())
|
||||||
} else {
|
} else {
|
||||||
expectWalletNotExists(t, &s, userId)
|
expectWalletNotExists(t, &s, userId)
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,6 +111,8 @@ func (s *Store) Migrate() error {
|
||||||
encrypted_wallet TEXT NOT NULL,
|
encrypted_wallet TEXT NOT NULL,
|
||||||
sequence INTEGER NOT NULL,
|
sequence INTEGER NOT NULL,
|
||||||
hmac TEXT NOT NULL,
|
hmac TEXT NOT NULL,
|
||||||
|
updated DATETIME NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (user_id)
|
PRIMARY KEY (user_id)
|
||||||
FOREIGN KEY (user_id) REFERENCES accounts(user_id)
|
FOREIGN KEY (user_id) REFERENCES accounts(user_id)
|
||||||
CHECK (
|
CHECK (
|
||||||
|
@ -134,6 +136,8 @@ func (s *Store) Migrate() error {
|
||||||
|
|
||||||
verify_expiration DATETIME,
|
verify_expiration DATETIME,
|
||||||
user_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
user_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
created DATETIME DEFAULT (DATETIME('now')),
|
||||||
|
updated DATETIME NOT NULL,
|
||||||
CHECK (
|
CHECK (
|
||||||
email <> '' AND
|
email <> '' AND
|
||||||
normalized_email <> '' AND
|
normalized_email <> '' AND
|
||||||
|
@ -281,7 +285,7 @@ func (s *Store) insertFirstWallet(
|
||||||
// The database will enforce that this will not be set if this user already
|
// The database will enforce that this will not be set if this user already
|
||||||
// has a wallet.
|
// has a wallet.
|
||||||
_, err = s.db.Exec(
|
_, err = s.db.Exec(
|
||||||
"INSERT INTO wallets (user_id, encrypted_wallet, sequence, hmac) VALUES(?,?,?,?)",
|
"INSERT INTO wallets (user_id, encrypted_wallet, sequence, hmac, updated) VALUES(?,?,?,?, datetime('now'))",
|
||||||
userId, encryptedWallet, 1, hmac,
|
userId, encryptedWallet, 1, hmac,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -310,7 +314,7 @@ func (s *Store) updateWalletToSequence(
|
||||||
// This way, if two clients attempt to update at the same time, it will return
|
// This way, if two clients attempt to update at the same time, it will return
|
||||||
// an error for the second one.
|
// an error for the second one.
|
||||||
res, err := s.db.Exec(
|
res, err := s.db.Exec(
|
||||||
"UPDATE wallets SET encrypted_wallet=?, sequence=?, hmac=? WHERE user_id=? AND sequence=?",
|
"UPDATE wallets SET encrypted_wallet=?, sequence=?, hmac=?, updated=datetime('now') WHERE user_id=? AND sequence=?",
|
||||||
encryptedWallet, sequence, hmac, userId, sequence-1,
|
encryptedWallet, sequence, hmac, userId, sequence-1,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -403,7 +407,7 @@ func (s *Store) CreateAccount(email auth.Email, password auth.Password, seed aut
|
||||||
|
|
||||||
// userId auto-increments
|
// userId auto-increments
|
||||||
_, err = s.db.Exec(
|
_, err = s.db.Exec(
|
||||||
"INSERT INTO accounts (normalized_email, email, key, server_salt, client_salt_seed, verify_token, verify_expiration) VALUES(?,?,?,?,?,?,?)",
|
"INSERT INTO accounts (normalized_email, email, key, server_salt, client_salt_seed, verify_token, verify_expiration, updated) VALUES(?,?,?,?,?,?,?, datetime('now'))",
|
||||||
email.Normalize(), email, key, salt, seed, verifyToken, verifyExpiration,
|
email.Normalize(), email, key, salt, seed, verifyToken, verifyExpiration,
|
||||||
)
|
)
|
||||||
var sqliteErr sqlite3.Error
|
var sqliteErr sqlite3.Error
|
||||||
|
@ -426,7 +430,7 @@ func (s *Store) UpdateVerifyTokenString(email auth.Email, verifyTokenString auth
|
||||||
expiration := time.Now().UTC().Add(VerifyTokenLifespan)
|
expiration := time.Now().UTC().Add(VerifyTokenLifespan)
|
||||||
|
|
||||||
res, err := s.db.Exec(
|
res, err := s.db.Exec(
|
||||||
`UPDATE accounts SET verify_token=?, verify_expiration=? WHERE normalized_email=? and verify_token is not null`,
|
`UPDATE accounts SET verify_token=?, verify_expiration=?, updated=datetime('now') WHERE normalized_email=? and verify_token is not null`,
|
||||||
verifyTokenString, expiration, email.Normalize(),
|
verifyTokenString, expiration, email.Normalize(),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -457,7 +461,7 @@ func (s *Store) UpdateVerifyTokenString(email auth.Email, verifyTokenString auth
|
||||||
|
|
||||||
func (s *Store) VerifyAccount(verifyTokenString auth.VerifyTokenString) (err error) {
|
func (s *Store) VerifyAccount(verifyTokenString auth.VerifyTokenString) (err error) {
|
||||||
res, err := s.db.Exec(
|
res, err := s.db.Exec(
|
||||||
"UPDATE accounts SET verify_token=null, verify_expiration=null WHERE verify_token=?",
|
"UPDATE accounts SET verify_token=null, verify_expiration=null, updated=datetime('now') WHERE verify_token=?",
|
||||||
verifyTokenString,
|
verifyTokenString,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -585,7 +589,7 @@ func (s *Store) changePassword(
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := tx.Exec(
|
res, err := tx.Exec(
|
||||||
"UPDATE accounts SET key=?, server_salt=?, client_salt_seed=? WHERE user_id=?",
|
"UPDATE accounts SET key=?, server_salt=?, client_salt_seed=?, updated=datetime('now') WHERE user_id=?",
|
||||||
newKey, newSalt, clientSaltSeed, userId,
|
newKey, newSalt, clientSaltSeed, userId,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -605,7 +609,7 @@ func (s *Store) changePassword(
|
||||||
// With a wallet expected: update it.
|
// With a wallet expected: update it.
|
||||||
|
|
||||||
res, err = tx.Exec(
|
res, err = tx.Exec(
|
||||||
`UPDATE wallets SET encrypted_wallet=?, sequence=?, hmac=?
|
`UPDATE wallets SET encrypted_wallet=?, sequence=?, hmac=?, updated=datetime('now')
|
||||||
WHERE user_id=? AND sequence=?`,
|
WHERE user_id=? AND sequence=?`,
|
||||||
encryptedWallet, sequence, hmac, userId, sequence-1,
|
encryptedWallet, sequence, hmac, userId, sequence-1,
|
||||||
)
|
)
|
||||||
|
|
|
@ -51,7 +51,7 @@ func makeTestUser(
|
||||||
seed = auth.ClientSaltSeed("abcd1234abcd1234")
|
seed = auth.ClientSaltSeed("abcd1234abcd1234")
|
||||||
|
|
||||||
rows, err := s.db.Query(
|
rows, err := s.db.Query(
|
||||||
"INSERT INTO accounts (normalized_email, email, key, server_salt, client_salt_seed, verify_token, verify_expiration) values(?,?,?,?,?,?,?) returning user_id",
|
"INSERT INTO accounts (normalized_email, email, key, server_salt, client_salt_seed, verify_token, verify_expiration, updated) values(?,?,?,?,?,?,?, datetime('now')) returning user_id",
|
||||||
normEmail, email, key, salt, seed, verifyToken, verifyExpiration,
|
normEmail, email, key, salt, seed, verifyToken, verifyExpiration,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -3,6 +3,7 @@ package store
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/mattn/go-sqlite3"
|
"github.com/mattn/go-sqlite3"
|
||||||
|
|
||||||
|
@ -17,9 +18,10 @@ func expectWalletExists(
|
||||||
expectedEncryptedWallet wallet.EncryptedWallet,
|
expectedEncryptedWallet wallet.EncryptedWallet,
|
||||||
expectedSequence wallet.Sequence,
|
expectedSequence wallet.Sequence,
|
||||||
expectedHmac wallet.WalletHmac,
|
expectedHmac wallet.WalletHmac,
|
||||||
|
approxUpdated time.Time,
|
||||||
) {
|
) {
|
||||||
rows, err := s.db.Query(
|
rows, err := s.db.Query(
|
||||||
"SELECT encrypted_wallet, sequence, hmac FROM wallets WHERE user_id=?", userId)
|
"SELECT encrypted_wallet, sequence, hmac, updated FROM wallets WHERE user_id=?", userId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error finding wallet for user_id=%d: %+v", userId, err)
|
t.Fatalf("Error finding wallet for user_id=%d: %+v", userId, err)
|
||||||
}
|
}
|
||||||
|
@ -28,6 +30,7 @@ func expectWalletExists(
|
||||||
var encryptedWallet wallet.EncryptedWallet
|
var encryptedWallet wallet.EncryptedWallet
|
||||||
var sequence wallet.Sequence
|
var sequence wallet.Sequence
|
||||||
var hmac wallet.WalletHmac
|
var hmac wallet.WalletHmac
|
||||||
|
var updated time.Time
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
|
|
||||||
|
@ -35,6 +38,7 @@ func expectWalletExists(
|
||||||
&encryptedWallet,
|
&encryptedWallet,
|
||||||
&sequence,
|
&sequence,
|
||||||
&hmac,
|
&hmac,
|
||||||
|
&updated,
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -45,6 +49,15 @@ func expectWalletExists(
|
||||||
t.Fatalf("Unexpected values for wallet: encrypted wallet: %+v sequence: %+v hmac: %+v err: %+v", encryptedWallet, sequence, hmac, err)
|
t.Fatalf("Unexpected values for wallet: encrypted wallet: %+v sequence: %+v hmac: %+v err: %+v", encryptedWallet, sequence, hmac, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expDiff := approxUpdated.Sub(updated)
|
||||||
|
if time.Second*2 < expDiff || expDiff < -time.Second*2 {
|
||||||
|
t.Fatalf(
|
||||||
|
"Updated timestamp not as expected. Want approximately: %s Got: %s",
|
||||||
|
approxUpdated,
|
||||||
|
updated,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return // found a match, we're good
|
return // found a match, we're good
|
||||||
}
|
}
|
||||||
t.Fatalf("Expected wallet for user_id=%d: %+v", userId, err)
|
t.Fatalf("Expected wallet for user_id=%d: %+v", userId, err)
|
||||||
|
@ -97,7 +110,7 @@ func TestStoreInsertWallet(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a wallet, have the values we put in with a sequence of 1
|
// Get a wallet, have the values we put in with a sequence of 1
|
||||||
expectWalletExists(t, &s, userId, wallet.EncryptedWallet("my-enc-wallet"), wallet.Sequence(1), wallet.WalletHmac("my-hmac"))
|
expectWalletExists(t, &s, userId, wallet.EncryptedWallet("my-enc-wallet"), wallet.Sequence(1), wallet.WalletHmac("my-hmac"), time.Now().UTC())
|
||||||
|
|
||||||
// Put in a first wallet for a second time, have an error for trying
|
// Put in a first wallet for a second time, have an error for trying
|
||||||
if err := s.insertFirstWallet(userId, wallet.EncryptedWallet("my-enc-wallet-2"), wallet.WalletHmac("my-hmac-2")); err != ErrDuplicateWallet {
|
if err := s.insertFirstWallet(userId, wallet.EncryptedWallet("my-enc-wallet-2"), wallet.WalletHmac("my-hmac-2")); err != ErrDuplicateWallet {
|
||||||
|
@ -105,7 +118,7 @@ func TestStoreInsertWallet(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the same *first* wallet we successfully put in
|
// Get the same *first* wallet we successfully put in
|
||||||
expectWalletExists(t, &s, userId, wallet.EncryptedWallet("my-enc-wallet"), wallet.Sequence(1), wallet.WalletHmac("my-hmac"))
|
expectWalletExists(t, &s, userId, wallet.EncryptedWallet("my-enc-wallet"), wallet.Sequence(1), wallet.WalletHmac("my-hmac"), time.Now().UTC())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test updateWalletToSequence, using insertFirstWallet as a helper
|
// Test updateWalletToSequence, using insertFirstWallet as a helper
|
||||||
|
@ -139,7 +152,7 @@ func TestStoreUpdateWallet(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the same wallet we initially *inserted*, since it didn't update
|
// Get the same wallet we initially *inserted*, since it didn't update
|
||||||
expectWalletExists(t, &s, userId, wallet.EncryptedWallet("my-enc-wallet-a"), wallet.Sequence(1), wallet.WalletHmac("my-hmac-a"))
|
expectWalletExists(t, &s, userId, wallet.EncryptedWallet("my-enc-wallet-a"), wallet.Sequence(1), wallet.WalletHmac("my-hmac-a"), time.Now().UTC())
|
||||||
|
|
||||||
// Update the wallet successfully, with the right sequence
|
// Update the wallet successfully, with the right sequence
|
||||||
if err := s.updateWalletToSequence(userId, wallet.EncryptedWallet("my-enc-wallet-b"), wallet.Sequence(2), wallet.WalletHmac("my-hmac-b")); err != nil {
|
if err := s.updateWalletToSequence(userId, wallet.EncryptedWallet("my-enc-wallet-b"), wallet.Sequence(2), wallet.WalletHmac("my-hmac-b")); err != nil {
|
||||||
|
@ -147,7 +160,7 @@ func TestStoreUpdateWallet(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a wallet, have the values we put in
|
// Get a wallet, have the values we put in
|
||||||
expectWalletExists(t, &s, userId, wallet.EncryptedWallet("my-enc-wallet-b"), wallet.Sequence(2), wallet.WalletHmac("my-hmac-b"))
|
expectWalletExists(t, &s, userId, wallet.EncryptedWallet("my-enc-wallet-b"), wallet.Sequence(2), wallet.WalletHmac("my-hmac-b"), time.Now().UTC())
|
||||||
|
|
||||||
// Update the wallet again successfully
|
// Update the wallet again successfully
|
||||||
if err := s.updateWalletToSequence(userId, wallet.EncryptedWallet("my-enc-wallet-c"), wallet.Sequence(3), wallet.WalletHmac("my-hmac-c")); err != nil {
|
if err := s.updateWalletToSequence(userId, wallet.EncryptedWallet("my-enc-wallet-c"), wallet.Sequence(3), wallet.WalletHmac("my-hmac-c")); err != nil {
|
||||||
|
@ -155,7 +168,7 @@ func TestStoreUpdateWallet(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a wallet, have the values we put in
|
// Get a wallet, have the values we put in
|
||||||
expectWalletExists(t, &s, userId, wallet.EncryptedWallet("my-enc-wallet-c"), wallet.Sequence(3), wallet.WalletHmac("my-hmac-c"))
|
expectWalletExists(t, &s, userId, wallet.EncryptedWallet("my-enc-wallet-c"), wallet.Sequence(3), wallet.WalletHmac("my-hmac-c"), time.Now().UTC())
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE - the "behind the scenes" comments give a view of what we're expecting
|
// NOTE - the "behind the scenes" comments give a view of what we're expecting
|
||||||
|
@ -186,33 +199,33 @@ func TestStoreSetWallet(t *testing.T) {
|
||||||
if err := s.SetWallet(userId, wallet.EncryptedWallet("my-enc-wallet-a"), wallet.Sequence(1), wallet.WalletHmac("my-hmac-a")); err != nil {
|
if err := s.SetWallet(userId, wallet.EncryptedWallet("my-enc-wallet-a"), wallet.Sequence(1), wallet.WalletHmac("my-hmac-a")); err != nil {
|
||||||
t.Fatalf("Unexpected error in SetWallet: %+v", err)
|
t.Fatalf("Unexpected error in SetWallet: %+v", err)
|
||||||
}
|
}
|
||||||
expectWalletExists(t, &s, userId, wallet.EncryptedWallet("my-enc-wallet-a"), wallet.Sequence(1), wallet.WalletHmac("my-hmac-a"))
|
expectWalletExists(t, &s, userId, wallet.EncryptedWallet("my-enc-wallet-a"), wallet.Sequence(1), wallet.WalletHmac("my-hmac-a"), time.Now().UTC())
|
||||||
|
|
||||||
// Sequence 1 - fails - out of sequence (behind the scenes, tries to insert but there's something there already)
|
// Sequence 1 - fails - out of sequence (behind the scenes, tries to insert but there's something there already)
|
||||||
if err := s.SetWallet(userId, wallet.EncryptedWallet("my-enc-wallet-b"), wallet.Sequence(1), wallet.WalletHmac("my-hmac-b")); err != ErrWrongSequence {
|
if err := s.SetWallet(userId, wallet.EncryptedWallet("my-enc-wallet-b"), wallet.Sequence(1), wallet.WalletHmac("my-hmac-b")); err != ErrWrongSequence {
|
||||||
t.Fatalf(`SetWallet err: wanted "%+v", got "%+v"`, ErrWrongSequence, err)
|
t.Fatalf(`SetWallet err: wanted "%+v", got "%+v"`, ErrWrongSequence, err)
|
||||||
}
|
}
|
||||||
// Expect the *first* wallet to still be there
|
// Expect the *first* wallet to still be there
|
||||||
expectWalletExists(t, &s, userId, wallet.EncryptedWallet("my-enc-wallet-a"), wallet.Sequence(1), wallet.WalletHmac("my-hmac-a"))
|
expectWalletExists(t, &s, userId, wallet.EncryptedWallet("my-enc-wallet-a"), wallet.Sequence(1), wallet.WalletHmac("my-hmac-a"), time.Now().UTC())
|
||||||
|
|
||||||
// Sequence 3 - fails - out of sequence (behind the scenes: tries via update, which is appropriate here)
|
// Sequence 3 - fails - out of sequence (behind the scenes: tries via update, which is appropriate here)
|
||||||
if err := s.SetWallet(userId, wallet.EncryptedWallet("my-enc-wallet-b"), wallet.Sequence(3), wallet.WalletHmac("my-hmac-b")); err != ErrWrongSequence {
|
if err := s.SetWallet(userId, wallet.EncryptedWallet("my-enc-wallet-b"), wallet.Sequence(3), wallet.WalletHmac("my-hmac-b")); err != ErrWrongSequence {
|
||||||
t.Fatalf(`SetWallet err: wanted "%+v", got "%+v"`, ErrWrongSequence, err)
|
t.Fatalf(`SetWallet err: wanted "%+v", got "%+v"`, ErrWrongSequence, err)
|
||||||
}
|
}
|
||||||
// Expect the *first* wallet to still be there
|
// Expect the *first* wallet to still be there
|
||||||
expectWalletExists(t, &s, userId, wallet.EncryptedWallet("my-enc-wallet-a"), wallet.Sequence(1), wallet.WalletHmac("my-hmac-a"))
|
expectWalletExists(t, &s, userId, wallet.EncryptedWallet("my-enc-wallet-a"), wallet.Sequence(1), wallet.WalletHmac("my-hmac-a"), time.Now().UTC())
|
||||||
|
|
||||||
// Sequence 2 - succeeds - (behind the scenes, does an update. Tests successful update-after-insert)
|
// Sequence 2 - succeeds - (behind the scenes, does an update. Tests successful update-after-insert)
|
||||||
if err := s.SetWallet(userId, wallet.EncryptedWallet("my-enc-wallet-b"), wallet.Sequence(2), wallet.WalletHmac("my-hmac-b")); err != nil {
|
if err := s.SetWallet(userId, wallet.EncryptedWallet("my-enc-wallet-b"), wallet.Sequence(2), wallet.WalletHmac("my-hmac-b")); err != nil {
|
||||||
t.Fatalf("Unexpected error in SetWallet: %+v", err)
|
t.Fatalf("Unexpected error in SetWallet: %+v", err)
|
||||||
}
|
}
|
||||||
expectWalletExists(t, &s, userId, wallet.EncryptedWallet("my-enc-wallet-b"), wallet.Sequence(2), wallet.WalletHmac("my-hmac-b"))
|
expectWalletExists(t, &s, userId, wallet.EncryptedWallet("my-enc-wallet-b"), wallet.Sequence(2), wallet.WalletHmac("my-hmac-b"), time.Now().UTC())
|
||||||
|
|
||||||
// Sequence 3 - succeeds - (behind the scenes, does an update. Tests successful update-after-update. Maybe gratuitous?)
|
// Sequence 3 - succeeds - (behind the scenes, does an update. Tests successful update-after-update. Maybe gratuitous?)
|
||||||
if err := s.SetWallet(userId, wallet.EncryptedWallet("my-enc-wallet-c"), wallet.Sequence(3), wallet.WalletHmac("my-hmac-c")); err != nil {
|
if err := s.SetWallet(userId, wallet.EncryptedWallet("my-enc-wallet-c"), wallet.Sequence(3), wallet.WalletHmac("my-hmac-c")); err != nil {
|
||||||
t.Fatalf("Unexpected error in SetWallet: %+v", err)
|
t.Fatalf("Unexpected error in SetWallet: %+v", err)
|
||||||
}
|
}
|
||||||
expectWalletExists(t, &s, userId, wallet.EncryptedWallet("my-enc-wallet-c"), wallet.Sequence(3), wallet.WalletHmac("my-hmac-c"))
|
expectWalletExists(t, &s, userId, wallet.EncryptedWallet("my-enc-wallet-c"), wallet.Sequence(3), wallet.WalletHmac("my-hmac-c"), time.Now().UTC())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pretty simple, only two cases: wallet is there or it's not.
|
// Pretty simple, only two cases: wallet is there or it's not.
|
||||||
|
|
Loading…
Reference in a new issue