-
Notifications
You must be signed in to change notification settings - Fork 11
feat(vaults): Implement vault system with move, create, and delete functionality #44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
71 commits
Select commit
Hold shift + click to select a range
5882c7f
[Rust] Refactor into workspace with UniFFI Kotlin bindings
OffRange 798103f
[Rust] Implement AEAD key definitions and error handling
OffRange 4395a50
[Rust] Implement basic account creation
OffRange 712be60
[Core] [Item] Refactor data model to support Vaults and UUID IDs
OffRange 2aa4311
[Rust] key derivation and wrap bindings
OffRange 119767b
[Core] [Identity] Implement Rust-backed Account system and refactor k…
OffRange 0023750
[Docs] Update CLAUDE.md guidelines for UniFFI and test fixtures
OffRange b342c18
[Rust] cargo fmt
OffRange 83b78db
[Github] Add rust ci
OffRange 1749f0f
[Rust] add Cargo.lock
OffRange 296a276
[Rust] Add fmt
OffRange b062329
[Rust] Rename di module
OffRange c984924
[Rust] Implement item manager
OffRange b28fc2f
[Rust] Implement item manager
OffRange f474640
[Core] [Item] Rename VaultItemMapper to ItemMapper
OffRange 804d1eb
[Core] Implement ItemKey wrapping and update AAD types
OffRange bdf5c64
[Item] Implement vault
OffRange 094b12c
build(rust): move generated .so files out of version control
OffRange cd8d4c2
fix(core-identity): prevent crash when mapping empty account state
OffRange dee18c7
fix(core-item): upsert active_vault row and correct FK target
OffRange 56a60eb
test(fixtures): include compose BOM and runtime dependencies
OffRange 385fc35
test(core-identity): ensure active vault info has been correctly set
OffRange 81a8372
feat(vault): Add Vault Icon structure and presentation mapper
OffRange d2556e0
build(rust): always compile rust by default
OffRange 6c3d9f5
feat(vault): include icon in db
OffRange 709f346
feat(vault): Add vault awareness during item creation
OffRange 3b16a92
feat(vault): vault metadata entities
OffRange 33c1a4c
build(proto): Upgrade to 0.10.0
OffRange 44f1a47
refactor(core-item): observe vault metadata
OffRange abd42b9
feat(list_screen): Add vault selection logic
OffRange 74d1f71
ci: Simplify test call
OffRange f9be041
feat(feat-item): Add vault selection option
OffRange b8a30ed
feat(feat-list): Add active vault indicator
OffRange 7c4f627
feat(feat-list): Add vault selection bottom sheet
OffRange 40a3cfc
refactor(list): move creation into dialog
OffRange 0fa3ee6
refactor(list): move searchbar resetting to caller
OffRange 642c7c3
feat(rust): add generate vault key bindings
OffRange 3a7089d
feat(list): implement create vault functionality
OffRange fbb4908
feat(list): sort by name
OffRange 56817bd
feat(list): add item count for vaults
OffRange 5f35c2a
feat(item): Add vault awareness to name duplicate check
OffRange 687a0a9
refactor: move vault context logic
OffRange d071ada
feat(list): Add edit vault functionality
OffRange 7ce9d4e
feat: Add delete vault functionality
OffRange 10d0ffd
feat: Add move to vault UI
OffRange bbe8949
refactor(item): extract MoveItemsToVaultUseCase to feature/item/core
OffRange 117bea8
refactor(vault): Move vault related logic in separate module
OffRange 1c0bfe2
ci: Merge rust and android ci
OffRange 929837a
feat(view): Add vault label
OffRange 2f628cb
feat(move-vault): Add progress
OffRange 64e2311
feat: Add vault icons
OffRange 0f32739
refactor(vault): replace Closed state with dismissal events
OffRange 098b89b
refactor(active-vault): Remove dead code (#41)
OffRange 9322bb5
refactor(vault): clean up VaultFlowViewModel state seeding (#40)
OffRange 33c5f52
feat(move-vault): Use Result<,> (#42)
OffRange fcb48a5
fix(vault): trim name in CreateVaultUseCase
OffRange c68ecfb
feat(vault): Add vault deletion confirmation dialog
OffRange 09fe524
feat(move-vault): Add vault deletion option
OffRange ff92a93
ci: Add permission
OffRange 0df19bc
refactor: Remove re-export
OffRange 4ceb2d7
fix: Possible crash
OffRange 08cf4f2
ci: fix android test
OffRange c6fa14e
refactor: Use standard SQL pattern
OffRange 570c3ab
fix(last interacted vault): filter out invalid vaults
OffRange 4e5bf60
fix(move-vault): delete vault conditionally
OffRange f0c048b
refactor: remove redundant getPasswordIdByVaultId
OffRange 892d5a1
fix: Add editing aware ui strings
OffRange 5b13875
feat(move-vault): atomic transactional move via @Transaction DAO
OffRange 0a14a7d
fix(last-interacted-vault): make absence explicit via nullable VaultId
OffRange f0d6a71
fix(create-access): persist account before vault to avoid orphans
OffRange 0756f3c
fix(edit-item): Take vault selection into account
OffRange File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,46 +1,120 @@ | ||
| name: Android CI | ||
| name: CI | ||
|
|
||
| on: | ||
| push: | ||
| branches: [ "v2" ] | ||
| pull_request: | ||
| branches: [ "v2" ] | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| env: | ||
| CARGO_TERM_COLOR: always | ||
|
|
||
| jobs: | ||
| ci: | ||
| detect-changes: | ||
| runs-on: ubuntu-latest | ||
|
|
||
| outputs: | ||
| rust: ${{ steps.filter.outputs.rust }} | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v6 | ||
| - uses: dorny/paths-filter@v4 | ||
| id: filter | ||
| with: | ||
| filters: | | ||
| rust: | ||
| - 'rust/**' | ||
| - '.github/workflows/ci.yaml' | ||
|
|
||
| # Fast quality gate: fmt + clippy only. Blocks both rust-test and android-test | ||
| # so a broken Rust change doesn't waste NDK cross-compilation time. | ||
| rust-lint: | ||
| needs: detect-changes | ||
| if: needs.detect-changes.outputs.rust == 'true' | ||
| runs-on: ubuntu-latest | ||
|
|
||
| defaults: | ||
| run: | ||
| working-directory: ./rust/rust-code | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: set up JDK 21 | ||
| uses: actions/setup-java@v4 | ||
| - uses: actions/checkout@v6 | ||
| - uses: actions/cache@v5 | ||
| with: | ||
| java-version: '21' | ||
| distribution: 'temurin' | ||
| cache: gradle | ||
| path: | | ||
| ~/.cargo/registry | ||
| ~/.cargo/git | ||
| rust/rust-code/target | ||
| key: ${{ runner.os }}-cargo-host-${{ hashFiles('**/Cargo.lock') }} | ||
| restore-keys: ${{ runner.os }}-cargo-host- | ||
| - name: Check formatting | ||
| run: cargo fmt --check --all | ||
| - name: Clippy | ||
| run: cargo clippy --workspace --all-targets -- -D warnings | ||
|
|
||
| # Rust-native tests (no NDK). Runs in parallel with android-test once lint passes. | ||
| rust-test: | ||
|
github-advanced-security[bot] marked this conversation as resolved.
Fixed
|
||
| needs: [ detect-changes, rust-lint ] | ||
| if: needs.detect-changes.outputs.rust == 'true' | ||
| runs-on: ubuntu-latest | ||
|
|
||
| - name: Setup Gradle | ||
| uses: gradle/actions/setup-gradle@v4 | ||
| defaults: | ||
| run: | ||
| working-directory: ./rust/rust-code | ||
|
|
||
| - name: Cache Gradle packages | ||
| uses: actions/cache@v4 | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
| - uses: actions/cache@v5 | ||
| with: | ||
| path: | | ||
| ~/.gradle/caches | ||
| ~/.gradle/wrapper | ||
| key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-gradle- | ||
| ~/.cargo/registry | ||
| ~/.cargo/git | ||
| rust/rust-code/target | ||
| key: ${{ runner.os }}-cargo-host-${{ hashFiles('**/Cargo.lock') }} | ||
| restore-keys: ${{ runner.os }}-cargo-host- | ||
| - name: Build | ||
| run: cargo build --workspace --all-targets --verbose | ||
| - name: Run tests | ||
| run: cargo test --workspace --verbose | ||
|
|
||
| # Android unit tests. Waits for rust-lint when rust changed, so NDK cross-compilation isn't | ||
| # triggered on code that already fails fmt/clippy. | ||
| # buildRust (make all) runs internally via the preBuild Gradle hook and generates | ||
| # the UniFFI Kotlin interfaces that the tests compile against. | ||
| android-test: | ||
|
github-advanced-security[bot] marked this conversation as resolved.
Fixed
|
||
| needs: [ detect-changes, rust-lint ] | ||
| if: | | ||
| always() && | ||
| ( | ||
| needs.detect-changes.outputs.rust != 'true' || | ||
| needs.rust-lint.result == 'success' | ||
| ) | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v6 | ||
| - name: Set up JDK 21 | ||
| uses: actions/setup-java@v5 | ||
| with: | ||
| java-version: '21' | ||
| distribution: 'temurin' | ||
| cache: gradle | ||
| - uses: gradle/actions/setup-gradle@v6 | ||
| - uses: actions/cache@v5 | ||
| with: | ||
| path: | | ||
| ~/.cargo/registry | ||
| ~/.cargo/git | ||
| rust/rust-code/target | ||
| key: ${{ runner.os }}-cargo-android-${{ hashFiles('**/Cargo.lock') }} | ||
| restore-keys: ${{ runner.os }}-cargo-android- | ||
| - name: Grant execute permission for gradlew | ||
| run: chmod +x ./gradlew | ||
| - name: Run unit tests | ||
| run: ./gradlew testDebugUnitTest --continue | ||
|
|
||
| - name: Build Debug APK | ||
| - name: Assemble debug APK | ||
| run: ./gradlew assembleDebug | ||
|
|
||
| - name: Run all unit tests | ||
| run: ./gradlew test | ||
|
|
||
| - name: Run debug-flavor unit tests | ||
| run: ./gradlew testDebugUnitTest | ||
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
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
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
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
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
45 changes: 0 additions & 45 deletions
45
core/identity/src/main/kotlin/de/davis/keygo/core/identity/data/WrappedKeyRepositoryImpl.kt
This file was deleted.
Oops, something went wrong.
39 changes: 33 additions & 6 deletions
39
core/identity/src/main/kotlin/de/davis/keygo/core/identity/data/mapper/ProtoMapper.kt
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,31 +1,58 @@ | ||
| package de.davis.keygo.core.identity.data.mapper | ||
|
|
||
| import com.google.protobuf.kotlin.toByteString | ||
| import de.davis.keygo.core.identity.data.local.model.ProtoAccountState | ||
| import de.davis.keygo.core.identity.data.local.model.ProtoBiometricKeyData | ||
| import de.davis.keygo.core.identity.data.local.model.ProtoPasswordKeyData | ||
| import de.davis.keygo.core.identity.data.local.model.biometricKeyDataOrNull | ||
| import de.davis.keygo.core.identity.data.local.model.protoAccount | ||
| import de.davis.keygo.core.identity.data.local.model.protoAccountState | ||
| import de.davis.keygo.core.identity.data.local.model.protoBiometricKeyData | ||
| import de.davis.keygo.core.identity.data.local.model.protoPasswordKeyData | ||
| import de.davis.keygo.core.identity.domain.model.BiometricWrappedKeyData | ||
| import de.davis.keygo.core.identity.domain.model.PasswordWrappedKeyData | ||
| import de.davis.keygo.core.identity.domain.model.Account | ||
| import de.davis.keygo.core.identity.domain.model.BiometricWrappedArk | ||
| import de.davis.keygo.core.identity.domain.model.PasswordWrappedArk | ||
| import java.util.UUID | ||
|
|
||
| internal fun ProtoBiometricKeyData.toDomain() = BiometricWrappedKeyData( | ||
| internal fun ProtoBiometricKeyData.toDomain() = BiometricWrappedArk( | ||
| key = key.toByteArray(), | ||
| keyIV = keyIV.toByteArray() | ||
| ) | ||
|
|
||
| internal fun BiometricWrappedKeyData.toProto() = protoBiometricKeyData { | ||
| internal fun BiometricWrappedArk.toProto() = protoBiometricKeyData { | ||
| key = this@toProto.key.toByteString() | ||
| keyIV = this@toProto.keyIV.toByteString() | ||
| } | ||
|
|
||
| internal fun ProtoPasswordKeyData.toDomain() = PasswordWrappedKeyData( | ||
| internal fun ProtoPasswordKeyData.toDomain() = PasswordWrappedArk( | ||
| key = key.toByteArray(), | ||
| keyIV = keyIV.toByteArray(), | ||
| salt = salt.toByteArray() | ||
| ) | ||
|
|
||
| internal fun PasswordWrappedKeyData.toProto() = protoPasswordKeyData { | ||
| internal fun PasswordWrappedArk.toProto() = protoPasswordKeyData { | ||
| key = this@toProto.key.toByteString() | ||
| keyIV = this@toProto.keyIV.toByteString() | ||
| salt = this@toProto.salt.toByteString() | ||
| } | ||
|
|
||
| internal fun ProtoAccountState.toDomain() = takeIf { it.hasAccount() }?.account?.let { | ||
| Account( | ||
| id = UUID.fromString(it.userId), | ||
| displayName = it.displayName, | ||
| createdAtEpochMillis = it.createdAtEpochMillis, | ||
| passwordWrappedArk = it.passwordKeyData.toDomain(), | ||
| biometricWrappedArk = it.biometricKeyDataOrNull?.toDomain(), | ||
| ) | ||
| } | ||
|
|
||
| internal fun Account.toProto() = protoAccountState { | ||
| account = protoAccount { | ||
| userId = this@toProto.id.toString() | ||
| displayName = this@toProto.displayName | ||
| createdAtEpochMillis = this@toProto.createdAtEpochMillis | ||
|
|
||
| passwordKeyData = passwordWrappedArk.toProto() | ||
| biometricWrappedArk?.let { biometricKeyData = it.toProto() } | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.