Draft
Conversation
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
19603ae to
e797c50
Compare
Use an independent random key stored in keychain for local DB encryption instead of deriving it from the CSPP master key. This prevents cloud backup restore from invalidating the local encryption key and wiping all local databases. - Add get/create_local_encryption_key() to Keychain (write-once) - Rename encrypted DB files: cove.encrypted.db, wallet_data.encrypted.json.redb - Rewrite redb migration to source≠dest flow (no two-phase-swap) - Simplify restore: save master key without replacing local encryption - Remove replace_encryption_key(), delete_master_key(), Database::reinitialize() - Fix .expect() panic in wallet_data database_location()
- Wipe BDK store files in wipe_local_data (B2) - Load persisted cloud backup state on startup via syncPersistedState (B3) - Add cloud restore option to CatastrophicErrorView with CloudKit probe (B1) - Add DeviceRestoreView orchestrating wipe → bootstrap → restore (B1) - Guard against concurrent enable/restore operations (I5) - Don't mark Enabled when all wallets fail to restore (C2) - Propagate collect_existing_fingerprints error instead of swallowing (C3) - Error on partial keychain state in get_local_encryption_key (C4) - Write-side hardening: cleanup orphaned cryptor on second save failure (C4) - Bootstrap handles partial keychain state: routes to DatabaseKeyMismatch or purges and recreates when no DB exists (C4) - Zeroize plaintext JSON in wallet_crypto encrypt/decrypt (I1) - Use .allKeys save policy in CloudKit uploads for idempotent retry (I2) - Add 120s timeout to passkey semaphore (I3) - Log encryption key mismatch in release builds (I4) - Log is_wallet_duplicate errors (I6) - Distinguish "record exists but data nil" from "not found" in CloudKit (I7)
On startup, if cloud backup state is disabled (fresh install or upgrade), probe CloudKit for an existing backup. If found, show a simple CloudRestoreOfferView with restore/skip options before entering the normal app flow.
Increment Android versionCode from 17 to 18 and update iOS CURRENT_PROJECT_VERSION from 64 to 67 in the Xcode project. These changes align build numbers for a new release while leaving Android versionName (1.3.0) unchanged.
Add request.prf = .checkForSupport during createPasskey so the authenticator knows PRF will be needed for assertions. Also log PRF support status after registration and log when assertion.prf is nil to help diagnose PRF failures.
When authenticateWithPrf fails (e.g. passkey was deleted externally), clear the cached credential_id and prf_salt from keychain so the next retry creates a fresh passkey instead of trying to sign in with a credential that no longer exists.
Runs enable/restore on tokio's blocking thread pool so the tokio reactor is available if any code inside needs it.
Replace verbose .map_err(|e| Error(e.to_string())) with map_err_str across cloud_backup_manager, derive strum::EnumIter on WalletMode for cleaner iteration, add iCloud/CloudKit entitlements, and document map_err_str preference in CLAUDE.md
Replace verbose .map_err(|e| ...) patterns with cove_util::ResultExt helpers (map_err_prefix / map_err_str) for cleaner, consistent error mapping across modules. Add missing use statements where needed, centralize and move the CloudBackupError enum earlier in cloud_backup_manager.rs (removing the duplicate at the bottom), and make small related fixes (manifest/version handling, whitespace). Also update CLAUDE.md to document the preferred ResultExt helpers. Affected files: CLAUDE.md, rust/crates/cove-device/src/keychain.rs, rust/src/auth.rs, rust/src/backup/crypto.rs, rust/src/backup/verify.rs, rust/src/manager/cloud_backup_manager.rs.
Clear per-wallet DATABASE_CONNECTIONS cache in reinit_database() so restored wallets don't get stale handles pointing at deleted files. Add 120s timeout to observeRestoreCompletion() polling loop to prevent infinite spinner if the Rust side gets stuck.
Rust: Improve legacy DB migration recovery and detection — handle interrupted two-phase swaps (.enc.tmp + .bak), restore from .bak or finish the .enc.tmp rename as appropriate, and avoid re-migrating databases that are already encrypted by the old migration (rename them instead). Added needs_legacy_rename helper, updated counting and migration flows to consider both migration and simple rename cases, and added safety logging and error handling. iOS: Surface iCloud backup check failures — add cloudCheckError state, present an alert when the cloud backup check throws, and switch the cloud check to a try/catch flow that logs failures and sets the error message while still finishing bootstrap.
Check all networks and modes when deciding whether to offer cloud restore on startup, preventing incorrect restore offers when wallets exist on a non-selected network or in decoy mode. Verify main DB health before deleting legacy .bak files, restoring from backup if the main DB is corrupt instead of silently dropping the last recoverable copy.
Auto-backup new wallets as they're created via backup_new_wallet() called from save_new_wallet_metadata. Add sync button on the cloud backup detail screen for manually uploading unsynced wallets. Use the cloud manifest as source of truth: refresh_cloud_backup_detail downloads the manifest from CloudKit to determine real backup status, and do_sync_unsynced_wallets compares against the manifest rather than the local cache. Extract all_local_wallets() helper to flatten the repeated network×mode double-loop pattern across the file.
Switch hasCloudBackup() and downloadRecord() from the convenience db.fetch(withRecordID:) API to CKFetchRecordsOperation to match how uploads already work. Add mapFetchError helper that logs raw CKError code, domain, and userInfo for diagnosing container errors. Handle operation-level failures in fetchRecordsResultBlock.
The local cache (cloud_backup_wallets in global_config) was falsely reporting wallets as backed up without verifying against the cloud. Remove the cache entirely and use the cloud manifest to determine real backup status. Add cloud_only_count to CloudBackupDetail and fetch_cloud_only_wallets() to download and decrypt orphan entries. Replace cloud_backup_detail() with is_cloud_backup_enabled() since the detail screen now loads everything from the cloud.
Show a progress indicator while downloading the cloud manifest instead of falsely displaying cached backup status. Show error state if the cloud read fails. Add cloud-only section showing count of wallets in the cloud but not on this device, with a Get More Info button that downloads and decrypts their metadata. Add SyncFailed reconcile message to separate sync errors from global backup state.
When the manifest is not found (e.g. switching from Development to Production CloudKit), automatically re-upload all local wallets instead of showing a generic error. For other cloud errors (access denied, network unavailable), show the specific error message with a retry button. Extract upload_all_wallets_and_manifest helper shared by enable and re-upload flows.
CloudKit required manual schema deployment and had bundle ID / container mismatch issues on TestFlight. iCloud Drive (ubiquity container) eliminates all of this with zero CloudKit Dashboard setup needed. - Add ICloudDriveHelper with NSFileCoordinator, NSMetadataQuery wrappers - Files stored in Data/ (hidden from user) with SHA256-hashed filenames - Uploads block until confirmed uploaded (waitForUpload polling) - downloadManifest uses NSMetadataQuery for authoritative NotFound - hasCloudBackup checks both manifest AND master key existence - Update entitlements: CloudDocuments + ubiquity container - Replace CKContainer.accountStatus with ubiquityIdentityToken - Add sync health indicator to cloud backup detail header
…agement - Add "Create New Passkey" recovery action on cancelled/failed verification for when the original passkey was deleted - Persist verification state as CloudBackup::Unverified in redb so the main settings screen shows "Cloud Backup Unverified" across app restarts - Remove passkey existence check from startup integrity check to prevent brief Face ID flash on launch - Auto-sync unsynced wallets during deep verify and startup integrity check - Add retry fallback to backup_new_wallet via full sync on failure - Deduplicate manifest record_ids to prevent duplicate wallet entries - Add restore and delete actions for cloud-only wallets with confirmation - Increase iCloud Drive upload timeout from 10s to 60s - Refresh detail after cloud wallet restore/delete operations
- Add namespace ID derivation (HKDF-SHA256 from master key) for directory isolation
- Replace flat Data/*.json layout with Data/cspp-namespaces/{namespace_id}/ structure
- Remove BackupManifest, use filesystem as source of truth via NSMetadataQuery
- Fix double-hash bug in wallet filenames (recordId is already SHA256)
- Fix /var vs /private/var symlink mismatch in NSMetadataQuery path comparisons
- Add legacy flat-file detection in hasAnyCloudBackup for old-format discovery
- Simplify DeviceRestoreView to additive restore (no wipe/bootstrap)
- Export NAMESPACES_SUBDIRECTORY constant from Rust for cross-platform consistency
c02ed3c to
9fa5e5d
Compare
Rename the documentation file from CLAUDE.md to AGENTS.md and update the first paragraph to reference AGENTS.md instead of CLAUDE.md. Content remains the same aside from the filename and the internal reference.
Split UI and logic for onboarding startup recovery views for better separation of concerns and testability. CloudCheckView now reports result via a completion closure and its cloud probe logic was extracted into CloudCheckContent and a static checkForCloudBackup helper. CatastrophicErrorView and DeviceRestoreView were refactored to separate Content subviews from task/logic (probing cloud, retry/contact/wipe handlers, restore start/timeout/sync with BackupManager). Added SwiftUI previews for CloudRestoreOffer, CloudCheck, CatastrophicError, and DeviceRestore states.
Add OnboardingRecoveryTypography to centralize font styles and replace many inline .font(.system(...)) calls across onboarding recovery views. Implement a custom restoringHeroIcon in DeviceRestoreView (replacing a previous OnboardingStatusHero usage) and adjust various text sizes, weights, and button styles to use the new typography. Align Terms & Conditions content to leading, tweak padding/spacing and footnote opacity, and refine checkbox card layout for improved consistency and maintainability.
Replace the plain SwiftUI Text for the privacy/terms line with a UIViewRepresentable (TermsAgreementText) backed by a non-editable UITextView to render styled, tappable links. Add @Environment(\.openURL) and a Coordinator to intercept link taps and forward them via openURL. Introduce LinkOnlyTextView with custom hit-testing so only link regions are interactive. Minor callsite update to TermsCheckboxCard to use the new component and remove the allowsCardToggle parameter. This enables properly styled, accessible link interaction inside the terms card.
9fa5e5d to
a5a6714
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This branch brings the iOS CSPP cloud backup flow to review-ready shape.
On the Rust/core side, it adds the CSPP backup data model, passkey and cloud storage callback interfaces, the new cloud backup manager, encrypted DB change detection, debounced upload handling, startup sync/reconciliation, restore support, and persisted backup verification state.
On iOS, it wires that stack into iCloud Drive and passkeys, adds the iOS 18.4 floor needed for safe PRF behavior, and rounds out the user-facing flows for backup setup, restore discovery, restore progress, backup verification, passkey repair, and cloud-backup detail/status screens. It also hardens recovery behavior around missing passkeys, unsupported backup formats, duplicate-wallet restore cases, and backup integrity verification after wallet changes.
What To Review
QA Notes
Closes: #562 #566 #567 #569 #570 #571 #575 #577 #578 #579 #582 #585 #600 #601 #603 #604
Also addresses: #580 #583 #584