Fix Argon2 hash-format claims and add the missing profile-creation step to the auth diagrams

This commit is contained in:
Aaron Po
2026-08-31 22:03:39 -04:00
parent 1dcc1bd625
commit 809b9b0f72
3 changed files with 19 additions and 5 deletions

View File

@@ -37,7 +37,7 @@ sequenceDiagram
UserMgr->>UserStore: DeleteAsync(user)
activate UserStore
UserStore->>DB: DELETE FROM UserAccount WHERE UserAccountID = @Id
Note right of UserStore: UserCredential/UserVerification/UserAvatar cascade on delete. Posts, comments, photos, and follows use ON DELETE NO ACTION — if any reference this account, the DELETE throws a foreign key violation (SQL error 547)
Note right of UserStore: UserCredential, UserVerification, and UserProfile cascade on delete (UserAvatar cascades transitively through UserProfile). Posts, comments, photos, and follows use ON DELETE NO ACTION — if any reference this account, the DELETE throws a foreign key violation (SQL error 547)
alt Foreign key violation (dependent records exist)
UserStore-->>UserMgr: IdentityResult.Failed (AccountHasDependentRecords)

View File

@@ -55,7 +55,7 @@ sequenceDiagram
Note right of UserMgr: HasPasswordAsync short-circuits to false (no active credential hydrated) without calling the hasher — otherwise delegates to Argon2PasswordHasher
UserMgr->>Argon2: VerifyHashedPassword(user, user.PasswordHash, password)
activate Argon2
Note right of Argon2: Split stored "salt:hash", rehash password with same salt, constant-time compare (CryptographicOperations.FixedTimeEquals)
Note right of Argon2: Parse stored PHC string ($argon2id$v=19$m=...,t=...,p=...$salt$hash), rehash password with the embedded salt/parameters, constant-time compare (CryptographicOperations.FixedTimeEquals)
Argon2-->>UserMgr: Success/Failed
deactivate Argon2
UserMgr-->>LoginHandler: true/false

View File

@@ -15,6 +15,7 @@ sequenceDiagram
end
box rgb(219,238,221) Repository / Cross-slice
participant UserStore as DapperUserStore<br/>(IUserStore/IUserPasswordStore/IUserEmailStore)
participant ProfileHandler as CreateUserProfileHandler<br/>(Profile slice)
participant EmailDispatcher as EmailDispatcher<br/>(Features.Emails)
end
participant DB as SQL Server
@@ -39,8 +40,8 @@ sequenceDiagram
activate UserMgr
UserMgr->>Argon2: HashPassword(user, password)
activate Argon2
Note right of Argon2: Argon2id — salt 16 bytes, memory 64MB, iterations 4, parallelism = CPU count, hash output 32 bytes
Argon2-->>UserMgr: "base64(salt):base64(hash)"
Note right of Argon2: Argon2id — salt 16 bytes, memory 64MB, iterations 4, parallelism 2 (fixed, to avoid thread-pool exhaustion), hash output 32 bytes
Argon2-->>UserMgr: "$argon2id$v=19$m=65536,t=4,p=2$&lt;salt&gt;$&lt;hash&gt;" (PHC string)
deactivate Argon2
UserMgr->>UserStore: SetPasswordHashAsync(user, hash)
@@ -84,6 +85,19 @@ sequenceDiagram
Mediator->>API: propagate
API->>User: 409 Conflict "Username or email already exists"
else result.Succeeded
RegHandler->>Mediator: Send(CreateUserProfileCommand(user.Id, ""))
activate Mediator
Mediator->>ProfileHandler: Handle(command)
activate ProfileHandler
ProfileHandler->>DB: INSERT INTO UserProfile (UserAccountId, Biography)
activate DB
DB-->>ProfileHandler: UserProfileId
deactivate DB
ProfileHandler-->>Mediator: UserProfileId
deactivate ProfileHandler
Mediator-->>RegHandler: UserProfileId
deactivate Mediator
RegHandler->>TokenSvc: GenerateAccessToken(user)
activate TokenSvc
TokenSvc->>JWT: GenerateJwt(userId, username, expiry)
@@ -117,7 +131,7 @@ sequenceDiagram
RegHandler->>Mediator: Send(SendRegistrationEmailCommand) (Shared.Application cross-slice contract)
activate Mediator
Note right of Mediator: Routed to Features.Emails' SendRegistrationEmailHandler — the only cross-slice call in the backend
Note right of Mediator: Routed to Features.Emails' SendRegistrationEmailHandler — the second of two cross-slice dispatches in this flow (profile creation is the first)
Mediator->>EmailDispatcher: SendRegistrationEmailAsync(firstName, email, confirmationToken)
activate EmailDispatcher