Checkpoint: password reset, rule expiry, migrations
- Self-service and admin password-change endpoints
(PUT /v1/auth/password, PUT /v1/accounts/{id}/password)
- Policy rule time-scoped expiry (not_before / expires_at)
with migration 000006 and engine filtering
- golang-migrate integration; embedded SQL migrations
- PolicyRecord fieldalignment lint fix
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -128,14 +128,23 @@ func (db *DB) UpdateAccountStatus(accountID int64, status model.AccountStatus) e
|
||||
}
|
||||
|
||||
// UpdatePasswordHash updates the Argon2id password hash for an account.
|
||||
// Returns ErrNotFound if no active account with the given ID exists, consistent
|
||||
// with the RowsAffected checks in RevokeToken and RenewToken.
|
||||
func (db *DB) UpdatePasswordHash(accountID int64, hash string) error {
|
||||
_, err := db.sql.Exec(`
|
||||
result, err := db.sql.Exec(`
|
||||
UPDATE accounts SET password_hash = ?, updated_at = ?
|
||||
WHERE id = ?
|
||||
`, hash, now(), accountID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("db: update password hash: %w", err)
|
||||
}
|
||||
rows, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return fmt.Errorf("db: update password hash rows affected: %w", err)
|
||||
}
|
||||
if rows == 0 {
|
||||
return ErrNotFound
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -640,6 +649,23 @@ func (db *DB) RevokeAllUserTokens(accountID int64, reason string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// RevokeAllUserTokensExcept revokes all non-expired, non-revoked tokens for an
|
||||
// account except for the token identified by exceptJTI. Used by the
|
||||
// self-service password change flow to invalidate all other sessions while
|
||||
// keeping the caller's current session active.
|
||||
func (db *DB) RevokeAllUserTokensExcept(accountID int64, exceptJTI, reason string) error {
|
||||
n := now()
|
||||
_, err := db.sql.Exec(`
|
||||
UPDATE token_revocation
|
||||
SET revoked_at = ?, revoke_reason = ?
|
||||
WHERE account_id = ? AND jti != ? AND revoked_at IS NULL AND expires_at > ?
|
||||
`, n, nullString(reason), accountID, exceptJTI, n)
|
||||
if err != nil {
|
||||
return fmt.Errorf("db: revoke all tokens except %q for account %d: %w", exceptJTI, accountID, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// PruneExpiredTokens removes token_revocation rows that are past their expiry.
|
||||
// Returns the number of rows deleted.
|
||||
func (db *DB) PruneExpiredTokens() (int64, error) {
|
||||
|
||||
Reference in New Issue
Block a user