Skip to content

PM-38625: Chore: Store the WrappedAccountCryptographicState#7030

Open
david-livefront wants to merge 1 commit into
mainfrom
PM-38625-store-account-crypto-state
Open

PM-38625: Chore: Store the WrappedAccountCryptographicState#7030
david-livefront wants to merge 1 commit into
mainfrom
PM-38625-store-account-crypto-state

Conversation

@david-livefront
Copy link
Copy Markdown
Collaborator

@david-livefront david-livefront commented Jun 5, 2026

🎟️ Tracking

PM-38625

📔 Objective

This PR removes the privateKey and accountKeys from our persistence layer and migrates everything we need to a new WrappedAccountCryptographicState object.

  • Migration logic has been added to the initialization of the AuthDiskSource
    • All old data stored to disk should be removed
  • Any places that previously stored the privateKey and/or accountKeys should now store the appropriate WrappedAccountCryptographicState
  • Any places retrieving the privateKey and/or accountKeys should now retrieve the WrappedAccountCryptographicState

@david-livefront david-livefront requested a review from a team as a code owner June 5, 2026 21:27
@github-actions github-actions Bot added app:password-manager Bitwarden Password Manager app context t:tech-debt Change Type - Tech debt labels Jun 5, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 5, 2026

🤖 Bitwarden Claude Code Review

Overall Assessment: APPROVE

This PR migrates from separately stored privateKey and accountKeys to a unified WrappedAccountCryptographicState persisted via a custom version-tagged serializer. The change includes a one-time migration in AuthDiskSourceImpl.init, updates every call site that previously read or wrote the two legacy values, and adapts the corresponding tests. The migration logic correctly prefers the wrapped private key inside AccountKeysJson when present and falls back to the standalone encrypted private key, then nulls out the legacy storage keys.

Code Review Details
  • ❓ : Sync no longer clears stored cryptographic state when the response carries null keys (already raised in existing thread)
    • app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultSyncManagerImpl.kt:381

@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 5, 2026

Codecov Report

❌ Patch coverage is 78.15126% with 26 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.80%. Comparing base (c0caaf9) to head (d4c973a).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...en/data/auth/datasource/disk/AuthDiskSourceImpl.kt 41.37% 15 Missing and 2 partials ⚠️
...izer/WrappedAccountCryptographicStateSerializer.kt 94.28% 0 Missing and 2 partials ⚠️
...rm/repository/AuthenticatorBridgeRepositoryImpl.kt 50.00% 1 Missing and 1 partial ⚠️
...twarden/data/vault/manager/VaultLockManagerImpl.kt 50.00% 1 Missing and 1 partial ⚠️
...twarden/data/vault/manager/VaultSyncManagerImpl.kt 71.42% 0 Missing and 2 partials ⚠️
.../auth/repository/util/AccountKeysJsonExtensions.kt 90.90% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7030      +/-   ##
==========================================
+ Coverage   85.50%   86.80%   +1.29%     
==========================================
  Files        1005      903     -102     
  Lines       66462    65029    -1433     
  Branches     9328     9285      -43     
==========================================
- Hits        56829    56448     -381     
+ Misses       6426     5383    -1043     
+ Partials     3207     3198       -9     
Flag Coverage Δ
app-data 17.23% <78.15%> (+0.11%) ⬆️
app-ui-auth-tools 18.99% <0.00%> (-0.01%) ⬇️
app-ui-platform 16.79% <0.00%> (-0.02%) ⬇️
app-ui-vault 28.31% <0.00%> (-0.01%) ⬇️
authenticator 6.21% <0.00%> (-0.01%) ⬇️
lib-core-network-bridge 4.06% <0.00%> (-0.01%) ⬇️
lib-data-ui 1.14% <0.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment on lines +381 to +388
profile.privateKeyOrNull()?.let { privateKey ->
storeAccountCryptographicState(
userId = userId,
accountCryptographicState = profile.accountKeys.toAccountCryptographicState(
privateKey = privateKey,
),
)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QUESTION: Sync no longer clears stored cryptographic state when the response carries null keys

Details

Previously storeProfileData unconditionally called storePrivateKey(userId, profile.privateKey) and storeAccountKeys(userId, profile.accountKeys). If a sync response returned null for those fields, the on-disk values were cleared.

The new implementation only writes when profile.privateKeyOrNull() is non-null, so a sync response with both accountKeys and the deprecated privateKey field null will leave any previously stored WrappedAccountCryptographicState untouched rather than clearing it.

Is the divergence intentional (e.g., to guard against transient null sync responses overwriting valid local state), or should we preserve the previous "clear on null" behavior by writing null to storeAccountCryptographicState when privateKeyOrNull() is null?

@david-livefront david-livefront added the ai-review-vnext Request a Claude code review using the vNext workflow label Jun 5, 2026
val securityState = this?.securityState?.securityState
val signingKey = this?.signatureKeyPair?.wrappedSigningKey
val signedPublicKey = this?.publicKeyEncryptionKeyPair?.signedPublicKey
return if (signingKey != null && securityState != null && signedPublicKey != null) {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic has not changed but I was able to completely remove the createWrappedAccountCryptographicState() function

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-review-vnext Request a Claude code review using the vNext workflow app:password-manager Bitwarden Password Manager app context t:tech-debt Change Type - Tech debt

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant