feat(v1.1.8): password reset flow (migration 0029 + revokes sessions)
migration 0029: app_user_password_resets table — same shape as
verification (token_hash PK, app_id + user_id FKs, expires_at,
consumed_at). One-shot via atomic UPDATE WHERE consumed_at IS NULL.
Default TTL 1h (shorter than verification's 48h — reset tokens are
higher-risk).
UsersServiceImpl gains password_resets: Arc<dyn AppUserPasswordResetRepo>.
users::request_password_reset(email, opts):
* Returns Ok(()) regardless of whether the email matched — no
existence-leak signal in script-land (per brief).
* Email-not-configured surfaces as NotConfigured so scripts can
fall back to a synchronous reset path. Other email errors are
silently swallowed and logged server-side; surfacing them would
leak which addresses produced a "real send attempted" signal vs
a no-op.
users::complete_password_reset(token, new_password):
* Atomically consumes the token, updates the Argon2id hash, and
revokes EVERY active session for that user (anyone with a stale
token shouldn't be able to ride out the reset). Emits
users::password_changed.
* Returns the user on success, () on bad/expired/already-used.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -21,9 +21,9 @@ use picloud_manager_core::{
|
||||
FilesServiceImpl, FsFilesRepo, HttpConfig, HttpServiceImpl, KvServiceImpl, OutboxEventEmitter,
|
||||
OutboxRepo, PostgresAbandonedRepo, PostgresAdminSessionRepository, PostgresAdminUserRepository,
|
||||
PostgresApiKeyRepository, PostgresAppDomainRepository, PostgresAppMembersRepository,
|
||||
PostgresAppRepository, PostgresAppSecretsRepo, PostgresAppUserRepository,
|
||||
PostgresAppUserSessionRepository, PostgresAppUserVerificationRepo, PostgresDeadLetterRepo,
|
||||
PostgresDeadLetterService,
|
||||
PostgresAppRepository, PostgresAppSecretsRepo, PostgresAppUserPasswordResetRepo,
|
||||
PostgresAppUserRepository, PostgresAppUserSessionRepository,
|
||||
PostgresAppUserVerificationRepo, PostgresDeadLetterRepo, PostgresDeadLetterService,
|
||||
PostgresDocsRepo, PostgresExecutionLogRepository, PostgresExecutionLogSink, PostgresKvRepo,
|
||||
PostgresOutboxRepo, PostgresPubsubRepo, PostgresRouteRepository, PostgresScriptRepository,
|
||||
PostgresSecretsRepo, PostgresTopicRepo, PostgresTriggerRepo, PrincipalResolver,
|
||||
@@ -253,10 +253,13 @@ pub async fn build_app(
|
||||
let app_user_sessions_repo = Arc::new(PostgresAppUserSessionRepository::new(pool.clone()));
|
||||
let app_user_verifications_repo =
|
||||
Arc::new(PostgresAppUserVerificationRepo::new(pool.clone()));
|
||||
let app_user_password_resets_repo =
|
||||
Arc::new(PostgresAppUserPasswordResetRepo::new(pool.clone()));
|
||||
let users: Arc<dyn UsersService> = Arc::new(UsersServiceImpl::new(
|
||||
app_users_repo.clone(),
|
||||
app_user_sessions_repo.clone(),
|
||||
app_user_verifications_repo.clone(),
|
||||
app_user_password_resets_repo.clone(),
|
||||
email.clone(),
|
||||
authz.clone(),
|
||||
events.clone(),
|
||||
|
||||
Reference in New Issue
Block a user