Skip to content

Feat/vault#5

Merged
npiesco merged 52 commits intomainfrom
feat/vault
Jan 2, 2026
Merged

Feat/vault#5
npiesco merged 52 commits intomainfrom
feat/vault

Conversation

@npiesco
Copy link
Copy Markdown
Owner

@npiesco npiesco commented Jan 2, 2026

No description provided.

React Native app structure using absurder-sql-mobile UniFFI bindings.
VaultDatabase wrapper with SQLCipher encryption and vault schema.
Zustand store for state management, unlock and credentials screens.
AddEditCredentialScreen provides full credential management:
- Create/edit credentials with name, username, password, URL, notes
- Generate cryptographically strong 20-character passwords
- Field validation with error feedback
- Scrollable form with keyboard avoidance

CredentialsScreen shows expandable list with edit/delete actions.
Metro config resolves symlinked absurder-sql-mobile bindings.
iOS/Android native projects configured for encrypted SQLite.
…launch

Persistence tests prove absurder-sql-mobile bindings work correctly:
- Multiple credentials stored in single encrypted vault
- Full app terminate and cold relaunch preserves all data
- Edits and deletes persist across restart cycles
… actions

Full credential detail view with:
- Password visibility toggle (tap to reveal/hide)
- Copy buttons for username, password, and URL
- Edit navigation from detail screen
- Back navigation to credentials list
- Created/Modified timestamps display
Settings accessible from credentials header shows vault name, credential count,
lock vault button, export button with confirmation dialog, and about section.
Navigation wiring complete with 24 E2E tests passing across all screens.
Password generator now includes slider UI for setting length from 8-128
characters. Default remains 20. Displays both configured and generated
length values. Uses @react-native-community/slider for native slider.
Resolves IDE TypeScript errors for describe, it, beforeAll etc in
E2E test files by creating dedicated tsconfig with jest/detox types.
Password generator supports two modes via toggle:
- Random: character-based passwords (8-128 chars)
- Passphrase: word-based using 1000-word EFF-style list (3-8 words)

Word count slider appears when passphrase mode selected.
Passphrases use hyphen separator between words.
Copy button appears next to generated password/passphrase indicator.
Tapping copies the current password to clipboard with confirmation alert.
Works for both random character passwords and word-based passphrases.
TOTP input field in AddEditCredentialScreen for storing authenticator secrets.
TOTP secret displayed (masked) in CredentialDetailScreen.
Secrets persist across app restarts via encrypted SQLite storage.
Credentials now support custom fields with name/value pairs.
Custom fields are persisted in encrypted storage and can be
added, edited, and deleted from the credential form.
Credentials can now be marked as favorite from detail screen or
expanded card. Favorite status shows as a star badge in the list
and persists across app restarts.
Credentials can now have multiple tags assigned for organization.
Tags are created inline when adding to credentials and displayed
in both list and detail views. Tags persist across app restarts.
CURRENT STATE:
- Phase 2.2 Credential Management in progress
- Tags/categories COMPLETE (7 E2E tests, committed c35af83)
- Credential sorting options IN PROGRESS

TDD STATUS:
- E2E test written: vault/mobile/e2e/credentialSorting.test.ts
- 8 tests covering:
  1. Display sort button in header
  2. Show sort options menu (A-Z, Z-A, Updated, Created, Favorites)
  3. Sort by name A-Z (default)
  4. Sort by name Z-A
  5. Sort by recently updated
  6. Sort by recently created
  7. Sort favorites first
  8. Persist sort preference across restart
- RED phase: Test written, needs to be run to confirm failure
- GREEN phase: Implementation pending

NEXT STEPS:
1. Run credentialSorting.test.ts to confirm RED (all 8 fail)
2. Implement in VaultDatabase.ts:
   - Add getSortedCredentials(sortOption) method
   - Store sort preference in vault_meta
3. Implement in store.ts:
   - Add sortOption state
   - Add setSortOption action
   - Modify refreshCredentials to use sort
4. Implement in CredentialsScreen.tsx:
   - Add sort button with testID="sort-button"
   - Add sort menu with options
   - Add current-sort-indicator display
5. Run test to confirm GREEN
6. Run all 70+ tests for regression
7. Commit and update progress tree

EXISTING TESTS (63 passing):
- persistence: 3
- addCredential: 5
- credentialDetail: 8
- passwordGenerator: 7
- passphrase: 8
- settings: 8
- totpSecret: 5
- customFields: 6
- favorites: 6
- tags: 7
- Move uniffi-bindgen-react-native from devDependencies to dependencies in absurder-sql-mobile
- Update .xcode.env.local to use symlinked Node path instead of hardcoded version
- Make registry module conditional on uniffi-bindings feature in lib.rs
- Add mobile development environment setup docs to README.md
- Add memoize-one dependency to vault mobile app
- Update absurder-sql-mobile/README.md with accurate build steps
- Add SQLCipher build instructions for Android arm64-v8a
- Document cargo-ndk v3.5.4 requirement (v4.x breaks uniffi-bindgen-react-native)
- Add environment variable setup (ANDROID_NDK_HOME, JAVA_HOME)
- Remove fix_cpp_adapter.py from ubrn:android script (not needed)
- Limit Android build to arm64-v8a in ubrn.config.yaml (only ABI with SQLCipher libs)
- Add sort button with dropdown menu in CredentialsScreen header
- Support 5 sort options: A-Z, Z-A, recently updated, recently created, favorites first
- Persist sort preference across app restarts using AsyncStorage
- Add sortCredentials helper function in store.ts
- Install @react-native-async-storage/async-storage dependency
- Add FoldersScreen for CRUD operations on folders
- Add folder navigation button in CredentialsScreen header
- Add folder picker in AddEditCredentialScreen
- Add folder filtering in CredentialsScreen
- Add folder badges on credentials in list
- Add updateFolder method to VaultDatabase
- Fix scrolling issues in folders and tags E2E tests
- Add subfolder creation with parent-child relationships
- Display nested folders with indentation and expand/collapse
- Show full folder paths in credential picker (Work / Projects / Active)
- Show folder path badges on credentials
- Filter credentials by nested folder with full path display
- Move subfolders to root when parent folder is deleted
- Add updateFolderParent method to VaultDatabase
- Add getSortedFoldersForPicker/Filter helpers for nested display
…/colors

- Replace all emoji usage with MaterialCommunityIcons across all screens
- Add MaterialCommunityIcons.ttf font to iOS Info.plist
- Add icon and color pickers to folder creation/editing modal
- Store folder icon and color in database
- Fix Detox visibility issues for Icon components
- Fix folder filter tests with atIndex(0) for multiple matches
- Add lastAccessedAt field to Credential interface and database schema
- Add updateLastAccessed() method to VaultDatabase
- Add 'recent' sort option to store with trackAccess() method
- Track access when viewing credential detail (with ref to prevent infinite loop)
- Track access when copying username or password
- Add 'Recently Accessed' sort option to CredentialsScreen
- Add testIDs for copy-username-button and copy-password-button
- Add Move to Folder button in expanded credential actions
- Add modal with folder picker and No Folder option
- Persist folder assignment across app restart
- Fix folderIconsColors test ordering to avoid FAB visibility issue after restart
- Implement export in SettingsScreen using react-native-fs and react-native-share
- Export saves encrypted database to Documents directory with timestamp
- Show file size in success message with optional Share button
- Add loading indicator while exporting
- Fix credentialSorting.test.ts edit button visibility issue
- Add Row and ColumnValue types to uniffi_api/types.rs matching core crate
- Update core.rs to convert from core types to UniFFI types using convert_row
- Update AbsurderDatabase.ts to handle typed Row/ColumnValue instead of JSON strings
- Fix ComparisonBenchmark.tsx to handle new typed format and provide all DatabaseConfig fields
- Add export for AbsurderDatabase in src/index.ts
- Fix react-native/tsconfig.json with proper compiler options
- Add type declarations for react-native-sqlite-storage, watermelondb, react-test-renderer, jest, react-native-safe-area-context
- Fix uniffi_encryption_blocking_test.rs to include all required DatabaseConfig fields
- Add encrypted export/import round-trip test
- Fix detox config to use xcworkspace and arm64 arch
- Update e2e tests to match actual UI tab names
- Add import vault UI to SettingsScreen
- Changed import_database to use ATTACH DATABASE instead of Connection::open
- ATTACH inherits encryption key from main connection, fixing encrypted backup import
- Removed debug logging from import function
- Add react-native-document-picker for iOS Files app integration
- Replace Alert dialog with Modal for import options
- Add Browse Files option (system file picker)
- Add Recent Backups option (list local backup files)
- Add backup file list modal with file selection
- Update importVault.test.ts for new modal UI
- Add biometricService.ts for secure keychain storage and biometric auth
- Add biometric toggle to SettingsScreen with enable/disable functionality
- Update UnlockScreen to show biometric unlock button when enabled
- Require explicit tap for biometric unlock (no auto-prompt on mount)
- Add NSFaceIDUsageDescription to Info.plist for Face ID permission
- Disable new architecture in Podfile to fix react-native-keychain linking
- Pass masterPassword from App.tsx to SettingsScreen for biometric enable
- FoldersScreen.tsx: Add zIndex to FAB for proper layering
- Add AppState listener in App.tsx for background/foreground detection
- Create autoLockService.ts for auto-lock and clipboard clear logic
- Add configurable auto-lock timeout (immediate, 1min, 5min, 15min, never)
- Add configurable clipboard clear timeout (30sec, 1min, 5min, never)
- Add settings UI with picker modals for both features
- Fix Clipboard imports to use @react-native-clipboard/clipboard
- Add syncService.ts for conflict detection between local vault and backup
- Add conflict resolution modal UI with keep local/remote/both options
- Add SecurityAuditService for password strength and age analysis
- Add SecurityAuditScreen with weak passwords and old passwords sections
- Integrate Security Audit button in SettingsScreen
- Wire SecurityAuditScreen navigation in App.tsx
… hint

- Add change password button and modal in SettingsScreen
- Implement password strength meter (weak/medium/strong)
- Add optional password hint saved to AsyncStorage
- Display password hint on UnlockScreen when set
- Validate current password, new password match, min 12 chars
- Rekey vault database on password change
- Update biometric stored password on change
TOTP Authenticator implementation:
- Add otpauth library for RFC 6238 TOTP generation
- Create totpService.ts with generateTOTP, formatTOTPCode, isValidTOTPSecret
- Create TOTPDisplay.tsx component with countdown timer, progress bar, copy button
- Integrate TOTP display in CredentialDetailScreen
- Add QRScannerScreen with camera integration (react-native-vision-camera v4)
- Add manual TOTP secret entry fallback for simulator/no-camera
- Add TOTPQuickViewScreen showing all credentials with TOTP secrets
- Add live countdown timer and copy functionality
- Add totpUriParser for parsing otpauth:// URIs
- Add getRemainingSeconds to totpService
- Integrate Scan QR button in AddEditCredentialScreen
- Add TOTP Quick View button in CredentialsScreen header
- Fix infinite loop with useMemo for totpCredentials
- Add camera usage description to iOS Info.plist
- Add ThemeProvider with light/dark/system mode support
- Add theme context with color definitions for both themes
- Persist theme preference in AsyncStorage
- Add theme setting in Settings with picker modal
- Wrap App with ThemeProvider for app-wide theming
- Add hapticService with light/medium/heavy/selection/success/error feedback
- Add haptic feedback setting in Settings Appearance section
- Persist haptic preference in AsyncStorage
- Loading states tests: vault creation, unlock, credential save (3 tests)
- Error handling tests: password mismatch, wrong password, validation
- Test empty credentials list display
- Add accessibilityLabel to FAB, settings button, search input
- Add accessibilityRole to interactive elements
- Add fontSizeService with small/medium/large options
- Add font size picker in Settings Appearance section
- Persist font size preference in AsyncStorage
- Add highContrastService for persistence
- Add high contrast toggle in Settings Accessibility section
- FlatList virtualization: removeClippedSubviews, windowSize, maxToRenderPerBatch
- Debounced search (150ms) for better typing performance
- Memoized filtered credentials with useMemo
- Memoized keyExtractor with useCallback
- Add 4 E2E tests: large list handling, scroll, search, filter
- Disable iOS password autofill with textContentType=oneTimeCode
- Tests create 20 credentials and verify virtualization works
…andling

- Add resolveDatabasePath() to convert relative paths to absolute paths on Android
- Register AbsurderSqlInitializer native module to provide data directory
- Add packagingOptions to handle duplicate .so files
- Extract error messages from DatabaseError.inner.message structure
- Fix E2E test keyboard handling for URL field

[skip ci]
Fixes #4

## Problem
IndexedDB keys included checksums (e.g., "demo.db:1:1018362130"). When a
block was updated, it created a NEW key instead of overwriting the old one,
causing multiple versions to accumulate. On restore, the wrong version could
be loaded due to lexicographic ordering, resulting in "database disk image
is malformed" errors after page refresh.

## Root Cause
- Keys: "db_name:block_id:checksum" created duplicates on update
- Restore iterated keys in lexicographic order (not chronological)
- Deduplication kept LAST iterated version (wrong one)

## Solution
Changed IndexedDB key format from "db_name:block_id:checksum" to "db_name:block_id"
Keys are now truly idempotent - updates OVERWRITE instead of creating duplicates.
Checksums still stored as VALUES in metadata for integrity checking.
@npiesco npiesco merged commit 0a0541b into main Jan 2, 2026
3 of 4 checks passed
@npiesco npiesco deleted the feat/vault branch January 2, 2026 23:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant