@@ -20,6 +20,7 @@ type Querier interface { |
| 20 | // strictly greater. Returns rows affected — 0 means a replay attempt and | 20 | // strictly greater. Returns rows affected — 0 means a replay attempt and |
| 21 | // the caller should reject the code. | 21 | // the caller should reject the code. |
| 22 | BumpTOTPCounter(ctx context.Context, db DBTX, arg BumpTOTPCounterParams) (int64, error) | 22 | BumpTOTPCounter(ctx context.Context, db DBTX, arg BumpTOTPCounterParams) (int64, error) |
| | 23 | + BumpUserSessionEpoch(ctx context.Context, db DBTX, id int64) error |
| 23 | // Sets confirmed_at on a pending row. Returns the number of rows updated; | 24 | // Sets confirmed_at on a pending row. Returns the number of rows updated; |
| 24 | // callers MUST check this to handle the parallel-enrollment race | 25 | // callers MUST check this to handle the parallel-enrollment race |
| 25 | // (only one of two concurrent confirms wins). | 26 | // (only one of two concurrent confirms wins). |
@@ -31,9 +32,12 @@ type Querier interface { |
| 31 | // 0 means rejected. | 32 | // 0 means rejected. |
| 32 | ConsumeRecoveryCode(ctx context.Context, db DBTX, arg ConsumeRecoveryCodeParams) (int64, error) | 33 | ConsumeRecoveryCode(ctx context.Context, db DBTX, arg ConsumeRecoveryCodeParams) (int64, error) |
| 33 | CountActiveUserTokens(ctx context.Context, db DBTX, userID int64) (int64, error) | 34 | CountActiveUserTokens(ctx context.Context, db DBTX, userID int64) (int64, error) |
| | 35 | + // Drives the 3-changes-per-60d cap. |
| | 36 | + CountRecentUsernameChanges(ctx context.Context, db DBTX, arg CountRecentUsernameChangesParams) (int64, error) |
| 34 | CountUnusedRecoveryCodes(ctx context.Context, db DBTX, userID int64) (int64, error) | 37 | CountUnusedRecoveryCodes(ctx context.Context, db DBTX, userID int64) (int64, error) |
| 35 | CountUserSSHKeys(ctx context.Context, db DBTX, userID int64) (int64, error) | 38 | CountUserSSHKeys(ctx context.Context, db DBTX, userID int64) (int64, error) |
| 36 | CountUsers(ctx context.Context, db DBTX) (int64, error) | 39 | CountUsers(ctx context.Context, db DBTX) (int64, error) |
| | 40 | + CountVerifiedUserEmails(ctx context.Context, db DBTX, userID int64) (int64, error) |
| 37 | // SPDX-License-Identifier: AGPL-3.0-or-later | 41 | // SPDX-License-Identifier: AGPL-3.0-or-later |
| 38 | CreateEmailVerification(ctx context.Context, db DBTX, arg CreateEmailVerificationParams) (EmailVerification, error) | 42 | CreateEmailVerification(ctx context.Context, db DBTX, arg CreateEmailVerificationParams) (EmailVerification, error) |
| 39 | // SPDX-License-Identifier: AGPL-3.0-or-later | 43 | // SPDX-License-Identifier: AGPL-3.0-or-later |
@@ -44,6 +48,10 @@ type Querier interface { |
| 44 | CreateUserEmail(ctx context.Context, db DBTX, arg CreateUserEmailParams) (UserEmail, error) | 48 | CreateUserEmail(ctx context.Context, db DBTX, arg CreateUserEmailParams) (UserEmail, error) |
| 45 | DeleteExpiredEmailVerifications(ctx context.Context, db DBTX) error | 49 | DeleteExpiredEmailVerifications(ctx context.Context, db DBTX) error |
| 46 | DeleteExpiredPasswordResets(ctx context.Context, db DBTX) error | 50 | DeleteExpiredPasswordResets(ctx context.Context, db DBTX) error |
| | 51 | + // Scoped delete: caller must pass owning user_id. Refuses to delete |
| | 52 | + // the primary email (UI must guide the user to set a different primary first). |
| | 53 | + DeleteUserEmail(ctx context.Context, db DBTX, arg DeleteUserEmailParams) (int64, error) |
| | 54 | + DeleteUserNotificationPref(ctx context.Context, db DBTX, arg DeleteUserNotificationPrefParams) error |
| 47 | DeleteUserRecoveryCodes(ctx context.Context, db DBTX, userID int64) error | 55 | DeleteUserRecoveryCodes(ctx context.Context, db DBTX, userID int64) error |
| 48 | // Scoped delete: caller must pass the owning user_id so a hijacked | 56 | // Scoped delete: caller must pass the owning user_id so a hijacked |
| 49 | // handler can never delete keys it doesn't own. | 57 | // handler can never delete keys it doesn't own. |
@@ -53,12 +61,16 @@ type Querier interface { |
| 53 | GetPasswordResetByTokenHash(ctx context.Context, db DBTX, tokenHash []byte) (PasswordReset, error) | 61 | GetPasswordResetByTokenHash(ctx context.Context, db DBTX, tokenHash []byte) (PasswordReset, error) |
| 54 | GetUserByID(ctx context.Context, db DBTX, id int64) (User, error) | 62 | GetUserByID(ctx context.Context, db DBTX, id int64) (User, error) |
| 55 | GetUserByUsername(ctx context.Context, db DBTX, username string) (User, error) | 63 | GetUserByUsername(ctx context.Context, db DBTX, username string) (User, error) |
| | 64 | + GetUserByUsernameIncludingDeleted(ctx context.Context, db DBTX, username string) (User, error) |
| 56 | GetUserEmailByAddress(ctx context.Context, db DBTX, email string) (UserEmail, error) | 65 | GetUserEmailByAddress(ctx context.Context, db DBTX, email string) (UserEmail, error) |
| 57 | GetUserEmailByID(ctx context.Context, db DBTX, id int64) (UserEmail, error) | 66 | GetUserEmailByID(ctx context.Context, db DBTX, id int64) (UserEmail, error) |
| 58 | GetUserEmailByVerificationHash(ctx context.Context, db DBTX, verificationTokenHash []byte) (UserEmail, error) | 67 | GetUserEmailByVerificationHash(ctx context.Context, db DBTX, verificationTokenHash []byte) (UserEmail, error) |
| | 68 | + // Like GetUserByID but returns the row even when deleted_at IS NOT NULL. |
| | 69 | + GetUserIncludingDeleted(ctx context.Context, db DBTX, id int64) (User, error) |
| 59 | // Hot path for sshd's AuthorizedKeysCommand. Index lookup via the UNIQUE | 70 | // Hot path for sshd's AuthorizedKeysCommand. Index lookup via the UNIQUE |
| 60 | // index on fingerprint_sha256. | 71 | // index on fingerprint_sha256. |
| 61 | GetUserSSHKeyByFingerprint(ctx context.Context, db DBTX, fingerprintSha256 string) (UserSshKey, error) | 72 | GetUserSSHKeyByFingerprint(ctx context.Context, db DBTX, fingerprintSha256 string) (UserSshKey, error) |
| | 73 | + GetUserSessionEpoch(ctx context.Context, db DBTX, id int64) (int32, error) |
| 62 | GetUserTOTP(ctx context.Context, db DBTX, userID int64) (UserTotp, error) | 74 | GetUserTOTP(ctx context.Context, db DBTX, userID int64) (UserTotp, error) |
| 63 | // Hot path for the auth middleware. token_hash is UNIQUE; returns at | 75 | // Hot path for the auth middleware. token_hash is UNIQUE; returns at |
| 64 | // most one row. Caller MUST also check revoked_at IS NULL and | 76 | // most one row. Caller MUST also check revoked_at IS NULL and |
@@ -81,6 +93,8 @@ type Querier interface { |
| 81 | LinkUserPrimaryEmail(ctx context.Context, db DBTX, arg LinkUserPrimaryEmailParams) error | 93 | LinkUserPrimaryEmail(ctx context.Context, db DBTX, arg LinkUserPrimaryEmailParams) error |
| 82 | ListAuditLogForTarget(ctx context.Context, db DBTX, arg ListAuditLogForTargetParams) ([]AuthAuditLog, error) | 94 | ListAuditLogForTarget(ctx context.Context, db DBTX, arg ListAuditLogForTargetParams) ([]AuthAuditLog, error) |
| 83 | ListUserEmailsForUser(ctx context.Context, db DBTX, userID int64) ([]UserEmail, error) | 95 | ListUserEmailsForUser(ctx context.Context, db DBTX, userID int64) ([]UserEmail, error) |
| | 96 | + // SPDX-License-Identifier: AGPL-3.0-or-later |
| | 97 | + ListUserNotificationPrefs(ctx context.Context, db DBTX, userID int64) ([]UserNotificationPref, error) |
| 84 | ListUserSSHKeys(ctx context.Context, db DBTX, userID int64) ([]UserSshKey, error) | 98 | ListUserSSHKeys(ctx context.Context, db DBTX, userID int64) ([]UserSshKey, error) |
| 85 | ListUserTokens(ctx context.Context, db DBTX, userID int64) ([]UserToken, error) | 99 | ListUserTokens(ctx context.Context, db DBTX, userID int64) ([]UserToken, error) |
| 86 | // SPDX-License-Identifier: AGPL-3.0-or-later | 100 | // SPDX-License-Identifier: AGPL-3.0-or-later |
@@ -92,19 +106,33 @@ type Querier interface { |
| 92 | MarkUserEmailPrimaryVerified(ctx context.Context, db DBTX, id int64) error | 106 | MarkUserEmailPrimaryVerified(ctx context.Context, db DBTX, id int64) error |
| 93 | MarkUserEmailVerified(ctx context.Context, db DBTX, id int64) error | 107 | MarkUserEmailVerified(ctx context.Context, db DBTX, id int64) error |
| 94 | PurgeStaleAuthThrottle(ctx context.Context, db DBTX, windowStartedAt pgtype.Timestamptz) error | 108 | PurgeStaleAuthThrottle(ctx context.Context, db DBTX, windowStartedAt pgtype.Timestamptz) error |
| | 109 | + // Wrapped by the username-change flow inside a tx that also writes |
| | 110 | + // username_redirects, so the old name becomes a redirect target atomically. |
| | 111 | + RenameUser(ctx context.Context, db DBTX, arg RenameUserParams) error |
| 95 | ResetAuthThrottle(ctx context.Context, db DBTX, arg ResetAuthThrottleParams) error | 112 | ResetAuthThrottle(ctx context.Context, db DBTX, arg ResetAuthThrottleParams) error |
| | 113 | + // Clears deleted_at; called when a user logs in within the 14-day grace |
| | 114 | + // window. The login handler enforces the window check before calling. |
| | 115 | + RestoreUserAccount(ctx context.Context, db DBTX, id int64) error |
| 96 | // Used by user suspension to revoke every active token in one statement. | 116 | // Used by user suspension to revoke every active token in one statement. |
| 97 | RevokeAllUserTokens(ctx context.Context, db DBTX, userID int64) error | 117 | RevokeAllUserTokens(ctx context.Context, db DBTX, userID int64) error |
| 98 | // Scoped revoke: caller must pass owning user_id so a hijacked handler | 118 | // Scoped revoke: caller must pass owning user_id so a hijacked handler |
| 99 | // can never revoke tokens it doesn't own. No-op on already-revoked rows. | 119 | // can never revoke tokens it doesn't own. No-op on already-revoked rows. |
| 100 | RevokeUserToken(ctx context.Context, db DBTX, arg RevokeUserTokenParams) (int64, error) | 120 | RevokeUserToken(ctx context.Context, db DBTX, arg RevokeUserTokenParams) (int64, error) |
| | 121 | + // Atomically unset the existing primary and set the supplied row as |
| | 122 | + // primary. Caller MUST have already verified the row belongs to the |
| | 123 | + // user and is verified. |
| | 124 | + SetUserEmailPrimary(ctx context.Context, db DBTX, arg SetUserEmailPrimaryParams) error |
| 101 | SetVerificationToken(ctx context.Context, db DBTX, arg SetVerificationTokenParams) error | 125 | SetVerificationToken(ctx context.Context, db DBTX, arg SetVerificationTokenParams) error |
| 102 | SoftDeleteUser(ctx context.Context, db DBTX, id int64) error | 126 | SoftDeleteUser(ctx context.Context, db DBTX, id int64) error |
| 103 | SuspendUser(ctx context.Context, db DBTX, arg SuspendUserParams) error | 127 | SuspendUser(ctx context.Context, db DBTX, arg SuspendUserParams) error |
| 104 | TouchSSHKeyLastUsed(ctx context.Context, db DBTX, arg TouchSSHKeyLastUsedParams) error | 128 | TouchSSHKeyLastUsed(ctx context.Context, db DBTX, arg TouchSSHKeyLastUsedParams) error |
| 105 | TouchUserLastLogin(ctx context.Context, db DBTX, id int64) error | 129 | TouchUserLastLogin(ctx context.Context, db DBTX, id int64) error |
| 106 | TouchUserTokenLastUsed(ctx context.Context, db DBTX, arg TouchUserTokenLastUsedParams) error | 130 | TouchUserTokenLastUsed(ctx context.Context, db DBTX, arg TouchUserTokenLastUsedParams) error |
| | 131 | + UpdateUserAvatarKey(ctx context.Context, db DBTX, arg UpdateUserAvatarKeyParams) error |
| 107 | UpdateUserPassword(ctx context.Context, db DBTX, arg UpdateUserPasswordParams) error | 132 | UpdateUserPassword(ctx context.Context, db DBTX, arg UpdateUserPasswordParams) error |
| | 133 | + UpdateUserProfile(ctx context.Context, db DBTX, arg UpdateUserProfileParams) error |
| | 134 | + UpdateUserTheme(ctx context.Context, db DBTX, arg UpdateUserThemeParams) error |
| | 135 | + UpsertUserNotificationPref(ctx context.Context, db DBTX, arg UpsertUserNotificationPrefParams) error |
| 108 | // SPDX-License-Identifier: AGPL-3.0-or-later | 136 | // SPDX-License-Identifier: AGPL-3.0-or-later |
| 109 | // Inserts a new pending TOTP row, or replaces an existing pending row for | 137 | // Inserts a new pending TOTP row, or replaces an existing pending row for |
| 110 | // the same user. Confirmed rows are NOT replaced — disable+regenerate | 138 | // the same user. Confirmed rows are NOT replaced — disable+regenerate |