Implement Rust-owned Android Keystore secure storage (#93)
Dependency security audit / rustsec (push) Failing after 23s
Dependency security audit / rustsec (push) Failing after 23s
This commit is contained in:
1 parent
874c8139a4
commit
1abd75282e
36 files changed
+4377
-34
No files matched your search
Generated
+1
@@ -5390,6 +5390,7 @@ checksum = "6a756c3fac73139e83f14c2d742155dd2b78d3ee56597b419a0579b7bdd6dd78"
|
|||||||
name = "ironstorage"
|
name = "ironstorage"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"aes-gcm 0.11.1",
|
||||||
"apple-native-keyring-store",
|
"apple-native-keyring-store",
|
||||||
"arboard",
|
"arboard",
|
||||||
"cap-std",
|
"cap-std",
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ dependencies {
|
|||||||
implementation(project(":features"))
|
implementation(project(":features"))
|
||||||
implementation(project(":core"))
|
implementation(project(":core"))
|
||||||
implementation(project(":platform"))
|
implementation(project(":platform"))
|
||||||
|
implementation(libs.fragment)
|
||||||
implementation(platform(libs.compose.bom))
|
implementation(platform(libs.compose.bom))
|
||||||
implementation(libs.compose.ui)
|
implementation(libs.compose.ui)
|
||||||
implementation(libs.compose.material3)
|
implementation(libs.compose.material3)
|
||||||
|
|||||||
@@ -3,19 +3,24 @@
|
|||||||
# This file is expected to be part of source control.
|
# This file is expected to be part of source control.
|
||||||
# To regenerate this file, run: ./gradlew :app:dependencies --write-locks
|
# To regenerate this file, run: ./gradlew :app:dependencies --write-locks
|
||||||
androidx.activity:activity-compose:1.13.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.activity:activity-compose:1.13.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.activity:activity-ktx:1.13.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.activity:activity-ktx:1.13.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.activity:activity:1.13.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.activity:activity:1.13.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.annotation:annotation-experimental:1.5.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.annotation:annotation-experimental:1.5.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.annotation:annotation-jvm:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.annotation:annotation-jvm:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.annotation:annotation-jvm:1.9.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
androidx.annotation:annotation-jvm:1.9.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
||||||
androidx.annotation:annotation:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.annotation:annotation:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.annotation:annotation:1.9.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
androidx.annotation:annotation:1.9.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
||||||
|
androidx.appcompat:appcompat-resources:1.2.0=debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.appcompat:appcompat:1.2.0=debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.arch.core:core-common:2.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.arch.core:core-common:2.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.arch.core:core-runtime:2.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.arch.core:core-runtime:2.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.autofill:autofill:1.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.autofill:autofill:1.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.collection:collection-jvm:1.5.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.biometric:biometric:1.1.0=debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.collection:collection-ktx:1.5.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.collection:collection-jvm:1.5.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
||||||
androidx.collection:collection:1.5.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.collection:collection-jvm:1.6.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.collection:collection-ktx:1.6.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.collection:collection:1.5.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
||||||
|
androidx.collection:collection:1.6.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.compose.animation:animation-android:1.12.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.compose.animation:animation-android:1.12.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.compose.animation:animation-core-android:1.12.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.compose.animation:animation-core-android:1.12.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.compose.animation:animation-core:1.12.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.compose.animation:animation-core:1.12.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
@@ -62,10 +67,12 @@ androidx.concurrent:concurrent-futures:1.2.0=debugAndroidTestCompileClasspath,de
|
|||||||
androidx.core:core-ktx:1.18.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.core:core-ktx:1.18.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.core:core-viewtree:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.core:core-viewtree:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.core:core:1.18.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.core:core:1.18.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.cursoradapter:cursoradapter:1.0.0=debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.customview:customview-poolingcontainer:1.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.customview:customview-poolingcontainer:1.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.customview:customview:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.customview:customview:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.drawerlayout:drawerlayout:1.0.0=debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.emoji2:emoji2:1.4.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.emoji2:emoji2:1.4.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.fragment:fragment:1.5.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.fragment:fragment:1.9.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.graphics:graphics-path:1.0.1=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.graphics:graphics-path:1.0.1=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.interpolator:interpolator:1.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.interpolator:interpolator:1.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.lifecycle:lifecycle-common-java8:2.11.0=debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.lifecycle:lifecycle-common-java8:2.11.0=debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
@@ -84,7 +91,7 @@ androidx.lifecycle:lifecycle-runtime:2.11.0=debugAndroidTestCompileClasspath,deb
|
|||||||
androidx.lifecycle:lifecycle-viewmodel-android:2.11.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.lifecycle:lifecycle-viewmodel-android:2.11.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.lifecycle:lifecycle-viewmodel-compose-android:2.11.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.lifecycle:lifecycle-viewmodel-compose-android:2.11.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.lifecycle:lifecycle-viewmodel-compose:2.11.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.lifecycle:lifecycle-viewmodel-compose:2.11.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.lifecycle:lifecycle-viewmodel-ktx:2.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.lifecycle:lifecycle-viewmodel-ktx:2.11.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.lifecycle:lifecycle-viewmodel-savedstate-android:2.11.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.lifecycle:lifecycle-viewmodel-savedstate-android:2.11.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.lifecycle:lifecycle-viewmodel-savedstate:2.11.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.lifecycle:lifecycle-viewmodel-savedstate:2.11.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.lifecycle:lifecycle-viewmodel:2.11.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.lifecycle:lifecycle-viewmodel:2.11.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
@@ -101,7 +108,7 @@ androidx.profileinstaller:profileinstaller:1.4.0=debugAndroidTestLintChecksClass
|
|||||||
androidx.savedstate:savedstate-android:1.4.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.savedstate:savedstate-android:1.4.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.savedstate:savedstate-compose-android:1.4.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.savedstate:savedstate-compose-android:1.4.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.savedstate:savedstate-compose:1.4.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.savedstate:savedstate-compose:1.4.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.savedstate:savedstate-ktx:1.4.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.savedstate:savedstate-ktx:1.4.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.savedstate:savedstate:1.4.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.savedstate:savedstate:1.4.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.startup:startup-runtime:1.1.1=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.startup:startup-runtime:1.1.1=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.test.espresso:espresso-core:3.7.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
androidx.test.espresso:espresso-core:3.7.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
@@ -111,8 +118,11 @@ androidx.test.services:storage:1.6.0=debugAndroidTestCompileClasspath,debugAndro
|
|||||||
androidx.test:core:1.7.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
androidx.test:core:1.7.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
androidx.test:monitor:1.8.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
androidx.test:monitor:1.8.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
androidx.test:runner:1.7.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
androidx.test:runner:1.7.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
|
androidx.tracing:tracing-android:2.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.tracing:tracing:1.1.0=debugAndroidTestCompileClasspath
|
androidx.tracing:tracing:1.1.0=debugAndroidTestCompileClasspath
|
||||||
androidx.tracing:tracing:1.2.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.tracing:tracing:2.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.vectordrawable:vectordrawable-animated:1.1.0=debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.vectordrawable:vectordrawable:1.1.0=debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.window:window-core-android:1.5.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.window:window-core-android:1.5.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||||
<application
|
<application
|
||||||
android:name=".IronStorageApplication"
|
android:name=".IronStorageApplication"
|
||||||
android:allowBackup="false"
|
android:allowBackup="false"
|
||||||
|
|||||||
@@ -1,24 +1,33 @@
|
|||||||
package de.rfc1437.ironstorage
|
package de.rfc1437.ironstorage
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.ComponentActivity
|
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.fragment.app.FragmentActivity
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import de.rfc1437.ironstorage.core.ShellRepository
|
import de.rfc1437.ironstorage.core.ShellRepository
|
||||||
import de.rfc1437.ironstorage.features.ShellViewModel
|
import de.rfc1437.ironstorage.features.ShellViewModel
|
||||||
|
import de.rfc1437.ironstorage.platform.AndroidKeystoreAdapter
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : FragmentActivity() {
|
||||||
|
@Inject lateinit var keystore: AndroidKeystoreAdapter
|
||||||
|
|
||||||
@Inject lateinit var repository: ShellRepository
|
@Inject lateinit var repository: ShellRepository
|
||||||
|
|
||||||
private val viewModel: ShellViewModel by viewModels()
|
private val viewModel: ShellViewModel by viewModels()
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
keystore.detach(this)
|
||||||
|
super.onDestroy()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
keystore.attach(this)
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
setContent {
|
setContent {
|
||||||
MaterialTheme {
|
MaterialTheme {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import dagger.hilt.android.qualifiers.ApplicationContext
|
|||||||
import dagger.hilt.components.SingletonComponent
|
import dagger.hilt.components.SingletonComponent
|
||||||
import de.rfc1437.ironstorage.core.NativeFixtureShellRepository
|
import de.rfc1437.ironstorage.core.NativeFixtureShellRepository
|
||||||
import de.rfc1437.ironstorage.core.ShellRepository
|
import de.rfc1437.ironstorage.core.ShellRepository
|
||||||
|
import de.rfc1437.ironstorage.platform.AndroidKeystoreAdapter
|
||||||
import de.rfc1437.ironstorage.platform.privateDirectories
|
import de.rfc1437.ironstorage.platform.privateDirectories
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
@@ -19,10 +20,18 @@ import kotlinx.coroutines.SupervisorJob
|
|||||||
object ShellModule {
|
object ShellModule {
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun shellRepository(@ApplicationContext context: Context): ShellRepository =
|
fun keystore(@ApplicationContext context: Context): AndroidKeystoreAdapter =
|
||||||
NativeFixtureShellRepository(
|
AndroidKeystoreAdapter(context)
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun shellRepository(
|
||||||
|
@ApplicationContext context: Context,
|
||||||
|
keystore: AndroidKeystoreAdapter
|
||||||
|
): ShellRepository = NativeFixtureShellRepository(
|
||||||
context,
|
context,
|
||||||
CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate),
|
CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate),
|
||||||
{ privateDirectories(context) }
|
{ privateDirectories(context) },
|
||||||
|
keystore
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package de.rfc1437.ironstorage.core
|
||||||
|
|
||||||
|
/** OS facts and cipher mechanics. Rust chooses policy, aliases and persistence. */
|
||||||
|
class KeystoreDeviceState(
|
||||||
|
val api: Int,
|
||||||
|
val locked: Boolean,
|
||||||
|
val secure: Boolean,
|
||||||
|
val strongBiometric: Boolean,
|
||||||
|
val strongbox: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
|
enum class KeystoreAuthorization { None, StrongBiometric, UserPresence }
|
||||||
|
|
||||||
|
class KeystoreKeySpecification(
|
||||||
|
val alias: String,
|
||||||
|
val authorization: KeystoreAuthorization,
|
||||||
|
val unlockedDevice: Boolean,
|
||||||
|
val invalidateOnEnrollment: Boolean,
|
||||||
|
val strongbox: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
|
class KeystoreCiphertext(val nonce: ByteArray, val bytes: ByteArray)
|
||||||
|
|
||||||
|
enum class KeystoreFailure {
|
||||||
|
MissingKey,
|
||||||
|
Invalidated,
|
||||||
|
Lockout,
|
||||||
|
Locked,
|
||||||
|
Denied,
|
||||||
|
Cancelled,
|
||||||
|
Corrupted,
|
||||||
|
UnsupportedProtection,
|
||||||
|
StrongboxUnavailable,
|
||||||
|
AlreadyExists,
|
||||||
|
Unavailable
|
||||||
|
}
|
||||||
|
|
||||||
|
class KeystoreException(val kind: KeystoreFailure) : Exception("Keystore operation failed")
|
||||||
|
|
||||||
|
interface AndroidKeystore {
|
||||||
|
fun deviceState(): KeystoreDeviceState
|
||||||
|
fun createKey(specification: KeystoreKeySpecification)
|
||||||
|
fun encrypt(
|
||||||
|
alias: String,
|
||||||
|
authorization: KeystoreAuthorization,
|
||||||
|
aad: ByteArray,
|
||||||
|
value: ByteArray
|
||||||
|
): KeystoreCiphertext
|
||||||
|
fun decrypt(
|
||||||
|
alias: String,
|
||||||
|
authorization: KeystoreAuthorization,
|
||||||
|
aad: ByteArray,
|
||||||
|
value: KeystoreCiphertext
|
||||||
|
): ByteArray
|
||||||
|
fun deleteKey(alias: String)
|
||||||
|
fun aliases(): List<String>
|
||||||
|
fun cancelPending()
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package de.rfc1437.ironstorage.core
|
||||||
|
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobileAndroidAuthorization
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobileAndroidCiphertext
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobileAndroidDeviceState
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobileAndroidKeySpecification
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobileAndroidKeystore
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobileAndroidKeystoreException
|
||||||
|
|
||||||
|
internal class KeystoreCallback(private val os: AndroidKeystore) : MobileAndroidKeystore {
|
||||||
|
override fun deviceState(): MobileAndroidDeviceState = call {
|
||||||
|
val s = os.deviceState()
|
||||||
|
MobileAndroidDeviceState(s.api.toUInt(), s.locked, s.secure, s.strongBiometric, s.strongbox)
|
||||||
|
}
|
||||||
|
override fun createKey(specification: MobileAndroidKeySpecification) = call {
|
||||||
|
os.createKey(
|
||||||
|
KeystoreKeySpecification(
|
||||||
|
specification.alias,
|
||||||
|
specification.authorization.toOs(),
|
||||||
|
specification.unlockedDevice,
|
||||||
|
specification.invalidateOnEnrollment,
|
||||||
|
specification.strongbox
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
override fun encrypt(
|
||||||
|
alias: String,
|
||||||
|
authorization: MobileAndroidAuthorization,
|
||||||
|
aad: ByteArray,
|
||||||
|
value: ByteArray
|
||||||
|
): MobileAndroidCiphertext = call {
|
||||||
|
try {
|
||||||
|
val result = os.encrypt(alias, authorization.toOs(), aad, value)
|
||||||
|
MobileAndroidCiphertext(result.nonce, result.bytes)
|
||||||
|
} finally {
|
||||||
|
value.fill(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override fun decrypt(
|
||||||
|
alias: String,
|
||||||
|
authorization: MobileAndroidAuthorization,
|
||||||
|
aad: ByteArray,
|
||||||
|
value: MobileAndroidCiphertext
|
||||||
|
): ByteArray = call {
|
||||||
|
os.decrypt(alias, authorization.toOs(), aad, KeystoreCiphertext(value.nonce, value.bytes))
|
||||||
|
}
|
||||||
|
override fun deleteKey(alias: String) = call { os.deleteKey(alias) }
|
||||||
|
override fun aliases(): List<String> = call { os.aliases() }
|
||||||
|
override fun cancelPending() = os.cancelPending()
|
||||||
|
}
|
||||||
|
private fun MobileAndroidAuthorization.toOs(): KeystoreAuthorization = when (this) {
|
||||||
|
MobileAndroidAuthorization.NONE -> KeystoreAuthorization.None
|
||||||
|
MobileAndroidAuthorization.STRONG_BIOMETRIC -> KeystoreAuthorization.StrongBiometric
|
||||||
|
MobileAndroidAuthorization.USER_PRESENCE -> KeystoreAuthorization.UserPresence
|
||||||
|
}
|
||||||
|
private inline fun <T> call(block: () -> T): T = try {
|
||||||
|
block()
|
||||||
|
} catch (error: KeystoreException) {
|
||||||
|
throw when (error.kind) {
|
||||||
|
KeystoreFailure.MissingKey -> MobileAndroidKeystoreException.MissingKey()
|
||||||
|
KeystoreFailure.Invalidated -> MobileAndroidKeystoreException.Invalidated()
|
||||||
|
KeystoreFailure.Lockout -> MobileAndroidKeystoreException.Lockout()
|
||||||
|
KeystoreFailure.Locked -> MobileAndroidKeystoreException.Locked()
|
||||||
|
KeystoreFailure.Denied -> MobileAndroidKeystoreException.Denied()
|
||||||
|
KeystoreFailure.Cancelled -> MobileAndroidKeystoreException.Cancelled()
|
||||||
|
KeystoreFailure.Corrupted -> MobileAndroidKeystoreException.Corrupted()
|
||||||
|
KeystoreFailure.UnsupportedProtection ->
|
||||||
|
MobileAndroidKeystoreException.UnsupportedProtection()
|
||||||
|
KeystoreFailure.StrongboxUnavailable ->
|
||||||
|
MobileAndroidKeystoreException.StrongboxUnavailable()
|
||||||
|
KeystoreFailure.AlreadyExists -> MobileAndroidKeystoreException.AlreadyExists()
|
||||||
|
KeystoreFailure.Unavailable -> MobileAndroidKeystoreException.Unavailable()
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
-3
@@ -27,8 +27,13 @@ class NativeFixtureShellRepository internal constructor(
|
|||||||
private val scope: CoroutineScope,
|
private val scope: CoroutineScope,
|
||||||
private val load: suspend (ShellState) -> ShellSnapshot
|
private val load: suspend (ShellState) -> ShellSnapshot
|
||||||
) : ShellRepository {
|
) : ShellRepository {
|
||||||
constructor(context: Context, scope: CoroutineScope, directories: () -> PrivateDirectories) :
|
constructor(
|
||||||
this(scope, nativeLoader(context, directories))
|
context: Context,
|
||||||
|
scope: CoroutineScope,
|
||||||
|
directories: () -> PrivateDirectories,
|
||||||
|
keystore: AndroidKeystore
|
||||||
|
) :
|
||||||
|
this(scope, nativeLoader(context, directories, keystore))
|
||||||
private val mutableSnapshot = MutableStateFlow(ShellSnapshot(ShellState.Loading, emptyList()))
|
private val mutableSnapshot = MutableStateFlow(ShellSnapshot(ShellState.Loading, emptyList()))
|
||||||
override val snapshot: StateFlow<ShellSnapshot> = mutableSnapshot
|
override val snapshot: StateFlow<ShellSnapshot> = mutableSnapshot
|
||||||
private val revision = AtomicLong()
|
private val revision = AtomicLong()
|
||||||
@@ -64,7 +69,8 @@ class NativeFixtureShellRepository internal constructor(
|
|||||||
|
|
||||||
private fun nativeLoader(
|
private fun nativeLoader(
|
||||||
context: Context,
|
context: Context,
|
||||||
directoryProvider: () -> PrivateDirectories
|
directoryProvider: () -> PrivateDirectories,
|
||||||
|
keystore: AndroidKeystore
|
||||||
): suspend (ShellState) -> ShellSnapshot {
|
): suspend (ShellState) -> ShellSnapshot {
|
||||||
val runtime = NativeRuntime(context)
|
val runtime = NativeRuntime(context)
|
||||||
var storage: MobilePrivateRuntime? = null
|
var storage: MobilePrivateRuntime? = null
|
||||||
@@ -85,6 +91,8 @@ private fun nativeLoader(
|
|||||||
)
|
)
|
||||||
storage = initialized
|
storage = initialized
|
||||||
initialized.activate()
|
initialized.activate()
|
||||||
|
val secrets = initialized.androidSecretBackend(KeystoreCallback(keystore))
|
||||||
|
initialized.verifySecureStorage(secrets)
|
||||||
recovery = initialized.status().recovery?.toFacade()
|
recovery = initialized.status().recovery?.toFacade()
|
||||||
initialized.shell()
|
initialized.shell()
|
||||||
} catch (error: MobilePrivateStorageFfiException.Failed) {
|
} catch (error: MobilePrivateStorageFfiException.Failed) {
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ cargoNdk = "4.1.2"
|
|||||||
jna = "5.19.1"
|
jna = "5.19.1"
|
||||||
annotation = "1.11.0"
|
annotation = "1.11.0"
|
||||||
|
|
||||||
|
biometric = "1.1.0"
|
||||||
|
fragment = "1.9.1"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
compose-bom = { module = "androidx.compose:compose-bom", version.ref = "compose" }
|
compose-bom = { module = "androidx.compose:compose-bom", version.ref = "compose" }
|
||||||
compose-ui = { module = "androidx.compose.ui:ui" }
|
compose-ui = { module = "androidx.compose.ui:ui" }
|
||||||
@@ -39,11 +42,15 @@ coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", ve
|
|||||||
hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hilt" }
|
hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hilt" }
|
||||||
hilt-compiler = { module = "com.google.dagger:hilt-compiler", version.ref = "hilt" }
|
hilt-compiler = { module = "com.google.dagger:hilt-compiler", version.ref = "hilt" }
|
||||||
junit = { module = "junit:junit", version.ref = "junit" }
|
junit = { module = "junit:junit", version.ref = "junit" }
|
||||||
|
android-test-core = { module = "androidx.test:core", version.ref = "androidTest" }
|
||||||
android-test-runner = { module = "androidx.test:runner", version.ref = "androidTest" }
|
android-test-runner = { module = "androidx.test:runner", version.ref = "androidTest" }
|
||||||
android-test-espresso = { module = "androidx.test.espresso:espresso-core", version.ref = "espresso" }
|
android-test-espresso = { module = "androidx.test.espresso:espresso-core", version.ref = "espresso" }
|
||||||
jna = { module = "net.java.dev.jna:jna", version.ref = "jna" }
|
jna = { module = "net.java.dev.jna:jna", version.ref = "jna" }
|
||||||
annotation = { module = "androidx.annotation:annotation", version.ref = "annotation" }
|
annotation = { module = "androidx.annotation:annotation", version.ref = "annotation" }
|
||||||
|
|
||||||
|
biometric = { module = "androidx.biometric:biometric", version.ref = "biometric" }
|
||||||
|
fragment = { module = "androidx.fragment:fragment", version.ref = "fragment" }
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||||
android-library = { id = "com.android.library", version.ref = "agp" }
|
android-library = { id = "com.android.library", version.ref = "agp" }
|
||||||
|
|||||||
@@ -5,6 +5,11 @@
|
|||||||
<verify-signatures>false</verify-signatures>
|
<verify-signatures>false</verify-signatures>
|
||||||
</configuration>
|
</configuration>
|
||||||
<components>
|
<components>
|
||||||
|
<component group="androidx.activity" name="activity" version="1.1.0">
|
||||||
|
<artifact name="activity-1.1.0.pom">
|
||||||
|
<sha256 value="3690001fc5a57ad176cacf7a13f56219bffb73b93c7978dbac1e1e5db082d6c0" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.activity" name="activity" version="1.12.0">
|
<component group="androidx.activity" name="activity" version="1.12.0">
|
||||||
<artifact name="activity-1.12.0.aar">
|
<artifact name="activity-1.12.0.aar">
|
||||||
<sha256 value="1af72f689de924143a03fe5b6f698a7170d7aea842f71307746e8d1db8bbfeeb" origin="Generated by Gradle"/>
|
<sha256 value="1af72f689de924143a03fe5b6f698a7170d7aea842f71307746e8d1db8bbfeeb" origin="Generated by Gradle"/>
|
||||||
@@ -26,6 +31,14 @@
|
|||||||
<sha256 value="c4317fb95ce2716b88f1f4a5334795efda084097a3f2447ffccb10a412c85be4" origin="Generated by Gradle"/>
|
<sha256 value="c4317fb95ce2716b88f1f4a5334795efda084097a3f2447ffccb10a412c85be4" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.activity" name="activity" version="1.8.1">
|
||||||
|
<artifact name="activity-1.8.1.aar">
|
||||||
|
<sha256 value="66bc2c13bd91fb8ea09e445b21f784d3e5d3a9ec9b180cd07e0e9208c2f939c6" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="activity-1.8.1.module">
|
||||||
|
<sha256 value="bc21549bdb908da2eeccb4ac81aef9996f8faf7b52b9c840c36a348b0579403a" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.activity" name="activity-compose" version="1.12.0">
|
<component group="androidx.activity" name="activity-compose" version="1.12.0">
|
||||||
<artifact name="activity-compose-1.12.0.aar">
|
<artifact name="activity-compose-1.12.0.aar">
|
||||||
<sha256 value="056a0700aa7e7cf5f7be1eebb32a70534b63a662c1b7408c1f2b099d75a0d13f" origin="Generated by Gradle"/>
|
<sha256 value="056a0700aa7e7cf5f7be1eebb32a70534b63a662c1b7408c1f2b099d75a0d13f" origin="Generated by Gradle"/>
|
||||||
@@ -63,11 +76,32 @@
|
|||||||
<sha256 value="f4001a709b6f7132b22a5e17c24f8b8a9b3c462a598de3b0f16cc57a4344bab6" origin="Generated by Gradle"/>
|
<sha256 value="f4001a709b6f7132b22a5e17c24f8b8a9b3c462a598de3b0f16cc57a4344bab6" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.activity" name="activity-ktx" version="1.8.1">
|
||||||
|
<artifact name="activity-ktx-1.8.1.aar">
|
||||||
|
<sha256 value="9f77caa2bbec7ceefa5c931e2f223c2b386a594ee0442d168dfeaf1c850aeb9d" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="activity-ktx-1.8.1.module">
|
||||||
|
<sha256 value="bea2f811b8d8c1b8a835e11d3c68219097c597c458429d3ceafd728e0ca2c6d1" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.annotation" name="annotation" version="1.1.0">
|
||||||
|
<artifact name="annotation-1.1.0.pom">
|
||||||
|
<sha256 value="2e9372ba7780ef44952adbf86b66e1f08682c1e5277c926185f6564a13799efe" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.annotation" name="annotation" version="1.11.0">
|
<component group="androidx.annotation" name="annotation" version="1.11.0">
|
||||||
<artifact name="annotation-1.11.0.module">
|
<artifact name="annotation-1.11.0.module">
|
||||||
<sha256 value="ac8410bea7adaabc9e71285f0627c9cb929c5addd00cfc6d0ebd421dc2da1ee0" origin="Generated by Gradle"/>
|
<sha256 value="ac8410bea7adaabc9e71285f0627c9cb929c5addd00cfc6d0ebd421dc2da1ee0" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.annotation" name="annotation" version="1.2.0">
|
||||||
|
<artifact name="annotation-1.2.0.jar">
|
||||||
|
<sha256 value="9029262bddce116e6d02be499e4afdba21f24c239087b76b3b57d7e98b490a36" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="annotation-1.2.0.module">
|
||||||
|
<sha256 value="2efcab81ef91b211bacd206eaacd995a51f633a2e96b57a8fc00144c5f9c56b3" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.annotation" name="annotation" version="1.7.0">
|
<component group="androidx.annotation" name="annotation" version="1.7.0">
|
||||||
<artifact name="annotation-1.7.0.module">
|
<artifact name="annotation-1.7.0.module">
|
||||||
<sha256 value="530708656d380605077ea8bca9ae1372fbd1af38e375f411d4e43263bd510c3c" origin="Generated by Gradle"/>
|
<sha256 value="530708656d380605077ea8bca9ae1372fbd1af38e375f411d4e43263bd510c3c" origin="Generated by Gradle"/>
|
||||||
@@ -78,6 +112,11 @@
|
|||||||
<sha256 value="ac94dfef4f82ccd2ca7573a53779dbf3dfab650e654056a4d4df90af43572990" origin="Generated by Gradle"/>
|
<sha256 value="ac94dfef4f82ccd2ca7573a53779dbf3dfab650e654056a4d4df90af43572990" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.annotation" name="annotation" version="1.8.1">
|
||||||
|
<artifact name="annotation-1.8.1.module">
|
||||||
|
<sha256 value="e6386e85afdd865044e216575e493ed39a63a6325bd925379a21429c3941c8b5" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.annotation" name="annotation" version="1.9.1">
|
<component group="androidx.annotation" name="annotation" version="1.9.1">
|
||||||
<artifact name="annotation-1.9.1.module">
|
<artifact name="annotation-1.9.1.module">
|
||||||
<sha256 value="f204b05b728a97561718bc716242e47c629c0085a80ee74fca53d4d638bcbe3f" origin="Generated by Gradle"/>
|
<sha256 value="f204b05b728a97561718bc716242e47c629c0085a80ee74fca53d4d638bcbe3f" origin="Generated by Gradle"/>
|
||||||
@@ -88,6 +127,22 @@
|
|||||||
<sha256 value="9b6974a7dfe26d3c209dd63e16f8ee2461b57a091789160ca1eb492bb1bf3f84" origin="Generated by Gradle"/>
|
<sha256 value="9b6974a7dfe26d3c209dd63e16f8ee2461b57a091789160ca1eb492bb1bf3f84" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.annotation" name="annotation-experimental" version="1.4.0">
|
||||||
|
<artifact name="annotation-experimental-1.4.0.aar">
|
||||||
|
<sha256 value="c6eb7e676011ec65b32428373d450debdfc45179c4f8b3a752174fb87c17b08a" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="annotation-experimental-1.4.0.module">
|
||||||
|
<sha256 value="5930ea7f21fcb6d0deb2ba32748a0ef7c8fd2c42384860582ba7cd20deb90379" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.annotation" name="annotation-experimental" version="1.4.1">
|
||||||
|
<artifact name="annotation-experimental-1.4.1.aar">
|
||||||
|
<sha256 value="6bd4c7c7476f8260cd3bdbb81183583e93fc9f790c27dea7dc314181cbf87aa0" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="annotation-experimental-1.4.1.module">
|
||||||
|
<sha256 value="2ac2f7106e12f263425b4a4dfc80989447fb895675fe902d86759aa74fd12b7d" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.annotation" name="annotation-experimental" version="1.5.1">
|
<component group="androidx.annotation" name="annotation-experimental" version="1.5.1">
|
||||||
<artifact name="annotation-experimental-1.5.1.aar">
|
<artifact name="annotation-experimental-1.5.1.aar">
|
||||||
<sha256 value="323a119b32e91d44e932fb97ed28eb568ca2a9d3ba57ec09392074b5c5e24ad4" origin="Generated by Gradle"/>
|
<sha256 value="323a119b32e91d44e932fb97ed28eb568ca2a9d3ba57ec09392074b5c5e24ad4" origin="Generated by Gradle"/>
|
||||||
@@ -112,6 +167,11 @@
|
|||||||
<sha256 value="07ce60c377ab94e47c8c902589b9776030064fd1a7e4d5a01a38d700e35e5db4" origin="Generated by Gradle"/>
|
<sha256 value="07ce60c377ab94e47c8c902589b9776030064fd1a7e4d5a01a38d700e35e5db4" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.annotation" name="annotation-jvm" version="1.8.1">
|
||||||
|
<artifact name="annotation-jvm-1.8.1.module">
|
||||||
|
<sha256 value="c959e3b0cdc75c15efe01605fa56aa79f033e39238e150638b8fabde6aa121a0" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.annotation" name="annotation-jvm" version="1.9.1">
|
<component group="androidx.annotation" name="annotation-jvm" version="1.9.1">
|
||||||
<artifact name="annotation-jvm-1.9.1.jar">
|
<artifact name="annotation-jvm-1.9.1.jar">
|
||||||
<sha256 value="1e343917ebf27ba96fe4dc52b1cad7fd32b738fbc6355bb6cd5b3b305d7212d0" origin="Generated by Gradle"/>
|
<sha256 value="1e343917ebf27ba96fe4dc52b1cad7fd32b738fbc6355bb6cd5b3b305d7212d0" origin="Generated by Gradle"/>
|
||||||
@@ -120,6 +180,27 @@
|
|||||||
<sha256 value="03fb659177c8618e47425925c11bc91f384703ea26c265be9b25cd79292b511c" origin="Generated by Gradle"/>
|
<sha256 value="03fb659177c8618e47425925c11bc91f384703ea26c265be9b25cd79292b511c" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.appcompat" name="appcompat" version="1.2.0">
|
||||||
|
<artifact name="appcompat-1.2.0.aar">
|
||||||
|
<sha256 value="3d2131a55a61a777322e2126e0018011efa6339e53b44153eb651b16020cca70" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="appcompat-1.2.0.module">
|
||||||
|
<sha256 value="2670902fc6c26047c42e0f60ee34656fa071841db370de958198413b5ab58fc3" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.appcompat" name="appcompat-resources" version="1.2.0">
|
||||||
|
<artifact name="appcompat-resources-1.2.0.aar">
|
||||||
|
<sha256 value="c470297c03ff3de1c3d15dacf0be0cae63abc10b52f021dd07ae28daa3100fe5" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="appcompat-resources-1.2.0.module">
|
||||||
|
<sha256 value="75d9865bc6b0f779043b4f6523a944bd2ccb7526f5c1f5ef24624ac78dec3bd3" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.arch.core" name="core-common" version="2.1.0">
|
||||||
|
<artifact name="core-common-2.1.0.pom">
|
||||||
|
<sha256 value="83bbb3960eaabc600ac366c94cb59414e441532a1d6aa9388b0b8bfface5cf01" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.arch.core" name="core-common" version="2.2.0">
|
<component group="androidx.arch.core" name="core-common" version="2.2.0">
|
||||||
<artifact name="core-common-2.2.0.jar">
|
<artifact name="core-common-2.2.0.jar">
|
||||||
<sha256 value="65308a06b1c00ee186cb9e19321383f043b993813f1522c47f4a3e3303bdba41" origin="Generated by Gradle"/>
|
<sha256 value="65308a06b1c00ee186cb9e19321383f043b993813f1522c47f4a3e3303bdba41" origin="Generated by Gradle"/>
|
||||||
@@ -128,6 +209,14 @@
|
|||||||
<sha256 value="edf4200cfdc2d946232252c99e5dcb9c61bb909eb5450b2613d1d4fdc974b981" origin="Generated by Gradle"/>
|
<sha256 value="edf4200cfdc2d946232252c99e5dcb9c61bb909eb5450b2613d1d4fdc974b981" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.arch.core" name="core-runtime" version="2.1.0">
|
||||||
|
<artifact name="core-runtime-2.1.0.aar">
|
||||||
|
<sha256 value="dd77615bd3dd275afb11b62df25bae46b10b4a117cd37943af45bdcbf8755852" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="core-runtime-2.1.0.pom">
|
||||||
|
<sha256 value="c0c4ed0160cd2ca18390015de8b392b697c173327c6b2c0947d4e62f6958c05d" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.arch.core" name="core-runtime" version="2.2.0">
|
<component group="androidx.arch.core" name="core-runtime" version="2.2.0">
|
||||||
<artifact name="core-runtime-2.2.0.aar">
|
<artifact name="core-runtime-2.2.0.aar">
|
||||||
<sha256 value="a1be5e0caa2b07623862af6ae21b3ab0718123245184d0e30dea81b53f990a47" origin="Generated by Gradle"/>
|
<sha256 value="a1be5e0caa2b07623862af6ae21b3ab0718123245184d0e30dea81b53f990a47" origin="Generated by Gradle"/>
|
||||||
@@ -144,16 +233,50 @@
|
|||||||
<sha256 value="3677abead5d4e06cf76cbacb954151e051779c2274494451fb424e375aa9e450" origin="Generated by Gradle"/>
|
<sha256 value="3677abead5d4e06cf76cbacb954151e051779c2274494451fb424e375aa9e450" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.biometric" name="biometric" version="1.1.0">
|
||||||
|
<artifact name="biometric-1.1.0.aar">
|
||||||
|
<sha256 value="270c7b7d99942d5ec1dd88594e4648feb33d8e31d8c3c2ab2321d49d9abdfc1f" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="biometric-1.1.0.module">
|
||||||
|
<sha256 value="4999f205b2b38e31180ad58111e32d564190c2024fbfd58527e2da8bfb67ff65" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.collection" name="collection" version="1.0.0">
|
||||||
|
<artifact name="collection-1.0.0.pom">
|
||||||
|
<sha256 value="a7913a5275ad68e555d2612ebe8c14c367b153e14ca48a1872a64899020e54ef" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.collection" name="collection" version="1.1.0">
|
<component group="androidx.collection" name="collection" version="1.1.0">
|
||||||
|
<artifact name="collection-1.1.0.jar">
|
||||||
|
<sha256 value="632a0e5407461de774409352940e292a291037724207a787820c77daf7d33b72" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
<artifact name="collection-1.1.0.pom">
|
<artifact name="collection-1.1.0.pom">
|
||||||
<sha256 value="67e9066ca4acfdc6e3cc508293c31ba0398057ff118e4f70b1e1813c9a3456d1" origin="Generated by Gradle"/>
|
<sha256 value="67e9066ca4acfdc6e3cc508293c31ba0398057ff118e4f70b1e1813c9a3456d1" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.collection" name="collection" version="1.4.2">
|
||||||
|
<artifact name="collection-1.4.2.module">
|
||||||
|
<sha256 value="0326d2cf5adbe592312810ca1f71c6c0cc30f753c43f07c7402361b788a7784c" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.collection" name="collection" version="1.5.0">
|
<component group="androidx.collection" name="collection" version="1.5.0">
|
||||||
<artifact name="collection-1.5.0.module">
|
<artifact name="collection-1.5.0.module">
|
||||||
<sha256 value="bfeb7bd84f3f7dda7bd73b6709d4a1f61f5a37f843728bae08a067e3df9a0aef" origin="Generated by Gradle"/>
|
<sha256 value="bfeb7bd84f3f7dda7bd73b6709d4a1f61f5a37f843728bae08a067e3df9a0aef" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.collection" name="collection" version="1.6.0">
|
||||||
|
<artifact name="collection-1.6.0.module">
|
||||||
|
<sha256 value="2cad9397bf1cce162f14732b3cfcefa36081b422e35a17b6c3c9c0d617ec523b" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.collection" name="collection-jvm" version="1.4.2">
|
||||||
|
<artifact name="collection-jvm-1.4.2.jar">
|
||||||
|
<sha256 value="984ce9bd780055eafb8a105aca3f514686bf7b1b6272ec7c645a98ce40fc7db4" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="collection-jvm-1.4.2.module">
|
||||||
|
<sha256 value="aad6b3536c0f0e570aa733d5141d70fa6b9b3add370f73a311ca4ca5dee25448" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.collection" name="collection-jvm" version="1.5.0">
|
<component group="androidx.collection" name="collection-jvm" version="1.5.0">
|
||||||
<artifact name="collection-jvm-1.5.0.jar">
|
<artifact name="collection-jvm-1.5.0.jar">
|
||||||
<sha256 value="70b35924e4babcdffa37d0e575ee039c56a2d97123342624c48b603233704341" origin="Generated by Gradle"/>
|
<sha256 value="70b35924e4babcdffa37d0e575ee039c56a2d97123342624c48b603233704341" origin="Generated by Gradle"/>
|
||||||
@@ -162,6 +285,27 @@
|
|||||||
<sha256 value="dde85e292509231b5471bb091b575099d4f43161eb281e87385038a0161072e6" origin="Generated by Gradle"/>
|
<sha256 value="dde85e292509231b5471bb091b575099d4f43161eb281e87385038a0161072e6" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.collection" name="collection-jvm" version="1.6.0">
|
||||||
|
<artifact name="collection-jvm-1.6.0.jar">
|
||||||
|
<sha256 value="839fcec147704611a222159fa84e3e062f68eee80caa549ddd1222d5210a13df" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="collection-jvm-1.6.0.module">
|
||||||
|
<sha256 value="28d88aee55c1b5c02640cfcda134a793e2cee40ea815561dd8f6174de883dc59" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.collection" name="collection-ktx" version="1.1.0">
|
||||||
|
<artifact name="collection-ktx-1.1.0.jar">
|
||||||
|
<sha256 value="2bfc54475c047131913361f56d0f7f019c6e5bee53eeb0eb7d94a7c499a05227" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="collection-ktx-1.1.0.pom">
|
||||||
|
<sha256 value="721e76e74ee4158d3fe9759074b7eceed4ff7d84ed34a3faca5843fb874ac946" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.collection" name="collection-ktx" version="1.4.2">
|
||||||
|
<artifact name="collection-ktx-1.4.2.module">
|
||||||
|
<sha256 value="8a68e297cd92c80789acc033e2b3d7cbd7941f9234335f00c037205df200bcf5" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.collection" name="collection-ktx" version="1.5.0">
|
<component group="androidx.collection" name="collection-ktx" version="1.5.0">
|
||||||
<artifact name="collection-ktx-1.5.0.jar">
|
<artifact name="collection-ktx-1.5.0.jar">
|
||||||
<sha256 value="939b4a8697640e77d83e4e8b4c4a9d18f8130198c5961194af8dd9db9dc7c353" origin="Generated by Gradle"/>
|
<sha256 value="939b4a8697640e77d83e4e8b4c4a9d18f8130198c5961194af8dd9db9dc7c353" origin="Generated by Gradle"/>
|
||||||
@@ -170,6 +314,14 @@
|
|||||||
<sha256 value="4228894e25eec7e17329b206ba72e8aad255bc535018dc62acc5eff3b5c7aaa5" origin="Generated by Gradle"/>
|
<sha256 value="4228894e25eec7e17329b206ba72e8aad255bc535018dc62acc5eff3b5c7aaa5" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.collection" name="collection-ktx" version="1.6.0">
|
||||||
|
<artifact name="collection-ktx-1.6.0.jar">
|
||||||
|
<sha256 value="939b4a8697640e77d83e4e8b4c4a9d18f8130198c5961194af8dd9db9dc7c353" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="collection-ktx-1.6.0.module">
|
||||||
|
<sha256 value="9d79ed80238d17125ead24a57fd7f9032ac4cda71c99710f60d7eb62a34fffae" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.compose" name="compose-bom" version="2026.09.00">
|
<component group="androidx.compose" name="compose-bom" version="2026.09.00">
|
||||||
<artifact name="compose-bom-2026.09.00.pom">
|
<artifact name="compose-bom-2026.09.00.pom">
|
||||||
<sha256 value="74791c31313009659bd0bf09008bd514a163aa04452dd4cb82df2fb971c757c3" origin="Generated by Gradle"/>
|
<sha256 value="74791c31313009659bd0bf09008bd514a163aa04452dd4cb82df2fb971c757c3" origin="Generated by Gradle"/>
|
||||||
@@ -464,6 +616,14 @@
|
|||||||
<sha256 value="384d529ad668ada4808de29b29a6348f0007c2841ad79cae9a5a089bd68810f5" origin="Generated by Gradle"/>
|
<sha256 value="384d529ad668ada4808de29b29a6348f0007c2841ad79cae9a5a089bd68810f5" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.core" name="core" version="1.13.1">
|
||||||
|
<artifact name="core-1.13.1.aar">
|
||||||
|
<sha256 value="2c27de199535675005553066597a4b20fa1eea7c228ab4ef6b32b5fe39ca1f59" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="core-1.13.1.module">
|
||||||
|
<sha256 value="2a10979bbb3bcd7b25b7f664ab4e9b016fabf2174a26768b677e12e4bea4c7c4" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.core" name="core" version="1.16.0">
|
<component group="androidx.core" name="core" version="1.16.0">
|
||||||
<artifact name="core-1.16.0.aar">
|
<artifact name="core-1.16.0.aar">
|
||||||
<sha256 value="6bf03d39dbe3744acce227d3b697374c3625aae1025fbec8ad9fd7bd58bce431" origin="Generated by Gradle"/>
|
<sha256 value="6bf03d39dbe3744acce227d3b697374c3625aae1025fbec8ad9fd7bd58bce431" origin="Generated by Gradle"/>
|
||||||
@@ -480,11 +640,24 @@
|
|||||||
<sha256 value="b67ff7a1f9be95687dfa86d6055147fc1d8bbe3b1dc19048c432afca18abfd95" origin="Generated by Gradle"/>
|
<sha256 value="b67ff7a1f9be95687dfa86d6055147fc1d8bbe3b1dc19048c432afca18abfd95" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.core" name="core" version="1.3.2">
|
||||||
|
<artifact name="core-1.3.2.pom">
|
||||||
|
<sha256 value="afb5ea494dd083ed404cd51f580d218e37362f8ae326e893bee521290ed34920" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.core" name="core" version="1.8.0">
|
<component group="androidx.core" name="core" version="1.8.0">
|
||||||
<artifact name="core-1.8.0.module">
|
<artifact name="core-1.8.0.module">
|
||||||
<sha256 value="505f1838869611519d65ec7feb650e88856e3682e37e42a2a24b73e655a98d74" origin="Generated by Gradle"/>
|
<sha256 value="505f1838869611519d65ec7feb650e88856e3682e37e42a2a24b73e655a98d74" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.core" name="core" version="1.9.0">
|
||||||
|
<artifact name="core-1.9.0.aar">
|
||||||
|
<sha256 value="8bda3ee3a88887d54f6679fb6b6cd788629f73234ac91c8bbed924e721ec85b8" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="core-1.9.0.module">
|
||||||
|
<sha256 value="8674ade1d12962469dd2d1e6edc03b465f20d180b0840a129bc40b351e8651d1" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.core" name="core-ktx" version="1.1.0">
|
<component group="androidx.core" name="core-ktx" version="1.1.0">
|
||||||
<artifact name="core-ktx-1.1.0.pom">
|
<artifact name="core-ktx-1.1.0.pom">
|
||||||
<sha256 value="729d11bad16d87c6212dc9ab80e9c770d333115062136e0732164a6b1696e11c" origin="Generated by Gradle"/>
|
<sha256 value="729d11bad16d87c6212dc9ab80e9c770d333115062136e0732164a6b1696e11c" origin="Generated by Gradle"/>
|
||||||
@@ -495,6 +668,14 @@
|
|||||||
<sha256 value="a3e6a0692e05fd59e6ac380715ed72b325c625a3627646c69d108bdcddc4260f" origin="Generated by Gradle"/>
|
<sha256 value="a3e6a0692e05fd59e6ac380715ed72b325c625a3627646c69d108bdcddc4260f" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.core" name="core-ktx" version="1.13.1">
|
||||||
|
<artifact name="core-ktx-1.13.1.aar">
|
||||||
|
<sha256 value="19ba50d094c7368ede1b4ccf1195ceb83e35970736593f823e5af716f8d05d70" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="core-ktx-1.13.1.module">
|
||||||
|
<sha256 value="ab530b04e2fbe73205484899a3be56c90968873eb496fc52e5ea7596d91035d1" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.core" name="core-ktx" version="1.16.0">
|
<component group="androidx.core" name="core-ktx" version="1.16.0">
|
||||||
<artifact name="core-ktx-1.16.0.aar">
|
<artifact name="core-ktx-1.16.0.aar">
|
||||||
<sha256 value="1766dbd82f64a12dcd359ecb6f15f3cf35db4d66d22961a7c51b2ffc6468314c" origin="Generated by Gradle"/>
|
<sha256 value="1766dbd82f64a12dcd359ecb6f15f3cf35db4d66d22961a7c51b2ffc6468314c" origin="Generated by Gradle"/>
|
||||||
@@ -516,6 +697,19 @@
|
|||||||
<sha256 value="29eaddba4e6a35e68a128e594ebae3b72ef7e767f1b273ef93dc2ed019ff97f6" origin="Generated by Gradle"/>
|
<sha256 value="29eaddba4e6a35e68a128e594ebae3b72ef7e767f1b273ef93dc2ed019ff97f6" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.core" name="core-ktx" version="1.8.0">
|
||||||
|
<artifact name="core-ktx-1.8.0.module">
|
||||||
|
<sha256 value="a91bc3e02f209f643dd8275345a9e3003ce20d64fc0760eccf479c1709842f72" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.core" name="core-ktx" version="1.9.0">
|
||||||
|
<artifact name="core-ktx-1.9.0.aar">
|
||||||
|
<sha256 value="1542a1df7be908c95fee91b8dbc03fd974f53f11d84a85d881f95a52551c4051" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="core-ktx-1.9.0.module">
|
||||||
|
<sha256 value="4d46646066c794f2812d5b33a9422d37e4f918c4d809cd1fb2579c7022ef2818" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.core" name="core-viewtree" version="1.0.0">
|
<component group="androidx.core" name="core-viewtree" version="1.0.0">
|
||||||
<artifact name="core-viewtree-1.0.0.aar">
|
<artifact name="core-viewtree-1.0.0.aar">
|
||||||
<sha256 value="dc1b678d58ebcf2bfa1587be68ff826694ce3d221251b9ef30d4d4b36297e6de" origin="Generated by Gradle"/>
|
<sha256 value="dc1b678d58ebcf2bfa1587be68ff826694ce3d221251b9ef30d4d4b36297e6de" origin="Generated by Gradle"/>
|
||||||
@@ -524,6 +718,14 @@
|
|||||||
<sha256 value="11386cfa46cbbfddb6a4059f14354c00691cf65d3d63c3618818a83326ef3c7f" origin="Generated by Gradle"/>
|
<sha256 value="11386cfa46cbbfddb6a4059f14354c00691cf65d3d63c3618818a83326ef3c7f" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.cursoradapter" name="cursoradapter" version="1.0.0">
|
||||||
|
<artifact name="cursoradapter-1.0.0.aar">
|
||||||
|
<sha256 value="a81c8fe78815fa47df5b749deb52727ad11f9397da58b16017f4eb2c11e28564" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="cursoradapter-1.0.0.pom">
|
||||||
|
<sha256 value="62d95c89850af21030b19f14d5f7ecd6d8bcc9a3014c59002ec99624caac8100" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.customview" name="customview" version="1.0.0">
|
<component group="androidx.customview" name="customview" version="1.0.0">
|
||||||
<artifact name="customview-1.0.0.aar">
|
<artifact name="customview-1.0.0.aar">
|
||||||
<sha256 value="20e5b8f6526a34595a604f56718da81167c0b40a7a94a57daa355663f2594df2" origin="Generated by Gradle"/>
|
<sha256 value="20e5b8f6526a34595a604f56718da81167c0b40a7a94a57daa355663f2594df2" origin="Generated by Gradle"/>
|
||||||
@@ -556,6 +758,14 @@
|
|||||||
<sha256 value="37d01baf6f0869f099ebdc6fb39f3dd3d267f17f24753d2587ccc43bc45685a1" origin="Generated by Gradle"/>
|
<sha256 value="37d01baf6f0869f099ebdc6fb39f3dd3d267f17f24753d2587ccc43bc45685a1" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.drawerlayout" name="drawerlayout" version="1.0.0">
|
||||||
|
<artifact name="drawerlayout-1.0.0.aar">
|
||||||
|
<sha256 value="9402442cdc5a43cf62fb14f8cf98c63342d4d9d9b805c8033c6cf7e802749ac1" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="drawerlayout-1.0.0.pom">
|
||||||
|
<sha256 value="da6733425a83f5ce850878fa7201082345fed7c668dd58550fdd19c0396c6fa4" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.emoji2" name="emoji2" version="1.2.0">
|
<component group="androidx.emoji2" name="emoji2" version="1.2.0">
|
||||||
<artifact name="emoji2-1.2.0.module">
|
<artifact name="emoji2-1.2.0.module">
|
||||||
<sha256 value="9d1996cca03777baa1f27cd15531db983a633dae37b90f85bd53501acb56699d" origin="Generated by Gradle"/>
|
<sha256 value="9d1996cca03777baa1f27cd15531db983a633dae37b90f85bd53501acb56699d" origin="Generated by Gradle"/>
|
||||||
@@ -574,6 +784,11 @@
|
|||||||
<sha256 value="92be16cccb757f807bddd92f1fca95a038a810ccca051c4149c11682478954b8" origin="Generated by Gradle"/>
|
<sha256 value="92be16cccb757f807bddd92f1fca95a038a810ccca051c4149c11682478954b8" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.fragment" name="fragment" version="1.2.5">
|
||||||
|
<artifact name="fragment-1.2.5.pom">
|
||||||
|
<sha256 value="df0aca46b62bb47cc662cbcee63372db6d2a2859478ee38b594fba3433fe30a5" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.fragment" name="fragment" version="1.5.1">
|
<component group="androidx.fragment" name="fragment" version="1.5.1">
|
||||||
<artifact name="fragment-1.5.1.aar">
|
<artifact name="fragment-1.5.1.aar">
|
||||||
<sha256 value="82b04780eda21b0a5eea02475415887a1cadfb368b371221aeb40703c067f338" origin="Generated by Gradle"/>
|
<sha256 value="82b04780eda21b0a5eea02475415887a1cadfb368b371221aeb40703c067f338" origin="Generated by Gradle"/>
|
||||||
@@ -582,6 +797,30 @@
|
|||||||
<sha256 value="2a665e166553b99bb789cef517e64131059df2a9ee60c1fd76b53cba7f0b4131" origin="Generated by Gradle"/>
|
<sha256 value="2a665e166553b99bb789cef517e64131059df2a9ee60c1fd76b53cba7f0b4131" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.fragment" name="fragment" version="1.8.9">
|
||||||
|
<artifact name="fragment-1.8.9.aar">
|
||||||
|
<sha256 value="12de5b89ab6641c1d8da82b63dc816652622b06d2781b949b6fbd2dff9fac492" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="fragment-1.8.9.module">
|
||||||
|
<sha256 value="67af03fb14d0e2bae2a7c62185d3a5607a915ed1fc494952afb165cd12b00b7c" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.fragment" name="fragment" version="1.9.1">
|
||||||
|
<artifact name="fragment-1.9.1.aar">
|
||||||
|
<sha256 value="72f70815c0a4d502f15c57e5e6bc861e64c5338ea06de75aed83969b17a2a727" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="fragment-1.9.1.module">
|
||||||
|
<sha256 value="066557e66adc00d5d53f67890f15620170ecb8700a0f214393748156b70fa66a" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.fragment" name="fragment-ktx" version="1.8.9">
|
||||||
|
<artifact name="fragment-ktx-1.8.9.aar">
|
||||||
|
<sha256 value="078ad5877b04f4bf7350198579d81f9c8796fa20e46b4ade3f231a370456c5ad" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="fragment-ktx-1.8.9.module">
|
||||||
|
<sha256 value="4e66c1b0f47b94d3e0dc41607d3af6b292996e98f065debedcbf8c791400081f" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.graphics" name="graphics-path" version="1.0.1">
|
<component group="androidx.graphics" name="graphics-path" version="1.0.1">
|
||||||
<artifact name="graphics-path-1.0.1.aar">
|
<artifact name="graphics-path-1.0.1.aar">
|
||||||
<sha256 value="8ca4032b6d79b351f0b59ad4b580eddbb9423e1652f7c958830687f1eee2ec03" origin="Generated by Gradle"/>
|
<sha256 value="8ca4032b6d79b351f0b59ad4b580eddbb9423e1652f7c958830687f1eee2ec03" origin="Generated by Gradle"/>
|
||||||
@@ -598,16 +837,39 @@
|
|||||||
<sha256 value="0ddc07cc39699f48ecd9ec894b5830c0f09e22e82959294edf37217224c88b7b" origin="Generated by Gradle"/>
|
<sha256 value="0ddc07cc39699f48ecd9ec894b5830c0f09e22e82959294edf37217224c88b7b" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-common" version="2.10.0">
|
||||||
|
<artifact name="lifecycle-common-2.10.0.module">
|
||||||
|
<sha256 value="5d1247b1edfbdc9ddedcbe525c9d2629567b1c538cb7a9c620cd044a124b5c73" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.lifecycle" name="lifecycle-common" version="2.11.0">
|
<component group="androidx.lifecycle" name="lifecycle-common" version="2.11.0">
|
||||||
<artifact name="lifecycle-common-2.11.0.module">
|
<artifact name="lifecycle-common-2.11.0.module">
|
||||||
<sha256 value="5b3db432c61a8f1668023d0aeb3e2cbc3ef337e5da22db9afb10b7513d1d4e5a" origin="Generated by Gradle"/>
|
<sha256 value="5b3db432c61a8f1668023d0aeb3e2cbc3ef337e5da22db9afb10b7513d1d4e5a" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-common" version="2.2.0">
|
||||||
|
<artifact name="lifecycle-common-2.2.0.pom">
|
||||||
|
<sha256 value="cc30a8a2a97d3767bd169b747c078727308096dd3ab7917d80b2f1f42d118bd6" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-common" version="2.3.1">
|
||||||
|
<artifact name="lifecycle-common-2.3.1.module">
|
||||||
|
<sha256 value="5fb7c8514d8c56cada5e29ef89dc0289e71942ab4cb0b2e6dca137b9dcb8fdd4" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.lifecycle" name="lifecycle-common" version="2.5.1">
|
<component group="androidx.lifecycle" name="lifecycle-common" version="2.5.1">
|
||||||
<artifact name="lifecycle-common-2.5.1.module">
|
<artifact name="lifecycle-common-2.5.1.module">
|
||||||
<sha256 value="7d4bc2961cd5bd399e3621d434f0c453dd6cadf891f917a946cc291abdda8f1a" origin="Generated by Gradle"/>
|
<sha256 value="7d4bc2961cd5bd399e3621d434f0c453dd6cadf891f917a946cc291abdda8f1a" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-common" version="2.6.1">
|
||||||
|
<artifact name="lifecycle-common-2.6.1.jar">
|
||||||
|
<sha256 value="f34831b6c71cd844e1d35d1be49d5e79447c5ab856346531b1e8676fda7374b1" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="lifecycle-common-2.6.1.module">
|
||||||
|
<sha256 value="93747a9145cb36bc71005f598ede32e2b1149ade5a16e62b0e4969345bc62d85" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.lifecycle" name="lifecycle-common" version="2.9.4">
|
<component group="androidx.lifecycle" name="lifecycle-common" version="2.9.4">
|
||||||
<artifact name="lifecycle-common-2.9.4.module">
|
<artifact name="lifecycle-common-2.9.4.module">
|
||||||
<sha256 value="c578bd755ea46d7a77811309a3539538e2d7fb86a05fc2ad81c655ecf7dff7a4" origin="Generated by Gradle"/>
|
<sha256 value="c578bd755ea46d7a77811309a3539538e2d7fb86a05fc2ad81c655ecf7dff7a4" origin="Generated by Gradle"/>
|
||||||
@@ -621,6 +883,14 @@
|
|||||||
<sha256 value="1c8c3fc840e4c565568baa57ba886aee5ed869df316335b056d92cdbbc84af6f" origin="Generated by Gradle"/>
|
<sha256 value="1c8c3fc840e4c565568baa57ba886aee5ed869df316335b056d92cdbbc84af6f" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-common-jvm" version="2.10.0">
|
||||||
|
<artifact name="lifecycle-common-jvm-2.10.0.jar">
|
||||||
|
<sha256 value="15943082d87bcd78830398fa377f2c8b12643de290d0906ed8e49a2d335ddb54" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="lifecycle-common-jvm-2.10.0.module">
|
||||||
|
<sha256 value="93d9016b3afd03639a407f51a119d5ca4dae988de376c380f0e51dd9d88e686d" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.lifecycle" name="lifecycle-common-jvm" version="2.11.0">
|
<component group="androidx.lifecycle" name="lifecycle-common-jvm" version="2.11.0">
|
||||||
<artifact name="lifecycle-common-jvm-2.11.0.jar">
|
<artifact name="lifecycle-common-jvm-2.11.0.jar">
|
||||||
<sha256 value="e6a66e67b9f63a0fb6344f165c1d872376e5fe6d235bffb138af45122cf452a9" origin="Generated by Gradle"/>
|
<sha256 value="e6a66e67b9f63a0fb6344f165c1d872376e5fe6d235bffb138af45122cf452a9" origin="Generated by Gradle"/>
|
||||||
@@ -629,6 +899,14 @@
|
|||||||
<sha256 value="c9477d6784c8dcb992f1a1774dd95df31f3e101e5d1e9cb7b01aaff3924a1942" origin="Generated by Gradle"/>
|
<sha256 value="c9477d6784c8dcb992f1a1774dd95df31f3e101e5d1e9cb7b01aaff3924a1942" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-livedata" version="2.10.0">
|
||||||
|
<artifact name="lifecycle-livedata-2.10.0.aar">
|
||||||
|
<sha256 value="3e8c009fc88da1c52e4ed05a81269d5ac9bd405046f300307f5e3a17e201a6df" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="lifecycle-livedata-2.10.0.module">
|
||||||
|
<sha256 value="3a6d473b3104c983501de4883d6ba7684dc83330c460ef958390a8265b078310" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.lifecycle" name="lifecycle-livedata" version="2.11.0">
|
<component group="androidx.lifecycle" name="lifecycle-livedata" version="2.11.0">
|
||||||
<artifact name="lifecycle-livedata-2.11.0.aar">
|
<artifact name="lifecycle-livedata-2.11.0.aar">
|
||||||
<sha256 value="1bc28e40e06ff5e0478b9276ca6287ce6993415b70910745ac916b14dec9b72f" origin="Generated by Gradle"/>
|
<sha256 value="1bc28e40e06ff5e0478b9276ca6287ce6993415b70910745ac916b14dec9b72f" origin="Generated by Gradle"/>
|
||||||
@@ -637,6 +915,22 @@
|
|||||||
<sha256 value="d990bc920ae43729d702d80077328e8a59781ea5a35b24c02bc47d326ae73d7d" origin="Generated by Gradle"/>
|
<sha256 value="d990bc920ae43729d702d80077328e8a59781ea5a35b24c02bc47d326ae73d7d" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-livedata" version="2.6.1">
|
||||||
|
<artifact name="lifecycle-livedata-2.6.1.aar">
|
||||||
|
<sha256 value="67359f609dfc2bf65da1270b23033f856064ec279f058e0a70c715f7c9003031" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="lifecycle-livedata-2.6.1.module">
|
||||||
|
<sha256 value="e2659e87e890b52b66f300471828b387a205e5387a392713190166f399ecf641" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-livedata-core" version="2.10.0">
|
||||||
|
<artifact name="lifecycle-livedata-core-2.10.0.aar">
|
||||||
|
<sha256 value="12dd61a9843ccebb4547d3ebe2f6d030ca8f6988d22f8fad19c0af93b4a97e95" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="lifecycle-livedata-core-2.10.0.module">
|
||||||
|
<sha256 value="1d83bd5f3ccc1298eda25b9ed128e8c187f830e7f3af8d0294be688abb03c35d" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.lifecycle" name="lifecycle-livedata-core" version="2.11.0">
|
<component group="androidx.lifecycle" name="lifecycle-livedata-core" version="2.11.0">
|
||||||
<artifact name="lifecycle-livedata-core-2.11.0.aar">
|
<artifact name="lifecycle-livedata-core-2.11.0.aar">
|
||||||
<sha256 value="39b26ef1e081fc88d7054ff1a63d0a5d71876373c33a711ab789c8228d025ad1" origin="Generated by Gradle"/>
|
<sha256 value="39b26ef1e081fc88d7054ff1a63d0a5d71876373c33a711ab789c8228d025ad1" origin="Generated by Gradle"/>
|
||||||
@@ -645,6 +939,27 @@
|
|||||||
<sha256 value="d1c1410c8ce9cf1463616c19ca7d8afca63bcbbac9dabd29da3121d61bd41343" origin="Generated by Gradle"/>
|
<sha256 value="d1c1410c8ce9cf1463616c19ca7d8afca63bcbbac9dabd29da3121d61bd41343" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-livedata-core" version="2.2.0">
|
||||||
|
<artifact name="lifecycle-livedata-core-2.2.0.pom">
|
||||||
|
<sha256 value="aa51621be3817d1f5d21336b0c0525fe96ae899cec656c13d8ea18a51ea32c2f" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-livedata-core" version="2.6.1">
|
||||||
|
<artifact name="lifecycle-livedata-core-2.6.1.aar">
|
||||||
|
<sha256 value="2256780a3cff4a1e57fbb3d442557c17dc363ab8af105bcaf5261d8e2d5db949" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="lifecycle-livedata-core-2.6.1.module">
|
||||||
|
<sha256 value="e9c0dc3f0ac54419c0cfed8ff5cecb82943a7c58f7a54169f0d849b2c60a3552" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-livedata-core-ktx" version="2.10.0">
|
||||||
|
<artifact name="lifecycle-livedata-core-ktx-2.10.0.aar">
|
||||||
|
<sha256 value="5f18429749a183e19178d8665ae42bf7b6310b50358ae9e0e0cc452afd6e0bc3" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="lifecycle-livedata-core-ktx-2.10.0.module">
|
||||||
|
<sha256 value="2b28a03201f3077b2ae3e2853f983944afdf518b02939acfc9fe9e5fcab87275" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.lifecycle" name="lifecycle-livedata-core-ktx" version="2.11.0">
|
<component group="androidx.lifecycle" name="lifecycle-livedata-core-ktx" version="2.11.0">
|
||||||
<artifact name="lifecycle-livedata-core-ktx-2.11.0.aar">
|
<artifact name="lifecycle-livedata-core-ktx-2.11.0.aar">
|
||||||
<sha256 value="408fac99b61a7ca9d0620f4f24891f85c14ee007cfd027abc3df759a31b0086a" origin="Generated by Gradle"/>
|
<sha256 value="408fac99b61a7ca9d0620f4f24891f85c14ee007cfd027abc3df759a31b0086a" origin="Generated by Gradle"/>
|
||||||
@@ -653,6 +968,14 @@
|
|||||||
<sha256 value="b66cb413ac9cde811c9b96e4d2b3d4ff2ef403236187b3db33fe4f1da8e95fcd" origin="Generated by Gradle"/>
|
<sha256 value="b66cb413ac9cde811c9b96e4d2b3d4ff2ef403236187b3db33fe4f1da8e95fcd" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-livedata-core-ktx" version="2.6.1">
|
||||||
|
<artifact name="lifecycle-livedata-core-ktx-2.6.1.aar">
|
||||||
|
<sha256 value="9f2c16e33a55ba8d67a3623a55befff2ec80643e3f0a926760df1d957c3f8aef" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="lifecycle-livedata-core-ktx-2.6.1.module">
|
||||||
|
<sha256 value="d8699c515516aee3a0613de951649d9f1e137d33fedf077be0a6aa9e01ae211f" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.lifecycle" name="lifecycle-process" version="2.11.0">
|
<component group="androidx.lifecycle" name="lifecycle-process" version="2.11.0">
|
||||||
<artifact name="lifecycle-process-2.11.0.aar">
|
<artifact name="lifecycle-process-2.11.0.aar">
|
||||||
<sha256 value="9743f0c7baf27d34497b7e9a1cd497d8260251b03124507963abfaad66c3f552" origin="Generated by Gradle"/>
|
<sha256 value="9743f0c7baf27d34497b7e9a1cd497d8260251b03124507963abfaad66c3f552" origin="Generated by Gradle"/>
|
||||||
@@ -661,16 +984,47 @@
|
|||||||
<sha256 value="7d9d7ad473370a6147d9fc9b1d1c6af14b55a474849483e5974940bdf8b52fdd" origin="Generated by Gradle"/>
|
<sha256 value="7d9d7ad473370a6147d9fc9b1d1c6af14b55a474849483e5974940bdf8b52fdd" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-runtime" version="2.0.0">
|
||||||
|
<artifact name="lifecycle-runtime-2.0.0.pom">
|
||||||
|
<sha256 value="a92a46fa7aec8ac326a5d578734a2d5b63206976996b9e06cae171b35b0ab6de" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-runtime" version="2.10.0">
|
||||||
|
<artifact name="lifecycle-runtime-2.10.0.module">
|
||||||
|
<sha256 value="da805fa017a4acce13f501469a75a3f306248eebc58f5bcc28019b0015dfba65" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.lifecycle" name="lifecycle-runtime" version="2.11.0">
|
<component group="androidx.lifecycle" name="lifecycle-runtime" version="2.11.0">
|
||||||
<artifact name="lifecycle-runtime-2.11.0.module">
|
<artifact name="lifecycle-runtime-2.11.0.module">
|
||||||
<sha256 value="5cf1c15ce1fd9329b8ef75517c309e3aab967bd785d96ae100c3d9c8906e317e" origin="Generated by Gradle"/>
|
<sha256 value="5cf1c15ce1fd9329b8ef75517c309e3aab967bd785d96ae100c3d9c8906e317e" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-runtime" version="2.2.0">
|
||||||
|
<artifact name="lifecycle-runtime-2.2.0.pom">
|
||||||
|
<sha256 value="7f154066fed1c9162870f728b208352831b3d1f8f23f5d388958a50ca4e9f441" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-runtime" version="2.6.1">
|
||||||
|
<artifact name="lifecycle-runtime-2.6.1.aar">
|
||||||
|
<sha256 value="4867fd5279742fba8388821930cb2affe06d81a52814e7e41e70392ea0ef887c" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="lifecycle-runtime-2.6.1.module">
|
||||||
|
<sha256 value="a4cbb01a42d07047bd8d870017c96a1b0b7b4673320e86b66317a13be2ec10c7" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.lifecycle" name="lifecycle-runtime" version="2.9.4">
|
<component group="androidx.lifecycle" name="lifecycle-runtime" version="2.9.4">
|
||||||
<artifact name="lifecycle-runtime-2.9.4.module">
|
<artifact name="lifecycle-runtime-2.9.4.module">
|
||||||
<sha256 value="dcbc5b5b50666e84258a74bfd8e514918c593a4ffcef0c0358562a02fbd80c58" origin="Generated by Gradle"/>
|
<sha256 value="dcbc5b5b50666e84258a74bfd8e514918c593a4ffcef0c0358562a02fbd80c58" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-runtime-android" version="2.10.0">
|
||||||
|
<artifact name="lifecycle-runtime-android-2.10.0.module">
|
||||||
|
<sha256 value="749b6e7a4422914581e0795d9d48fb4f96daa3fee97747421ff4234860185f47" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="lifecycle-runtime.aar">
|
||||||
|
<sha256 value="2193a1573d623f37b20c7d27d1a8f903a72f651cc6f32e5794f85dda744fee75" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.lifecycle" name="lifecycle-runtime-android" version="2.11.0">
|
<component group="androidx.lifecycle" name="lifecycle-runtime-android" version="2.11.0">
|
||||||
<artifact name="lifecycle-runtime-android-2.11.0.module">
|
<artifact name="lifecycle-runtime-android-2.11.0.module">
|
||||||
<sha256 value="25d7a9baeb72fbdba65756865a900c37a6146e5b3f835c44fc0493b15bd19286" origin="Generated by Gradle"/>
|
<sha256 value="25d7a9baeb72fbdba65756865a900c37a6146e5b3f835c44fc0493b15bd19286" origin="Generated by Gradle"/>
|
||||||
@@ -692,11 +1046,32 @@
|
|||||||
<sha256 value="7b31489e6e162143c481f14e1ae5a4dc089f8ec58e65976a0502b910c641987f" origin="Generated by Gradle"/>
|
<sha256 value="7b31489e6e162143c481f14e1ae5a4dc089f8ec58e65976a0502b910c641987f" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-runtime-ktx" version="2.10.0">
|
||||||
|
<artifact name="lifecycle-runtime-ktx-2.10.0.module">
|
||||||
|
<sha256 value="556f15957376858b6e3abc08fb3df566ea5eb4067149253194bf2a049606db4e" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.lifecycle" name="lifecycle-runtime-ktx" version="2.11.0">
|
<component group="androidx.lifecycle" name="lifecycle-runtime-ktx" version="2.11.0">
|
||||||
<artifact name="lifecycle-runtime-ktx-2.11.0.module">
|
<artifact name="lifecycle-runtime-ktx-2.11.0.module">
|
||||||
<sha256 value="bb6ba31505096941a988cc69f7d490514629cd45cb5da29cda79a9bde4bcdce5" origin="Generated by Gradle"/>
|
<sha256 value="bb6ba31505096941a988cc69f7d490514629cd45cb5da29cda79a9bde4bcdce5" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-runtime-ktx" version="2.6.1">
|
||||||
|
<artifact name="lifecycle-runtime-ktx-2.6.1.aar">
|
||||||
|
<sha256 value="28a0b834f40edd52e2f8010bdc3057d2a0cc76aaa5ac9311adb0b9ce919ca9cc" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="lifecycle-runtime-ktx-2.6.1.module">
|
||||||
|
<sha256 value="39854f32c9b010f652f4e5041ca4ce06981dcb6954128c1e8e1cc02e63ab185f" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-runtime-ktx-android" version="2.10.0">
|
||||||
|
<artifact name="lifecycle-runtime-ktx-android-2.10.0.module">
|
||||||
|
<sha256 value="980a1be146cafa16ab3b1680991dde14b2077a4b13d5b31427cb98dc8930f24b" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="lifecycle-runtime-ktx.aar">
|
||||||
|
<sha256 value="871883703339f87284d232cb436e317c6f4af5612d92b43f27c6b13b92109fa7" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.lifecycle" name="lifecycle-runtime-ktx-android" version="2.11.0">
|
<component group="androidx.lifecycle" name="lifecycle-runtime-ktx-android" version="2.11.0">
|
||||||
<artifact name="lifecycle-runtime-ktx-android-2.11.0.module">
|
<artifact name="lifecycle-runtime-ktx-android-2.11.0.module">
|
||||||
<sha256 value="2e756a084e928f367b22dccb89f775d5562ff634d4b9c4e5e5415a9e00f8accd" origin="Generated by Gradle"/>
|
<sha256 value="2e756a084e928f367b22dccb89f775d5562ff634d4b9c4e5e5415a9e00f8accd" origin="Generated by Gradle"/>
|
||||||
@@ -705,6 +1080,14 @@
|
|||||||
<sha256 value="1fead96607f8b4ebd2bc5840c6fcf08b09fc47ceb1665e4b381dce80b19f32a0" origin="Generated by Gradle"/>
|
<sha256 value="1fead96607f8b4ebd2bc5840c6fcf08b09fc47ceb1665e4b381dce80b19f32a0" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-viewmodel" version="2.10.0">
|
||||||
|
<artifact name="lifecycle-viewmodel-2.10.0.aar">
|
||||||
|
<sha256 value="4b809cf9eb7323d200504e95921feb777ff080215cadb8237742d5ed0ba5b792" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="lifecycle-viewmodel-2.10.0.module">
|
||||||
|
<sha256 value="4fd71df733245c46e4b88e85b4a90b82c9af4a359ef31f2bdf250f93a02c7452" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.lifecycle" name="lifecycle-viewmodel" version="2.11.0">
|
<component group="androidx.lifecycle" name="lifecycle-viewmodel" version="2.11.0">
|
||||||
<artifact name="lifecycle-viewmodel-2.11.0.aar">
|
<artifact name="lifecycle-viewmodel-2.11.0.aar">
|
||||||
<sha256 value="4b809cf9eb7323d200504e95921feb777ff080215cadb8237742d5ed0ba5b792" origin="Generated by Gradle"/>
|
<sha256 value="4b809cf9eb7323d200504e95921feb777ff080215cadb8237742d5ed0ba5b792" origin="Generated by Gradle"/>
|
||||||
@@ -713,16 +1096,37 @@
|
|||||||
<sha256 value="8393aa093e7e848902de9b3ccc0a12269106ac6e773d75ff97f9754295c49298" origin="Generated by Gradle"/>
|
<sha256 value="8393aa093e7e848902de9b3ccc0a12269106ac6e773d75ff97f9754295c49298" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-viewmodel" version="2.2.0">
|
||||||
|
<artifact name="lifecycle-viewmodel-2.2.0.pom">
|
||||||
|
<sha256 value="aaa3afaa49ff47e2bc9b2389f939d3e8137616c4616684e2dfb53ba8366aa11d" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.lifecycle" name="lifecycle-viewmodel" version="2.5.1">
|
<component group="androidx.lifecycle" name="lifecycle-viewmodel" version="2.5.1">
|
||||||
<artifact name="lifecycle-viewmodel-2.5.1.module">
|
<artifact name="lifecycle-viewmodel-2.5.1.module">
|
||||||
<sha256 value="01e413b73cbe38cb714dc5bdb21bd860931124c8e5f2369803f4aacc49081c9f" origin="Generated by Gradle"/>
|
<sha256 value="01e413b73cbe38cb714dc5bdb21bd860931124c8e5f2369803f4aacc49081c9f" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-viewmodel" version="2.6.1">
|
||||||
|
<artifact name="lifecycle-viewmodel-2.6.1.aar">
|
||||||
|
<sha256 value="e4ff4338999e1c6c9c724719f5d4aa7dd61bf6f545d5256a27a9d375df9f2330" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="lifecycle-viewmodel-2.6.1.module">
|
||||||
|
<sha256 value="2b406faea5c12f2b8df4b7a60931f846648f2e1f4d78361e198d1184f19a4797" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.lifecycle" name="lifecycle-viewmodel" version="2.9.4">
|
<component group="androidx.lifecycle" name="lifecycle-viewmodel" version="2.9.4">
|
||||||
<artifact name="lifecycle-viewmodel-2.9.4.module">
|
<artifact name="lifecycle-viewmodel-2.9.4.module">
|
||||||
<sha256 value="964d69d6b877296e8b79a77bb826ef5fb186aecaa7a1a7ff776fb2250c993006" origin="Generated by Gradle"/>
|
<sha256 value="964d69d6b877296e8b79a77bb826ef5fb186aecaa7a1a7ff776fb2250c993006" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-viewmodel-android" version="2.10.0">
|
||||||
|
<artifact name="lifecycle-viewmodel-android-2.10.0.module">
|
||||||
|
<sha256 value="06b07a07ae17c7592a30c533c3d46a125fcb1bef096d7e6134e2420db2464d0a" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="lifecycle-viewmodel.aar">
|
||||||
|
<sha256 value="9303287030027ca0b8cf98a748ddeb121ec1bfa1312c0069428e4765bbabce78" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.lifecycle" name="lifecycle-viewmodel-android" version="2.11.0">
|
<component group="androidx.lifecycle" name="lifecycle-viewmodel-android" version="2.11.0">
|
||||||
<artifact name="lifecycle-viewmodel-android-2.11.0.module">
|
<artifact name="lifecycle-viewmodel-android-2.11.0.module">
|
||||||
<sha256 value="646813f4c50bc5f198bb96a26f1accf319da09d09c0bffbf35e8dcf2173d8393" origin="Generated by Gradle"/>
|
<sha256 value="646813f4c50bc5f198bb96a26f1accf319da09d09c0bffbf35e8dcf2173d8393" origin="Generated by Gradle"/>
|
||||||
@@ -744,6 +1148,14 @@
|
|||||||
<sha256 value="2bafd402807bd4af05c06cf58c48cbdad09521e2145273faae90908b7712f689" origin="Generated by Gradle"/>
|
<sha256 value="2bafd402807bd4af05c06cf58c48cbdad09521e2145273faae90908b7712f689" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-viewmodel-ktx" version="2.10.0">
|
||||||
|
<artifact name="lifecycle-viewmodel-ktx-2.10.0.aar">
|
||||||
|
<sha256 value="54295ac86b67886dc0613e38f621c531995d0662005fc763e340e19a90994f84" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="lifecycle-viewmodel-ktx-2.10.0.module">
|
||||||
|
<sha256 value="837bfdd848eefef77544fa289dbff4c428680dd9820641eadb841cc7a74c83f9" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.lifecycle" name="lifecycle-viewmodel-ktx" version="2.11.0">
|
<component group="androidx.lifecycle" name="lifecycle-viewmodel-ktx" version="2.11.0">
|
||||||
<artifact name="lifecycle-viewmodel-ktx-2.11.0.aar">
|
<artifact name="lifecycle-viewmodel-ktx-2.11.0.aar">
|
||||||
<sha256 value="230af6c866076d320d92c22c7c44bb52afca97f6892ddf987e2906ef2919998f" origin="Generated by Gradle"/>
|
<sha256 value="230af6c866076d320d92c22c7c44bb52afca97f6892ddf987e2906ef2919998f" origin="Generated by Gradle"/>
|
||||||
@@ -752,6 +1164,24 @@
|
|||||||
<sha256 value="2b35a1381397614ad13cf301cb3685a15be4d50d1584376e7e5418010bd4096d" origin="Generated by Gradle"/>
|
<sha256 value="2b35a1381397614ad13cf301cb3685a15be4d50d1584376e7e5418010bd4096d" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-viewmodel-ktx" version="2.6.1">
|
||||||
|
<artifact name="lifecycle-viewmodel-ktx-2.6.1.aar">
|
||||||
|
<sha256 value="7fc0fa234a3321b1f34db5862b17da83d1c62c1bc66ec2fd4f1bb0a771acfabb" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="lifecycle-viewmodel-ktx-2.6.1.module">
|
||||||
|
<sha256 value="a5110f85788bc167df9fe8fbe08004ddc5c5dd9b15cb7376ceeaef025fccaaf8" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-viewmodel-savedstate" version="1.0.0">
|
||||||
|
<artifact name="lifecycle-viewmodel-savedstate-1.0.0.pom">
|
||||||
|
<sha256 value="37a46395fb334f5d54843d5823f37513c80485dcae6cf16188babc49ebe65e17" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-viewmodel-savedstate" version="2.10.0">
|
||||||
|
<artifact name="lifecycle-viewmodel-savedstate-2.10.0.module">
|
||||||
|
<sha256 value="50857781e3ddf8e39905e4e4a57a30496c245f9901d1b7d3f17382382188347d" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.lifecycle" name="lifecycle-viewmodel-savedstate" version="2.11.0">
|
<component group="androidx.lifecycle" name="lifecycle-viewmodel-savedstate" version="2.11.0">
|
||||||
<artifact name="lifecycle-viewmodel-savedstate-2.11.0.module">
|
<artifact name="lifecycle-viewmodel-savedstate-2.11.0.module">
|
||||||
<sha256 value="dc6750a6991bfaac0817469865fe2ccb01e26186a0386299a5d056bac2cc72cc" origin="Generated by Gradle"/>
|
<sha256 value="dc6750a6991bfaac0817469865fe2ccb01e26186a0386299a5d056bac2cc72cc" origin="Generated by Gradle"/>
|
||||||
@@ -762,6 +1192,22 @@
|
|||||||
<sha256 value="29acd5fe614b3f89123eb838f688d625eaa8b422c8d1905b48ad8e760cd7ad8b" origin="Generated by Gradle"/>
|
<sha256 value="29acd5fe614b3f89123eb838f688d625eaa8b422c8d1905b48ad8e760cd7ad8b" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-viewmodel-savedstate" version="2.6.1">
|
||||||
|
<artifact name="lifecycle-viewmodel-savedstate-2.6.1.aar">
|
||||||
|
<sha256 value="c82f89221adbe19df7c7adbab63f4ecc857fc746e3c9494256ab8fa5c20491b2" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="lifecycle-viewmodel-savedstate-2.6.1.module">
|
||||||
|
<sha256 value="dafb8649763d29c29cda27bc22fcdab9a9efc53c0fff9ae3de90882eabaa8944" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.lifecycle" name="lifecycle-viewmodel-savedstate-android" version="2.10.0">
|
||||||
|
<artifact name="lifecycle-viewmodel-savedstate-android-2.10.0.module">
|
||||||
|
<sha256 value="949d2a862b6b584cee91af70a9e017bdb117d225bb46096da9424a1728ca79e9" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="lifecycle-viewmodel-savedstate.aar">
|
||||||
|
<sha256 value="19404239fa584322c2f81e9659e162bc011b746d29dc950a11d260624d83225e" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.lifecycle" name="lifecycle-viewmodel-savedstate-android" version="2.11.0">
|
<component group="androidx.lifecycle" name="lifecycle-viewmodel-savedstate-android" version="2.11.0">
|
||||||
<artifact name="lifecycle-viewmodel-savedstate-android-2.11.0.module">
|
<artifact name="lifecycle-viewmodel-savedstate-android-2.11.0.module">
|
||||||
<sha256 value="4351e91c13b1e6282cae924276799e0efdba67b801f12142479964e0b9b9f7ee" origin="Generated by Gradle"/>
|
<sha256 value="4351e91c13b1e6282cae924276799e0efdba67b801f12142479964e0b9b9f7ee" origin="Generated by Gradle"/>
|
||||||
@@ -835,6 +1281,14 @@
|
|||||||
<sha256 value="4c978461881d0506dd8d38deb25f84f56ea28756a14e583f2561c0ee98dff2d6" origin="Generated by Gradle"/>
|
<sha256 value="4c978461881d0506dd8d38deb25f84f56ea28756a14e583f2561c0ee98dff2d6" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.profileinstaller" name="profileinstaller" version="1.3.1">
|
||||||
|
<artifact name="profileinstaller-1.3.1.aar">
|
||||||
|
<sha256 value="d0e402ec31f24028a1dc7eb6a0a3f9d9635c1459392cd734396343b73d673948" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="profileinstaller-1.3.1.module">
|
||||||
|
<sha256 value="cc7eed0ed4b669de84b852f78797a50018a4f30002e1e38aaa668af22ca5b460" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.profileinstaller" name="profileinstaller" version="1.4.0">
|
<component group="androidx.profileinstaller" name="profileinstaller" version="1.4.0">
|
||||||
<artifact name="profileinstaller-1.4.0.aar">
|
<artifact name="profileinstaller-1.4.0.aar">
|
||||||
<sha256 value="d502141fcce902430f62b674c32aecd0f75262e7ee2cd15c74adb617cd13130a" origin="Generated by Gradle"/>
|
<sha256 value="d502141fcce902430f62b674c32aecd0f75262e7ee2cd15c74adb617cd13130a" origin="Generated by Gradle"/>
|
||||||
@@ -843,12 +1297,20 @@
|
|||||||
<sha256 value="39bf997a28d8eed2cb319819f6f352a1ba3a78b9c979004fbe05e26b8f7d160b" origin="Generated by Gradle"/>
|
<sha256 value="39bf997a28d8eed2cb319819f6f352a1ba3a78b9c979004fbe05e26b8f7d160b" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.savedstate" name="savedstate" version="1.0.0">
|
||||||
|
<artifact name="savedstate-1.0.0.pom">
|
||||||
|
<sha256 value="844d7d22fcea798c78bf5559229daf88ec9cad8136f5eea0a29aa76b3f8fde7c" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.savedstate" name="savedstate" version="1.2.0">
|
<component group="androidx.savedstate" name="savedstate" version="1.2.0">
|
||||||
<artifact name="savedstate-1.2.0.module">
|
<artifact name="savedstate-1.2.0.module">
|
||||||
<sha256 value="4247c23308abcb5d0ff8cdaf7dfd583f3c2a1016f68d13f1a41c21600b6fafd7" origin="Generated by Gradle"/>
|
<sha256 value="4247c23308abcb5d0ff8cdaf7dfd583f3c2a1016f68d13f1a41c21600b6fafd7" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
<component group="androidx.savedstate" name="savedstate" version="1.2.1">
|
<component group="androidx.savedstate" name="savedstate" version="1.2.1">
|
||||||
|
<artifact name="savedstate-1.2.1.aar">
|
||||||
|
<sha256 value="21a7d4bcf6bdb94ad7b9283801529300b4fbb8808ca4f191e0cdce6fd8e4705a" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
<artifact name="savedstate-1.2.1.module">
|
<artifact name="savedstate-1.2.1.module">
|
||||||
<sha256 value="5bb656fc760d9e3996b535160cbb4106033c9f736e9089e6ef4eb0c669785066" origin="Generated by Gradle"/>
|
<sha256 value="5bb656fc760d9e3996b535160cbb4106033c9f736e9089e6ef4eb0c669785066" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
@@ -879,6 +1341,14 @@
|
|||||||
<sha256 value="0f0ae3032d6c6eea834ee22179c8976160d09d841d30e47f53f56b1b3438774b" origin="Generated by Gradle"/>
|
<sha256 value="0f0ae3032d6c6eea834ee22179c8976160d09d841d30e47f53f56b1b3438774b" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.savedstate" name="savedstate-ktx" version="1.2.1">
|
||||||
|
<artifact name="savedstate-ktx-1.2.1.aar">
|
||||||
|
<sha256 value="8553f87e7136c24ec5243560f48f1c32cba56daa77722f89589a5cafcb8f7894" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="savedstate-ktx-1.2.1.module">
|
||||||
|
<sha256 value="94359184b2ba51c0f498a2b9055d37b372231ef9bcc54a4972ac99f0303afff1" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.savedstate" name="savedstate-ktx" version="1.3.1">
|
<component group="androidx.savedstate" name="savedstate-ktx" version="1.3.1">
|
||||||
<artifact name="savedstate-ktx-1.3.1.module">
|
<artifact name="savedstate-ktx-1.3.1.module">
|
||||||
<sha256 value="59007d8d33cf166fdfd1a9bf56ccfd212e9822c04b3a741966face5918610655" origin="Generated by Gradle"/>
|
<sha256 value="59007d8d33cf166fdfd1a9bf56ccfd212e9822c04b3a741966face5918610655" origin="Generated by Gradle"/>
|
||||||
@@ -994,6 +1464,9 @@
|
|||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
<component group="androidx.tracing" name="tracing" version="1.0.0">
|
<component group="androidx.tracing" name="tracing" version="1.0.0">
|
||||||
|
<artifact name="tracing-1.0.0.aar">
|
||||||
|
<sha256 value="07b8b6139665b884a162eccf97891ca50f7f56831233bf25168ae04f7b568612" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
<artifact name="tracing-1.0.0.module">
|
<artifact name="tracing-1.0.0.module">
|
||||||
<sha256 value="fc8b21ebe5fa3a7c96ee098bcdcd00f077ebce73f243fa858e2b0671615f75d8" origin="Generated by Gradle"/>
|
<sha256 value="fc8b21ebe5fa3a7c96ee098bcdcd00f077ebce73f243fa858e2b0671615f75d8" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
@@ -1014,11 +1487,45 @@
|
|||||||
<sha256 value="d0d8d486b6bd33206dbf3f1a6d167e9b43c268ea63c3321c886b1543ad05ece3" origin="Generated by Gradle"/>
|
<sha256 value="d0d8d486b6bd33206dbf3f1a6d167e9b43c268ea63c3321c886b1543ad05ece3" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.tracing" name="tracing" version="2.0.0">
|
||||||
|
<artifact name="tracing-2.0.0.module">
|
||||||
|
<sha256 value="407139f993e891940a7f71a3cca099f5ee8d7828845bbb8239717eedf80c9553" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.tracing" name="tracing-android" version="2.0.0">
|
||||||
|
<artifact name="tracing-android-2.0.0.module">
|
||||||
|
<sha256 value="d2baa5464529169efa7ae5e7351b424c9b56d445f090d1824d1f87d1472e4510" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="tracing.aar">
|
||||||
|
<sha256 value="b21800b83ed0e3e214742c8a94edee90130e0a9970c85e59161d161546f5fe9a" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.vectordrawable" name="vectordrawable" version="1.1.0">
|
||||||
|
<artifact name="vectordrawable-1.1.0.aar">
|
||||||
|
<sha256 value="46fd633ac01b49b7fcabc263bf098c5a8b9e9a69774d234edcca04fb02df8e26" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="vectordrawable-1.1.0.pom">
|
||||||
|
<sha256 value="5b0e2d5b2179e54804785cbc21ce5f473b5e1ddd55a57da482e94dcd39492bb2" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="androidx.vectordrawable" name="vectordrawable-animated" version="1.1.0">
|
||||||
|
<artifact name="vectordrawable-animated-1.1.0.aar">
|
||||||
|
<sha256 value="76da2c502371d9c38054df5e2b248d00da87809ed058f3363eae87ce5e2403f8" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="vectordrawable-animated-1.1.0.pom">
|
||||||
|
<sha256 value="276a20116b705fb75b9003ee9496c56f6fd3b32375fb232472811eba60a040bd" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.versionedparcelable" name="versionedparcelable" version="1.0.0">
|
<component group="androidx.versionedparcelable" name="versionedparcelable" version="1.0.0">
|
||||||
<artifact name="versionedparcelable-1.0.0.pom">
|
<artifact name="versionedparcelable-1.0.0.pom">
|
||||||
<sha256 value="47ee7c5543239a651f8fb81310cadeeaab8e38a2d844d7bb92dd086e4ffbb320" origin="Generated by Gradle"/>
|
<sha256 value="47ee7c5543239a651f8fb81310cadeeaab8e38a2d844d7bb92dd086e4ffbb320" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="androidx.versionedparcelable" name="versionedparcelable" version="1.1.0">
|
||||||
|
<artifact name="versionedparcelable-1.1.0.pom">
|
||||||
|
<sha256 value="c729c7be0cc06323bda829d460666e79dbd43b799a21089a44bd3b293dc253b5" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="androidx.versionedparcelable" name="versionedparcelable" version="1.1.1">
|
<component group="androidx.versionedparcelable" name="versionedparcelable" version="1.1.1">
|
||||||
<artifact name="versionedparcelable-1.1.1.aar">
|
<artifact name="versionedparcelable-1.1.1.aar">
|
||||||
<sha256 value="57e8d93260d18d5b9007c9eed3c64ad159de90c8609ebfc74a347cbd514535a4" origin="Generated by Gradle"/>
|
<sha256 value="57e8d93260d18d5b9007c9eed3c64ad159de90c8609ebfc74a347cbd514535a4" origin="Generated by Gradle"/>
|
||||||
@@ -3020,6 +3527,11 @@
|
|||||||
<sha256 value="425d1683a903d085a1718122918242ad6ad0246c79283786697395e4d3a8c801" origin="Generated by Gradle"/>
|
<sha256 value="425d1683a903d085a1718122918242ad6ad0246c79283786697395e4d3a8c801" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="kotlin-stdlib" version="1.9.21">
|
||||||
|
<artifact name="kotlin-stdlib-1.9.21.module">
|
||||||
|
<sha256 value="d3019f7f0d71924ce47298c9cc46af0245f75219719b35c5915fbcc7e7a69395" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="kotlin-stdlib" version="2.2.0">
|
<component group="org.jetbrains.kotlin" name="kotlin-stdlib" version="2.2.0">
|
||||||
<artifact name="kotlin-stdlib-2.2.0.jar">
|
<artifact name="kotlin-stdlib-2.2.0.jar">
|
||||||
<sha256 value="65d12d85a3b865c160db9147851712a64b10dadd68b22eea22a95bf8a8670dca" origin="Generated by Gradle"/>
|
<sha256 value="65d12d85a3b865c160db9147851712a64b10dadd68b22eea22a95bf8a8670dca" origin="Generated by Gradle"/>
|
||||||
@@ -3097,6 +3609,11 @@
|
|||||||
<sha256 value="58fc0d664fc3a67e7e6be9fdbeaedbd212dfa3e527f744f861e792cda72c0e47" origin="Generated by Gradle"/>
|
<sha256 value="58fc0d664fc3a67e7e6be9fdbeaedbd212dfa3e527f744f861e792cda72c0e47" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlin" name="kotlin-stdlib-common" version="2.4.21">
|
||||||
|
<artifact name="kotlin-stdlib-common-2.4.21.module">
|
||||||
|
<sha256 value="aeae4f24688e1dd7ebee648ab2b12be685cbe33e9c72bc1439730a794d6e2d5b" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlin" name="kotlin-stdlib-jdk7" version="1.8.0">
|
<component group="org.jetbrains.kotlin" name="kotlin-stdlib-jdk7" version="1.8.0">
|
||||||
<artifact name="kotlin-stdlib-jdk7-1.8.0.jar">
|
<artifact name="kotlin-stdlib-jdk7-1.8.0.jar">
|
||||||
<sha256 value="4c889d1d9803f5f2eb6c1592a6b7e62369ac7660c9eee15aba16fec059163666" origin="Generated by Gradle"/>
|
<sha256 value="4c889d1d9803f5f2eb6c1592a6b7e62369ac7660c9eee15aba16fec059163666" origin="Generated by Gradle"/>
|
||||||
@@ -3221,6 +3738,22 @@
|
|||||||
<sha256 value="7b7d1dddf188817deaad738e92e11faa5abdf937c87120cdf036102566ad4be3" origin="Generated by Gradle"/>
|
<sha256 value="7b7d1dddf188817deaad738e92e11faa5abdf937c87120cdf036102566ad4be3" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-android" version="1.6.4">
|
||||||
|
<artifact name="kotlinx-coroutines-android-1.6.4.jar">
|
||||||
|
<sha256 value="3fdc0eed5bc4b83ee9622774520a2db25470370eacd1581cac1e37704f095b00" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="kotlinx-coroutines-android-1.6.4.module">
|
||||||
|
<sha256 value="68516559e6f84a621b9783cd892a64630ccd7875843588ddb3f0501425e33f15" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-android" version="1.9.0">
|
||||||
|
<artifact name="kotlinx-coroutines-android-1.9.0.jar">
|
||||||
|
<sha256 value="bd783acd2f9738845d58380f46f45b5cde95d0cb03027d56725338b26bfc4d72" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="kotlinx-coroutines-android-1.9.0.module">
|
||||||
|
<sha256 value="7df1e04d77f0cc411890d999a9449b0e3bcd4f159a46c3060b110204ca607d43" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-bom" version="1.10.2">
|
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-bom" version="1.10.2">
|
||||||
<artifact name="kotlinx-coroutines-bom-1.10.2.pom">
|
<artifact name="kotlinx-coroutines-bom-1.10.2.pom">
|
||||||
<sha256 value="faf0c6538e53ddc0499a63664d8e763c216580b2e18e722ccbdf1b431a6afe26" origin="Generated by Gradle"/>
|
<sha256 value="faf0c6538e53ddc0499a63664d8e763c216580b2e18e722ccbdf1b431a6afe26" origin="Generated by Gradle"/>
|
||||||
@@ -3231,6 +3764,16 @@
|
|||||||
<sha256 value="f65860bce58a2bfadf05fdc516d38333421f0e387fef87e24449c0394c80d254" origin="Generated by Gradle"/>
|
<sha256 value="f65860bce58a2bfadf05fdc516d38333421f0e387fef87e24449c0394c80d254" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-bom" version="1.6.4">
|
||||||
|
<artifact name="kotlinx-coroutines-bom-1.6.4.pom">
|
||||||
|
<sha256 value="ab2614855fba66aa8a42514dbe3d5a884315ffe1ed63f5932e710a8006245ce1" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-bom" version="1.7.3">
|
||||||
|
<artifact name="kotlinx-coroutines-bom-1.7.3.pom">
|
||||||
|
<sha256 value="4e5d1900e6379ef3f5970d04a8f30529adc82f859e8cc107c21ce8149ef666c4" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-bom" version="1.8.1">
|
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-bom" version="1.8.1">
|
||||||
<artifact name="kotlinx-coroutines-bom-1.8.1.pom">
|
<artifact name="kotlinx-coroutines-bom-1.8.1.pom">
|
||||||
<sha256 value="563e4aa29fa8fe09a6e1746d0a5b51308f7c7dedc468dc5a0ca810a485877030" origin="Generated by Gradle"/>
|
<sha256 value="563e4aa29fa8fe09a6e1746d0a5b51308f7c7dedc468dc5a0ca810a485877030" origin="Generated by Gradle"/>
|
||||||
@@ -3246,6 +3789,21 @@
|
|||||||
<sha256 value="1e19785d34728b7525d7a77ff32ead4547d51cc7a45d4ac44d4de608169b0c0d" origin="Generated by Gradle"/>
|
<sha256 value="1e19785d34728b7525d7a77ff32ead4547d51cc7a45d4ac44d4de608169b0c0d" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-core" version="1.6.4">
|
||||||
|
<artifact name="kotlinx-coroutines-core-1.6.4.module">
|
||||||
|
<sha256 value="a6eed4a1835588e7c84fcd7b0475fce9a7b3444c870ebc797b88ba64ccf4576b" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-core" version="1.7.3">
|
||||||
|
<artifact name="kotlinx-coroutines-core-1.7.3.module">
|
||||||
|
<sha256 value="7fb162396594ec28e1b6a4411b457949a7670f5e12019176774e1fd6b9471bbf" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-core" version="1.8.1">
|
||||||
|
<artifact name="kotlinx-coroutines-core-1.8.1.module">
|
||||||
|
<sha256 value="08cbaf3325b54e0f8ef8da85e4eb596f7d946f843e5d1600385463f3268a4ef0" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-core" version="1.9.0">
|
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-core" version="1.9.0">
|
||||||
<artifact name="kotlinx-coroutines-core-1.9.0.module">
|
<artifact name="kotlinx-coroutines-core-1.9.0.module">
|
||||||
<sha256 value="ad534034a953b4e12cbeeb874c66adf8b1ca14df15fe0d2e6547aa34e86dfeca" origin="Generated by Gradle"/>
|
<sha256 value="ad534034a953b4e12cbeeb874c66adf8b1ca14df15fe0d2e6547aa34e86dfeca" origin="Generated by Gradle"/>
|
||||||
@@ -3267,6 +3825,14 @@
|
|||||||
<sha256 value="5b255653ad6b1f21e0c46108605f129e3aa56ed9414849cc9f5b436441517528" origin="Generated by Gradle"/>
|
<sha256 value="5b255653ad6b1f21e0c46108605f129e3aa56ed9414849cc9f5b436441517528" origin="Generated by Gradle"/>
|
||||||
</artifact>
|
</artifact>
|
||||||
</component>
|
</component>
|
||||||
|
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-core-jvm" version="1.6.4">
|
||||||
|
<artifact name="kotlinx-coroutines-core-jvm-1.6.4.jar">
|
||||||
|
<sha256 value="c24c8bb27bb320c4a93871501a7e5e0c61607638907b197aef675513d4c820be" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
<artifact name="kotlinx-coroutines-core-jvm-1.6.4.module">
|
||||||
|
<sha256 value="0d94c8a41483e7c2707ebd693e1b1357a84152998ce85550ebbc54ca4321a3a7" origin="Generated by Gradle"/>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-core-jvm" version="1.8.0">
|
<component group="org.jetbrains.kotlinx" name="kotlinx-coroutines-core-jvm" version="1.8.0">
|
||||||
<artifact name="kotlinx-coroutines-core-jvm-1.8.0-sources.jar">
|
<artifact name="kotlinx-coroutines-core-jvm-1.8.0-sources.jar">
|
||||||
<sha256 value="451599ff2044e6a98f975b28d106891cc664ae69ad7a30c572dffb5413202179" origin="Generated by Gradle"/>
|
<sha256 value="451599ff2044e6a98f975b28d106891cc664ae69ad7a30c572dffb5413202179" origin="Generated by Gradle"/>
|
||||||
|
|||||||
@@ -12,11 +12,13 @@ android {
|
|||||||
.toInt()
|
.toInt()
|
||||||
ndkVersion = libs.versions.ndk.get()
|
ndkVersion = libs.versions.ndk.get()
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
minSdk =
|
minSdk =
|
||||||
libs.versions.minSdk
|
libs.versions.minSdk
|
||||||
.get()
|
.get()
|
||||||
.toInt()
|
.toInt()
|
||||||
}
|
}
|
||||||
|
testOptions { targetSdk = libs.versions.compileSdk.get().toInt() }
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
targetCompatibility = JavaVersion.VERSION_17
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
@@ -35,5 +37,9 @@ kotlin {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":core"))
|
implementation(project(":core"))
|
||||||
|
implementation(libs.biometric)
|
||||||
|
implementation(libs.fragment)
|
||||||
testImplementation(libs.junit)
|
testImplementation(libs.junit)
|
||||||
|
androidTestImplementation(libs.android.test.runner)
|
||||||
|
androidTestImplementation(libs.android.test.core)
|
||||||
}
|
}
|
||||||
@@ -2,8 +2,66 @@
|
|||||||
# Manual edits can break the build and are not advised.
|
# Manual edits can break the build and are not advised.
|
||||||
# This file is expected to be part of source control.
|
# This file is expected to be part of source control.
|
||||||
# To regenerate this file, run: ./gradlew :platform:dependencies --write-locks
|
# To regenerate this file, run: ./gradlew :platform:dependencies --write-locks
|
||||||
|
androidx.activity:activity-ktx:1.8.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.activity:activity:1.8.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.annotation:annotation-experimental:1.4.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
androidx.annotation:annotation-jvm:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.annotation:annotation-jvm:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.annotation:annotation-jvm:1.9.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
||||||
androidx.annotation:annotation:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
androidx.annotation:annotation:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.annotation:annotation:1.9.1=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
||||||
|
androidx.appcompat:appcompat-resources:1.2.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.appcompat:appcompat:1.2.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.arch.core:core-common:2.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.arch.core:core-runtime:2.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.biometric:biometric:1.1.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.collection:collection-jvm:1.4.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
||||||
|
androidx.collection:collection-jvm:1.6.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.collection:collection:1.4.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
||||||
|
androidx.collection:collection:1.6.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.concurrent:concurrent-futures-ktx:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
|
androidx.concurrent:concurrent-futures:1.1.0=debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.concurrent:concurrent-futures:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
|
androidx.core:core-ktx:1.13.1=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.core:core-ktx:1.9.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
||||||
|
androidx.core:core-viewtree:1.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.core:core:1.13.1=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.core:core:1.9.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
||||||
|
androidx.cursoradapter:cursoradapter:1.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.customview:customview:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.drawerlayout:drawerlayout:1.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.fragment:fragment:1.9.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.interpolator:interpolator:1.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.lifecycle:lifecycle-common-jvm:2.10.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.lifecycle:lifecycle-common:2.10.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.lifecycle:lifecycle-livedata-core-ktx:2.10.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.lifecycle:lifecycle-livedata-core:2.10.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.lifecycle:lifecycle-livedata:2.10.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.lifecycle:lifecycle-runtime-android:2.10.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.lifecycle:lifecycle-runtime-ktx-android:2.10.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.lifecycle:lifecycle-runtime-ktx:2.10.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.lifecycle:lifecycle-runtime:2.10.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.lifecycle:lifecycle-viewmodel-android:2.10.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.lifecycle:lifecycle-viewmodel-ktx:2.10.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.lifecycle:lifecycle-viewmodel-savedstate-android:2.10.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.lifecycle:lifecycle-viewmodel-savedstate:2.10.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.lifecycle:lifecycle-viewmodel:2.10.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.loader:loader:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.profileinstaller:profileinstaller:1.4.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.savedstate:savedstate-android:1.4.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.savedstate:savedstate-ktx:1.4.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.savedstate:savedstate:1.4.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.startup:startup-runtime:1.1.1=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.test.services:storage:1.6.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
|
androidx.test:core:1.7.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
|
androidx.test:monitor:1.8.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
|
androidx.test:runner:1.7.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
|
androidx.tracing:tracing-android:2.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.tracing:tracing:1.1.0=debugAndroidTestCompileClasspath
|
||||||
|
androidx.tracing:tracing:2.0.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.vectordrawable:vectordrawable-animated:1.1.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.vectordrawable:vectordrawable:1.1.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
ch.qos.logback:logback-classic:1.3.15=ktlint
|
ch.qos.logback:logback-classic:1.3.15=ktlint
|
||||||
ch.qos.logback:logback-core:1.3.15=ktlint
|
ch.qos.logback:logback-core:1.3.15=ktlint
|
||||||
com.android.tools.analytics-library:protos:32.4.1=androidLintTool
|
com.android.tools.analytics-library:protos:32.4.1=androidLintTool
|
||||||
@@ -42,6 +100,7 @@ com.google.code.gson:gson:2.11.0=androidLintTool
|
|||||||
com.google.errorprone:error_prone_annotations:2.36.0=androidLintTool
|
com.google.errorprone:error_prone_annotations:2.36.0=androidLintTool
|
||||||
com.google.guava:failureaccess:1.0.2=androidLintTool
|
com.google.guava:failureaccess:1.0.2=androidLintTool
|
||||||
com.google.guava:guava:33.4.0-jre=androidLintTool
|
com.google.guava:guava:33.4.0-jre=androidLintTool
|
||||||
|
com.google.guava:listenablefuture:1.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=androidLintTool
|
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=androidLintTool
|
||||||
com.google.j2objc:j2objc-annotations:3.0.0=androidLintTool
|
com.google.j2objc:j2objc-annotations:3.0.0=androidLintTool
|
||||||
com.google.jimfs:jimfs:1.1=androidLintTool
|
com.google.jimfs:jimfs:1.1=androidLintTool
|
||||||
@@ -75,7 +134,7 @@ io.github.oshai:kotlin-logging:5.1.0=ktlint,ktlintBaselineReporter,ktlintReporte
|
|||||||
jakarta.activation:jakarta.activation-api:1.2.1=androidLintTool
|
jakarta.activation:jakarta.activation-api:1.2.1=androidLintTool
|
||||||
jakarta.xml.bind:jakarta.xml.bind-api:2.3.2=androidLintTool
|
jakarta.xml.bind:jakarta.xml.bind-api:2.3.2=androidLintTool
|
||||||
javax.inject:javax.inject:1=androidLintTool
|
javax.inject:javax.inject:1=androidLintTool
|
||||||
junit:junit:4.13.2=debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
junit:junit:4.13.2=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
||||||
net.java.dev.jna:jna-platform:5.6.0=androidLintTool
|
net.java.dev.jna:jna-platform:5.6.0=androidLintTool
|
||||||
net.java.dev.jna:jna:5.19.1=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
net.java.dev.jna:jna:5.19.1=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
net.java.dev.jna:jna:5.6.0=androidLintTool
|
net.java.dev.jna:jna:5.6.0=androidLintTool
|
||||||
@@ -94,7 +153,7 @@ org.checkerframework:checker-qual:3.43.0=androidLintTool
|
|||||||
org.ec4j.core:ec4j-core:1.1.1=ktlint,ktlintBaselineReporter,ktlintRuleset
|
org.ec4j.core:ec4j-core:1.1.1=ktlint,ktlintBaselineReporter,ktlintRuleset
|
||||||
org.glassfish.jaxb:jaxb-runtime:2.3.2=androidLintTool
|
org.glassfish.jaxb:jaxb-runtime:2.3.2=androidLintTool
|
||||||
org.glassfish.jaxb:txw2:2.3.2=androidLintTool
|
org.glassfish.jaxb:txw2:2.3.2=androidLintTool
|
||||||
org.hamcrest:hamcrest-core:1.3=debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
org.hamcrest:hamcrest-core:1.3=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.0=kotlinAbiValidationCompatClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.0=kotlinAbiValidationCompatClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-api:2.4.21=kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlin:kotlin-build-tools-compat:2.4.21=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-build-tools-compat:2.4.21=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
@@ -128,19 +187,24 @@ org.jetbrains.kotlin:kotlin-stdlib:2.4.0=kotlinAbiValidationCompatClasspath
|
|||||||
org.jetbrains.kotlin:kotlin-stdlib:2.4.21=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
org.jetbrains.kotlin:kotlin-stdlib:2.4.21=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlin:kotlin-tooling-core:2.4.21=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
org.jetbrains.kotlin:kotlin-tooling-core:2.4.21=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0=androidLintTool,unified-test-platform-gradle-work-action
|
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0=androidLintTool,debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath,unified-test-platform-gradle-work-action
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.0=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,ktlint,ktlintBaselineReporter,ktlintRuleset
|
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.0=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,ktlint,ktlintBaselineReporter,ktlintRuleset
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0=androidLintTool,unified-test-platform-gradle-work-action
|
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0=androidLintTool,debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath,unified-test-platform-gradle-work-action
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.11.0=debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0=androidLintTool,unified-test-platform-gradle-work-action
|
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0=androidLintTool,debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,releaseCompileClasspath,unified-test-platform-gradle-work-action
|
||||||
|
org.jetbrains.kotlinx:kotlinx-serialization-bom:1.7.3=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.4.1=ktlintReporter
|
org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.4.1=ktlintReporter
|
||||||
|
org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.7.3=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-serialization-core:1.4.1=ktlintReporter
|
org.jetbrains.kotlinx:kotlinx-serialization-core:1.4.1=ktlintReporter
|
||||||
|
org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.3=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.4.1=ktlintReporter
|
org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.4.1=ktlintReporter
|
||||||
org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1=ktlintReporter
|
org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1=ktlintReporter
|
||||||
org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugUnitTestCompileClasspath,kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,ktlint,ktlintBaselineReporter,ktlintReporter,ktlintRuleset,releaseCompileClasspath
|
org.jetbrains:annotations:13.0=kotlinAbiValidationCompatClasspath,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,ktlint,ktlintBaselineReporter,ktlintReporter,ktlintRuleset
|
||||||
org.jetbrains:annotations:23.0.0=androidLintTool,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath,unified-test-platform-gradle-work-action
|
org.jetbrains:annotations:23.0.0=androidLintTool,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath,unified-test-platform-gradle-work-action
|
||||||
|
org.jspecify:jspecify:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
org.junit.platform:junit-platform-commons:1.13.3=unified-test-platform-gradle-work-action
|
org.junit.platform:junit-platform-commons:1.13.3=unified-test-platform-gradle-work-action
|
||||||
org.junit.platform:junit-platform-engine:1.13.3=unified-test-platform-gradle-work-action
|
org.junit.platform:junit-platform-engine:1.13.3=unified-test-platform-gradle-work-action
|
||||||
org.junit.platform:junit-platform-launcher:1.13.3=unified-test-platform-gradle-work-action
|
org.junit.platform:junit-platform-launcher:1.13.3=unified-test-platform-gradle-work-action
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<application>
|
||||||
|
<activity android:name="de.rfc1437.ironstorage.platform.KeystoreTestActivity" android:exported="false" android:theme="@android:style/Theme.Material.Light.NoActionBar" />
|
||||||
|
</application>
|
||||||
|
</manifest>
|
||||||
+359
@@ -0,0 +1,359 @@
|
|||||||
|
package de.rfc1437.ironstorage.platform
|
||||||
|
|
||||||
|
import android.security.keystore.KeyInfo
|
||||||
|
import androidx.test.core.app.ActivityScenario
|
||||||
|
import androidx.test.filters.SdkSuppress
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import de.rfc1437.ironstorage.core.KeystoreAuthorization
|
||||||
|
import de.rfc1437.ironstorage.core.KeystoreException
|
||||||
|
import de.rfc1437.ironstorage.core.KeystoreFailure
|
||||||
|
import de.rfc1437.ironstorage.core.KeystoreKeySpecification
|
||||||
|
import java.security.KeyStore
|
||||||
|
import java.util.UUID
|
||||||
|
import javax.crypto.SecretKey
|
||||||
|
import javax.crypto.SecretKeyFactory
|
||||||
|
import org.junit.Assert.assertArrayEquals
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class AndroidKeystoreTest {
|
||||||
|
private val context = InstrumentationRegistry.getInstrumentation().targetContext
|
||||||
|
|
||||||
|
@Before fun removeAbandonedFixtureKeys() {
|
||||||
|
val os = AndroidKeystoreAdapter(context)
|
||||||
|
os.aliases().filter {
|
||||||
|
it.startsWith("ironstorage.issue93.fixture.")
|
||||||
|
}.forEach { os.deleteKey(it) }
|
||||||
|
}
|
||||||
|
private fun alias(): String = "ironstorage.issue93.fixture.${UUID.randomUUID()}"
|
||||||
|
private fun specification(
|
||||||
|
alias: String,
|
||||||
|
auth: KeystoreAuthorization = KeystoreAuthorization.None
|
||||||
|
) = KeystoreKeySpecification(
|
||||||
|
alias,
|
||||||
|
auth,
|
||||||
|
true,
|
||||||
|
auth == KeystoreAuthorization.StrongBiometric,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
private fun failure(expected: KeystoreFailure, block: () -> Unit) {
|
||||||
|
try {
|
||||||
|
block()
|
||||||
|
throw AssertionError("Expected typed failure")
|
||||||
|
} catch (
|
||||||
|
error: KeystoreException
|
||||||
|
) {
|
||||||
|
assertEquals(expected, error.kind)
|
||||||
|
assertEquals("Keystore operation failed", error.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun deviceUnlockedRoundtripReplaceDeleteAndTamper() {
|
||||||
|
val os = AndroidKeystoreAdapter(context)
|
||||||
|
assertFalse(os.deviceState().locked)
|
||||||
|
val alias = alias()
|
||||||
|
try {
|
||||||
|
os.createKey(specification(alias))
|
||||||
|
failure(KeystoreFailure.AlreadyExists) { os.createKey(specification(alias)) }
|
||||||
|
val clear = "public-test-token".toByteArray()
|
||||||
|
val encrypted = os.encrypt(alias, KeystoreAuthorization.None, byteArrayOf(1, 2), clear)
|
||||||
|
assertTrue(clear.all { it == 0.toByte() })
|
||||||
|
assertEquals(12, encrypted.nonce.size)
|
||||||
|
val retrieved = os.decrypt(
|
||||||
|
alias,
|
||||||
|
KeystoreAuthorization.None,
|
||||||
|
byteArrayOf(1, 2),
|
||||||
|
encrypted
|
||||||
|
)
|
||||||
|
try {
|
||||||
|
assertArrayEquals("public-test-token".toByteArray(), retrieved)
|
||||||
|
} finally {
|
||||||
|
retrieved.fill(0)
|
||||||
|
}
|
||||||
|
failure(KeystoreFailure.Corrupted) {
|
||||||
|
os.decrypt(alias, KeystoreAuthorization.None, byteArrayOf(3), encrypted)
|
||||||
|
}
|
||||||
|
encrypted.bytes[encrypted.bytes.lastIndex] =
|
||||||
|
(encrypted.bytes.last().toInt() xor 1).toByte()
|
||||||
|
failure(KeystoreFailure.Corrupted) {
|
||||||
|
os.decrypt(alias, KeystoreAuthorization.None, byteArrayOf(1, 2), encrypted)
|
||||||
|
}
|
||||||
|
val store = KeyStore.getInstance("AndroidKeyStore").apply { load(null) }
|
||||||
|
val key = store.getKey(alias, null) as SecretKey
|
||||||
|
val info = SecretKeyFactory.getInstance(
|
||||||
|
key.algorithm,
|
||||||
|
"AndroidKeyStore"
|
||||||
|
).getKeySpec(key, KeyInfo::class.java) as KeyInfo
|
||||||
|
assertEquals(256, info.keySize)
|
||||||
|
assertFalse(info.isUserAuthenticationRequired)
|
||||||
|
assertTrue(os.aliases().contains(alias))
|
||||||
|
os.deleteKey(alias)
|
||||||
|
failure(KeystoreFailure.MissingKey) {
|
||||||
|
os.decrypt(alias, KeystoreAuthorization.None, byteArrayOf(1, 2), encrypted)
|
||||||
|
}
|
||||||
|
os.deleteKey(alias)
|
||||||
|
} finally {
|
||||||
|
os.deleteKey(alias)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun biometricRoundtripAndCancellation() {
|
||||||
|
val os = AndroidKeystoreAdapter(context)
|
||||||
|
assertTrue(
|
||||||
|
"Enroll synthetic fingerprint before this test",
|
||||||
|
os.deviceState().strongBiometric
|
||||||
|
)
|
||||||
|
val alias = alias()
|
||||||
|
ActivityScenario.launch(KeystoreTestActivity::class.java).use { scenario ->
|
||||||
|
lateinit var host: KeystoreTestActivity
|
||||||
|
scenario.onActivity {
|
||||||
|
host = it
|
||||||
|
os.attach(it)
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
os.createKey(specification(alias, KeystoreAuthorization.StrongBiometric))
|
||||||
|
val store = KeyStore.getInstance("AndroidKeyStore").apply { load(null) }
|
||||||
|
val key = store.getKey(alias, null) as SecretKey
|
||||||
|
val info = SecretKeyFactory.getInstance(
|
||||||
|
key.algorithm,
|
||||||
|
"AndroidKeyStore"
|
||||||
|
).getKeySpec(key, KeyInfo::class.java) as KeyInfo
|
||||||
|
assertTrue(info.isUserAuthenticationRequired)
|
||||||
|
assertTrue(info.isInvalidatedByBiometricEnrollment)
|
||||||
|
assertEquals(0, info.userAuthenticationValidityDurationSeconds)
|
||||||
|
host.stage("93:biometric-encrypt")
|
||||||
|
val encrypted = os.encrypt(
|
||||||
|
alias,
|
||||||
|
KeystoreAuthorization.StrongBiometric,
|
||||||
|
byteArrayOf(4),
|
||||||
|
"public-passphrase".toByteArray()
|
||||||
|
)
|
||||||
|
host.stage("93:biometric-decrypt")
|
||||||
|
val clear = os.decrypt(
|
||||||
|
alias,
|
||||||
|
KeystoreAuthorization.StrongBiometric,
|
||||||
|
byteArrayOf(4),
|
||||||
|
encrypted
|
||||||
|
)
|
||||||
|
try {
|
||||||
|
assertArrayEquals("public-passphrase".toByteArray(), clear)
|
||||||
|
} finally {
|
||||||
|
clear.fill(0)
|
||||||
|
}
|
||||||
|
host.stage("93:biometric-cancel")
|
||||||
|
failure(KeystoreFailure.Cancelled) {
|
||||||
|
os.decrypt(
|
||||||
|
alias,
|
||||||
|
KeystoreAuthorization.StrongBiometric,
|
||||||
|
byteArrayOf(4),
|
||||||
|
encrypted
|
||||||
|
)
|
||||||
|
}
|
||||||
|
host.stage("93:complete")
|
||||||
|
} catch (error: KeystoreException) {
|
||||||
|
throw AssertionError("Typed Keystore failure: ${error.kind}", error)
|
||||||
|
} finally {
|
||||||
|
os.cancelPending()
|
||||||
|
os.detach(host)
|
||||||
|
os.deleteKey(alias)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun userPresenceSupportsTheConfiguredCredentialFlow() {
|
||||||
|
val os = AndroidKeystoreAdapter(context)
|
||||||
|
val alias = alias()
|
||||||
|
ActivityScenario.launch(KeystoreTestActivity::class.java).use { scenario ->
|
||||||
|
lateinit var host: KeystoreTestActivity
|
||||||
|
scenario.onActivity {
|
||||||
|
host = it
|
||||||
|
os.attach(it)
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
os.createKey(specification(alias, KeystoreAuthorization.UserPresence))
|
||||||
|
host.stage("93:presence-encrypt")
|
||||||
|
val encrypted = os.encrypt(
|
||||||
|
alias,
|
||||||
|
KeystoreAuthorization.UserPresence,
|
||||||
|
byteArrayOf(7),
|
||||||
|
"public-passphrase".toByteArray()
|
||||||
|
)
|
||||||
|
host.stage("93:presence-decrypt")
|
||||||
|
val clear = os.decrypt(
|
||||||
|
alias,
|
||||||
|
KeystoreAuthorization.UserPresence,
|
||||||
|
byteArrayOf(7),
|
||||||
|
encrypted
|
||||||
|
)
|
||||||
|
try {
|
||||||
|
assertArrayEquals("public-passphrase".toByteArray(), clear)
|
||||||
|
} finally {
|
||||||
|
clear.fill(0)
|
||||||
|
}
|
||||||
|
} catch (error: KeystoreException) {
|
||||||
|
throw AssertionError("Typed Keystore failure: ${error.kind}", error)
|
||||||
|
} finally {
|
||||||
|
os.cancelPending()
|
||||||
|
os.detach(host)
|
||||||
|
os.deleteKey(alias)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SdkSuppress(maxSdkVersion = 36)
|
||||||
|
fun biometricLockoutIsTyped() {
|
||||||
|
val os = AndroidKeystoreAdapter(context)
|
||||||
|
val alias = alias()
|
||||||
|
ActivityScenario.launch(KeystoreTestActivity::class.java).use { scenario ->
|
||||||
|
lateinit var host: KeystoreTestActivity
|
||||||
|
scenario.onActivity {
|
||||||
|
host = it
|
||||||
|
os.attach(it)
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
os.createKey(specification(alias, KeystoreAuthorization.StrongBiometric))
|
||||||
|
host.stage("93:biometric-lockout")
|
||||||
|
failure(KeystoreFailure.Lockout) {
|
||||||
|
os.encrypt(
|
||||||
|
alias,
|
||||||
|
KeystoreAuthorization.StrongBiometric,
|
||||||
|
byteArrayOf(8),
|
||||||
|
"public-passphrase".toByteArray()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
os.cancelPending()
|
||||||
|
os.detach(host)
|
||||||
|
os.deleteKey(alias)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SdkSuppress(minSdkVersion = 37)
|
||||||
|
fun biometricLockoutRecoveryStillRequiresMatchingBiometric() {
|
||||||
|
val os = AndroidKeystoreAdapter(context)
|
||||||
|
val alias = alias()
|
||||||
|
ActivityScenario.launch(KeystoreTestActivity::class.java).use { scenario ->
|
||||||
|
lateinit var host: KeystoreTestActivity
|
||||||
|
scenario.onActivity {
|
||||||
|
host = it
|
||||||
|
os.attach(it)
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
os.createKey(specification(alias, KeystoreAuthorization.StrongBiometric))
|
||||||
|
host.stage("93:biometric-lockout-recovery")
|
||||||
|
failure(KeystoreFailure.Cancelled) {
|
||||||
|
os.encrypt(
|
||||||
|
alias,
|
||||||
|
KeystoreAuthorization.StrongBiometric,
|
||||||
|
byteArrayOf(8),
|
||||||
|
"public-passphrase".toByteArray()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
os.cancelPending()
|
||||||
|
os.detach(host)
|
||||||
|
os.deleteKey(alias)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun addingBiometricInvalidatesTheProtectedKey() = invalidation("93:add-enrollment")
|
||||||
|
|
||||||
|
@Test fun removingAllBiometricsInvalidatesTheProtectedKey() = invalidation(
|
||||||
|
"93:remove-enrollment"
|
||||||
|
)
|
||||||
|
|
||||||
|
@Test fun removingSecureLockInvalidatesTheProtectedKey() =
|
||||||
|
invalidation("93:remove-lock", KeystoreFailure.MissingKey)
|
||||||
|
|
||||||
|
private fun invalidation(
|
||||||
|
stage: String,
|
||||||
|
expected: KeystoreFailure = KeystoreFailure.Invalidated
|
||||||
|
) {
|
||||||
|
val os = AndroidKeystoreAdapter(context)
|
||||||
|
assertTrue(os.deviceState().strongBiometric)
|
||||||
|
val alias = alias()
|
||||||
|
val credentialAlias = alias()
|
||||||
|
ActivityScenario.launch(KeystoreTestActivity::class.java).use { scenario ->
|
||||||
|
lateinit var host: KeystoreTestActivity
|
||||||
|
scenario.onActivity {
|
||||||
|
host = it
|
||||||
|
os.attach(it)
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
os.createKey(specification(credentialAlias))
|
||||||
|
val credential = os.encrypt(
|
||||||
|
credentialAlias,
|
||||||
|
KeystoreAuthorization.None,
|
||||||
|
byteArrayOf(10),
|
||||||
|
"public-token".toByteArray()
|
||||||
|
)
|
||||||
|
os.createKey(specification(alias, KeystoreAuthorization.StrongBiometric))
|
||||||
|
host.stage("93:biometric-encrypt")
|
||||||
|
val encrypted = os.encrypt(
|
||||||
|
alias,
|
||||||
|
KeystoreAuthorization.StrongBiometric,
|
||||||
|
byteArrayOf(9),
|
||||||
|
"public-passphrase".toByteArray()
|
||||||
|
)
|
||||||
|
assertTrue(
|
||||||
|
"Complete the indicated emulator fixture change",
|
||||||
|
host.awaitStep(stage)
|
||||||
|
)
|
||||||
|
if (expected ==
|
||||||
|
KeystoreFailure.MissingKey
|
||||||
|
) {
|
||||||
|
assertFalse(os.aliases().contains(alias))
|
||||||
|
}
|
||||||
|
val token = os.decrypt(
|
||||||
|
credentialAlias,
|
||||||
|
KeystoreAuthorization.None,
|
||||||
|
byteArrayOf(10),
|
||||||
|
credential
|
||||||
|
)
|
||||||
|
try {
|
||||||
|
assertArrayEquals("public-token".toByteArray(), token)
|
||||||
|
} finally {
|
||||||
|
token.fill(0)
|
||||||
|
}
|
||||||
|
failure(expected) {
|
||||||
|
os.decrypt(
|
||||||
|
alias,
|
||||||
|
KeystoreAuthorization.StrongBiometric,
|
||||||
|
byteArrayOf(9),
|
||||||
|
encrypted
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} catch (error: KeystoreException) {
|
||||||
|
throw AssertionError("Typed Keystore failure: ${error.kind}", error)
|
||||||
|
} finally {
|
||||||
|
os.cancelPending()
|
||||||
|
os.detach(host)
|
||||||
|
os.deleteKey(alias)
|
||||||
|
os.deleteKey(credentialAlias)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun protectedKeyRequiresAnAuthenticationHost() {
|
||||||
|
val os = AndroidKeystoreAdapter(context)
|
||||||
|
assertTrue(os.deviceState().strongBiometric)
|
||||||
|
val alias = alias()
|
||||||
|
try {
|
||||||
|
os.createKey(specification(alias, KeystoreAuthorization.StrongBiometric))
|
||||||
|
val value = "public-test-passphrase".toByteArray()
|
||||||
|
failure(KeystoreFailure.Unavailable) {
|
||||||
|
os.encrypt(alias, KeystoreAuthorization.StrongBiometric, byteArrayOf(1), value)
|
||||||
|
}
|
||||||
|
assertTrue(value.all { it == 0.toByte() })
|
||||||
|
} finally {
|
||||||
|
os.deleteKey(alias)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+50
@@ -0,0 +1,50 @@
|
|||||||
|
package de.rfc1437.ironstorage.platform
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.widget.Button
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import de.rfc1437.ironstorage.platform.test.R
|
||||||
|
import java.util.concurrent.CountDownLatch
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import java.util.concurrent.atomic.AtomicReference
|
||||||
|
|
||||||
|
/** Instrumentation host, omitted from release builds; shows stages, never secrets. */
|
||||||
|
class KeystoreTestActivity : FragmentActivity() {
|
||||||
|
private lateinit var label: TextView
|
||||||
|
private val step = AtomicReference<CountDownLatch?>()
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
label = TextView(this).apply {
|
||||||
|
setText(R.string.keystore_fixture_title)
|
||||||
|
textSize = 24f
|
||||||
|
}
|
||||||
|
val next = Button(this).apply {
|
||||||
|
setText(R.string.keystore_fixture_continue)
|
||||||
|
setOnClickListener { step.get()?.countDown() }
|
||||||
|
}
|
||||||
|
setContentView(
|
||||||
|
LinearLayout(this).apply {
|
||||||
|
orientation = LinearLayout.VERTICAL
|
||||||
|
setPadding(0, 80, 0, 0)
|
||||||
|
addView(label)
|
||||||
|
addView(next)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fun awaitStep(value: String): Boolean {
|
||||||
|
val next = CountDownLatch(1)
|
||||||
|
step.set(next)
|
||||||
|
stage(value)
|
||||||
|
return try {
|
||||||
|
next.await(180, TimeUnit.SECONDS)
|
||||||
|
} finally {
|
||||||
|
step.set(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun stage(value: String) {
|
||||||
|
android.util.Log.i("IronStorage93", value)
|
||||||
|
runOnUiThread { label.text = value }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<resources>
|
||||||
|
<string name="keystore_fixture_title" translatable="false">Keystore fixture</string>
|
||||||
|
<string name="keystore_fixture_continue" translatable="false">Continue fixture</string>
|
||||||
|
</resources>
|
||||||
@@ -1 +1,3 @@
|
|||||||
<manifest />
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||||
|
</manifest>
|
||||||
+306
@@ -0,0 +1,306 @@
|
|||||||
|
package de.rfc1437.ironstorage.platform
|
||||||
|
|
||||||
|
import android.app.KeyguardManager
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.security.keystore.KeyGenParameterSpec
|
||||||
|
import android.security.keystore.KeyPermanentlyInvalidatedException
|
||||||
|
import android.security.keystore.KeyProperties
|
||||||
|
import android.security.keystore.StrongBoxUnavailableException
|
||||||
|
import android.security.keystore.UserNotAuthenticatedException
|
||||||
|
import androidx.biometric.BiometricManager
|
||||||
|
import androidx.biometric.BiometricPrompt
|
||||||
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import de.rfc1437.ironstorage.core.AndroidKeystore
|
||||||
|
import de.rfc1437.ironstorage.core.KeystoreAuthorization
|
||||||
|
import de.rfc1437.ironstorage.core.KeystoreCiphertext
|
||||||
|
import de.rfc1437.ironstorage.core.KeystoreDeviceState
|
||||||
|
import de.rfc1437.ironstorage.core.KeystoreException
|
||||||
|
import de.rfc1437.ironstorage.core.KeystoreFailure
|
||||||
|
import de.rfc1437.ironstorage.core.KeystoreKeySpecification
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
|
import java.security.KeyStore
|
||||||
|
import java.util.concurrent.CountDownLatch
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import java.util.concurrent.atomic.AtomicReference
|
||||||
|
import javax.crypto.AEADBadTagException
|
||||||
|
import javax.crypto.Cipher
|
||||||
|
import javax.crypto.KeyGenerator
|
||||||
|
import javax.crypto.SecretKey
|
||||||
|
import javax.crypto.spec.GCMParameterSpec
|
||||||
|
|
||||||
|
/** Android API mechanics only; ciphertext is returned to Rust for private persistence. */
|
||||||
|
class AndroidKeystoreAdapter(context: Context) : AndroidKeystore {
|
||||||
|
private val context = context.applicationContext
|
||||||
|
private val keyguard = context.getSystemService(KeyguardManager::class.java)
|
||||||
|
private val handler = Handler(Looper.getMainLooper())
|
||||||
|
private var activity = WeakReference<FragmentActivity>(null)
|
||||||
|
private val pending = AtomicReference<Pending?>()
|
||||||
|
|
||||||
|
fun attach(host: FragmentActivity) {
|
||||||
|
activity = WeakReference(host)
|
||||||
|
}
|
||||||
|
fun detach(host: FragmentActivity) {
|
||||||
|
if (activity.get() === host) {
|
||||||
|
cancelPending()
|
||||||
|
activity.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override fun deviceState(): KeystoreDeviceState = KeystoreDeviceState(
|
||||||
|
Build.VERSION.SDK_INT,
|
||||||
|
keyguard.isDeviceLocked,
|
||||||
|
keyguard.isDeviceSecure,
|
||||||
|
BiometricManager.from(
|
||||||
|
context
|
||||||
|
).canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG) ==
|
||||||
|
BiometricManager.BIOMETRIC_SUCCESS,
|
||||||
|
Build.VERSION.SDK_INT >= 28 &&
|
||||||
|
context.packageManager.hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE)
|
||||||
|
)
|
||||||
|
override fun createKey(specification: KeystoreKeySpecification) = operation {
|
||||||
|
val store = store()
|
||||||
|
if (store.containsAlias(specification.alias)) fail(KeystoreFailure.AlreadyExists)
|
||||||
|
val builder = KeyGenParameterSpec.Builder(
|
||||||
|
specification.alias,
|
||||||
|
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
|
||||||
|
)
|
||||||
|
.setKeySize(256)
|
||||||
|
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
|
||||||
|
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
|
||||||
|
.setRandomizedEncryptionRequired(true)
|
||||||
|
if (specification.unlockedDevice) {
|
||||||
|
if (Build.VERSION.SDK_INT < 28) fail(KeystoreFailure.UnsupportedProtection)
|
||||||
|
builder.setUnlockedDeviceRequired(true)
|
||||||
|
}
|
||||||
|
if (specification.strongbox) {
|
||||||
|
if (Build.VERSION.SDK_INT < 28) fail(KeystoreFailure.StrongboxUnavailable)
|
||||||
|
builder.setIsStrongBoxBacked(true)
|
||||||
|
}
|
||||||
|
if (specification.authorization != KeystoreAuthorization.None) {
|
||||||
|
builder.setUserAuthenticationRequired(true)
|
||||||
|
if (Build.VERSION.SDK_INT >= 30) {
|
||||||
|
val authenticators = when (specification.authorization) {
|
||||||
|
KeystoreAuthorization.StrongBiometric -> KeyProperties.AUTH_BIOMETRIC_STRONG
|
||||||
|
KeystoreAuthorization.UserPresence ->
|
||||||
|
KeyProperties.AUTH_BIOMETRIC_STRONG or
|
||||||
|
KeyProperties.AUTH_DEVICE_CREDENTIAL
|
||||||
|
KeystoreAuthorization.None -> fail(KeystoreFailure.UnsupportedProtection)
|
||||||
|
}
|
||||||
|
builder.setUserAuthenticationParameters(0, authenticators)
|
||||||
|
} else {
|
||||||
|
if (specification.authorization !=
|
||||||
|
KeystoreAuthorization.StrongBiometric
|
||||||
|
) {
|
||||||
|
fail(KeystoreFailure.UnsupportedProtection)
|
||||||
|
}
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
builder.setUserAuthenticationValidityDurationSeconds(-1)
|
||||||
|
}
|
||||||
|
builder.setInvalidatedByBiometricEnrollment(specification.invalidateOnEnrollment)
|
||||||
|
}
|
||||||
|
KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore").apply {
|
||||||
|
init(builder.build())
|
||||||
|
generateKey()
|
||||||
|
}
|
||||||
|
Unit
|
||||||
|
}
|
||||||
|
override fun encrypt(
|
||||||
|
alias: String,
|
||||||
|
authorization: KeystoreAuthorization,
|
||||||
|
aad: ByteArray,
|
||||||
|
value: ByteArray
|
||||||
|
): KeystoreCiphertext = operation {
|
||||||
|
try {
|
||||||
|
requireUnlocked()
|
||||||
|
val cipher = cipher(alias, Cipher.ENCRYPT_MODE, null)
|
||||||
|
// Auth-bound providers can process AAD immediately.
|
||||||
|
authenticate(cipher, authorization)
|
||||||
|
cipher.updateAAD(aad)
|
||||||
|
val bytes = cipher.doFinal(value)
|
||||||
|
requireUnlocked()
|
||||||
|
KeystoreCiphertext(cipher.iv, bytes)
|
||||||
|
} finally {
|
||||||
|
value.fill(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override fun decrypt(
|
||||||
|
alias: String,
|
||||||
|
authorization: KeystoreAuthorization,
|
||||||
|
aad: ByteArray,
|
||||||
|
value: KeystoreCiphertext
|
||||||
|
): ByteArray = operation {
|
||||||
|
requireUnlocked()
|
||||||
|
if (value.nonce.size != 12 || value.bytes.size < 17) fail(KeystoreFailure.Corrupted)
|
||||||
|
val cipher = cipher(alias, Cipher.DECRYPT_MODE, value.nonce)
|
||||||
|
authenticate(cipher, authorization)
|
||||||
|
cipher.updateAAD(aad)
|
||||||
|
val clear = cipher.doFinal(value.bytes)
|
||||||
|
try {
|
||||||
|
requireUnlocked()
|
||||||
|
clear
|
||||||
|
} catch (error: Exception) {
|
||||||
|
clear.fill(0)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override fun deleteKey(alias: String) = operation { store().deleteEntry(alias) }
|
||||||
|
override fun aliases(): List<String> = operation { store().aliases().toList() }
|
||||||
|
override fun cancelPending() {
|
||||||
|
pending.getAndSet(null)?.let { request ->
|
||||||
|
request.error.set(KeystoreFailure.Cancelled)
|
||||||
|
request.done.countDown()
|
||||||
|
handler.post {
|
||||||
|
request.prompt?.cancelAuthentication()
|
||||||
|
request.prompt = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private fun store(): KeyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) }
|
||||||
|
private fun cipher(alias: String, mode: Int, nonce: ByteArray?): Cipher {
|
||||||
|
val key = store().getKey(alias, null) as? SecretKey
|
||||||
|
?: fail(KeystoreFailure.MissingKey)
|
||||||
|
return Cipher.getInstance("AES/GCM/NoPadding").apply {
|
||||||
|
if (nonce == null) {
|
||||||
|
init(mode, key)
|
||||||
|
} else {
|
||||||
|
init(mode, key, GCMParameterSpec(128, nonce))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private fun requireUnlocked() {
|
||||||
|
if (keyguard.isDeviceLocked) fail(KeystoreFailure.Locked)
|
||||||
|
}
|
||||||
|
private class Pending {
|
||||||
|
val done = CountDownLatch(1)
|
||||||
|
val error = AtomicReference<KeystoreFailure?>()
|
||||||
|
val authenticated = AtomicReference<Cipher?>()
|
||||||
|
var prompt: BiometricPrompt? = null
|
||||||
|
}
|
||||||
|
private fun authenticate(cipher: Cipher, authorization: KeystoreAuthorization) {
|
||||||
|
if (authorization == KeystoreAuthorization.None) return
|
||||||
|
if (Looper.myLooper() == Looper.getMainLooper()) fail(KeystoreFailure.Unavailable)
|
||||||
|
val request = Pending()
|
||||||
|
if (!pending.compareAndSet(null, request)) fail(KeystoreFailure.Unavailable)
|
||||||
|
handler.post {
|
||||||
|
if (pending.get() !== request) return@post
|
||||||
|
val host = activity.get()
|
||||||
|
if (host == null || host.isFinishing || host.isDestroyed) {
|
||||||
|
request.error.set(KeystoreFailure.Unavailable)
|
||||||
|
request.done.countDown()
|
||||||
|
return@post
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
val callback = object : BiometricPrompt.AuthenticationCallback() {
|
||||||
|
override fun onAuthenticationSucceeded(
|
||||||
|
result: BiometricPrompt.AuthenticationResult
|
||||||
|
) {
|
||||||
|
if (pending.get() ===
|
||||||
|
request
|
||||||
|
) {
|
||||||
|
request.authenticated.set(result.cryptoObject?.cipher)
|
||||||
|
}
|
||||||
|
request.done.countDown()
|
||||||
|
}
|
||||||
|
override fun onAuthenticationError(code: Int, message: CharSequence) {
|
||||||
|
request.error.set(
|
||||||
|
when (code) {
|
||||||
|
BiometricPrompt.ERROR_CANCELED,
|
||||||
|
BiometricPrompt.ERROR_USER_CANCELED,
|
||||||
|
BiometricPrompt.ERROR_NEGATIVE_BUTTON ->
|
||||||
|
KeystoreFailure.Cancelled
|
||||||
|
BiometricPrompt.ERROR_LOCKOUT,
|
||||||
|
BiometricPrompt.ERROR_LOCKOUT_PERMANENT ->
|
||||||
|
KeystoreFailure.Lockout
|
||||||
|
BiometricPrompt.ERROR_NO_BIOMETRICS,
|
||||||
|
BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL,
|
||||||
|
BiometricPrompt.ERROR_HW_NOT_PRESENT ->
|
||||||
|
KeystoreFailure.UnsupportedProtection
|
||||||
|
else -> KeystoreFailure.Denied
|
||||||
|
}
|
||||||
|
)
|
||||||
|
request.done.countDown()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val prompt = BiometricPrompt(host, { handler.post(it) }, callback)
|
||||||
|
request.prompt = prompt
|
||||||
|
val information = BiometricPrompt.PromptInfo.Builder().setTitle(
|
||||||
|
context.getString(R.string.keystore_prompt_title)
|
||||||
|
)
|
||||||
|
if (authorization == KeystoreAuthorization.StrongBiometric) {
|
||||||
|
information.setAllowedAuthenticators(
|
||||||
|
BiometricManager.Authenticators.BIOMETRIC_STRONG
|
||||||
|
).setNegativeButtonText(context.getString(R.string.keystore_prompt_cancel))
|
||||||
|
} else {
|
||||||
|
if (Build.VERSION.SDK_INT < 30) fail(KeystoreFailure.UnsupportedProtection)
|
||||||
|
information.setAllowedAuthenticators(
|
||||||
|
BiometricManager.Authenticators.BIOMETRIC_STRONG or
|
||||||
|
BiometricManager.Authenticators.DEVICE_CREDENTIAL
|
||||||
|
)
|
||||||
|
}
|
||||||
|
prompt.authenticate(information.build(), BiometricPrompt.CryptoObject(cipher))
|
||||||
|
} catch (error: Exception) {
|
||||||
|
request.error.set(
|
||||||
|
if (error is KeystoreException) error.kind else KeystoreFailure.Unavailable
|
||||||
|
)
|
||||||
|
request.done.countDown()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (!request.done.await(180, TimeUnit.SECONDS)) fail(KeystoreFailure.Cancelled)
|
||||||
|
request.error.get()?.let { fail(it) }
|
||||||
|
if (request.authenticated.get() !== cipher ||
|
||||||
|
pending.get() !== request
|
||||||
|
) {
|
||||||
|
fail(KeystoreFailure.Cancelled)
|
||||||
|
}
|
||||||
|
} catch (_: InterruptedException) {
|
||||||
|
Thread.currentThread().interrupt()
|
||||||
|
fail(KeystoreFailure.Cancelled)
|
||||||
|
} finally {
|
||||||
|
pending.compareAndSet(request, null)
|
||||||
|
val succeeded = request.authenticated.getAndSet(null) === cipher
|
||||||
|
handler.post {
|
||||||
|
if (!succeeded) request.prompt?.cancelAuthentication()
|
||||||
|
request.prompt = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private fun fail(kind: KeystoreFailure): Nothing = throw KeystoreException(kind)
|
||||||
|
private inline fun <T> operation(block: () -> T): T = try {
|
||||||
|
block()
|
||||||
|
} catch (error: Exception) {
|
||||||
|
if (error is KeystoreException) throw error
|
||||||
|
var cause: Throwable? = error
|
||||||
|
var kind = KeystoreFailure.Unavailable
|
||||||
|
repeat(8) {
|
||||||
|
val osError = cause
|
||||||
|
if (kind == KeystoreFailure.Unavailable && Build.VERSION.SDK_INT >= 33 &&
|
||||||
|
osError is android.security.KeyStoreException
|
||||||
|
) {
|
||||||
|
kind = when (osError.numericErrorCode) {
|
||||||
|
android.security.KeyStoreException.ERROR_USER_AUTHENTICATION_REQUIRED ->
|
||||||
|
KeystoreFailure.Locked
|
||||||
|
android.security.KeyStoreException.ERROR_KEY_DOES_NOT_EXIST ->
|
||||||
|
KeystoreFailure.MissingKey
|
||||||
|
android.security.KeyStoreException.ERROR_KEY_CORRUPTED -> KeystoreFailure.Corrupted
|
||||||
|
android.security.KeyStoreException.ERROR_PERMISSION_DENIED -> KeystoreFailure.Denied
|
||||||
|
android.security.KeyStoreException.ERROR_UNIMPLEMENTED ->
|
||||||
|
KeystoreFailure.UnsupportedProtection
|
||||||
|
else -> kind
|
||||||
|
}
|
||||||
|
}
|
||||||
|
when {
|
||||||
|
cause is KeyPermanentlyInvalidatedException -> kind = KeystoreFailure.Invalidated
|
||||||
|
cause is UserNotAuthenticatedException -> kind = KeystoreFailure.Locked
|
||||||
|
cause is AEADBadTagException -> kind = KeystoreFailure.Corrupted
|
||||||
|
Build.VERSION.SDK_INT >= 28 && cause is StrongBoxUnavailableException ->
|
||||||
|
kind = KeystoreFailure.StrongboxUnavailable
|
||||||
|
}
|
||||||
|
cause = cause?.cause
|
||||||
|
}
|
||||||
|
throw KeystoreException(kind)
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<resources>
|
||||||
|
<string name="keystore_prompt_title">Unlock protected secret</string>
|
||||||
|
<string name="keystore_prompt_cancel">Cancel</string>
|
||||||
|
</resources>
|
||||||
+119
@@ -0,0 +1,119 @@
|
|||||||
|
package de.rfc1437.ironstorage.bridge
|
||||||
|
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobileAndroidAuthorization
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobileAndroidCiphertext
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobileAndroidDeviceState
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobileAndroidKeySpecification
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobileAndroidKeystore
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobileAndroidKeystoreException
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobilePrivateDirectories
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobilePrivateStorageErrorKind
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobilePrivateStorageFfiException
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobileSecretException
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobileSecretLocator
|
||||||
|
import de.rfc1437.ironstorage.bridge.generated.MobileSecretProtection
|
||||||
|
import org.junit.Assert.assertArrayEquals
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertThrows
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class KeystoreContractTest {
|
||||||
|
@Test fun rustOwnsRecordsPoliciesAndForeignSecretLifetime() {
|
||||||
|
val context = InstrumentationRegistry.getInstrumentation().targetContext
|
||||||
|
NativeRuntime(context).privateStorage(
|
||||||
|
MobilePrivateDirectories(
|
||||||
|
context.filesDir.canonicalPath,
|
||||||
|
context.noBackupFilesDir.canonicalPath,
|
||||||
|
context.cacheDir.canonicalPath
|
||||||
|
)
|
||||||
|
).use { runtime ->
|
||||||
|
val os = FixtureKeystore()
|
||||||
|
val backend = runtime.androidSecretBackend(os)
|
||||||
|
val locator = MobileSecretLocator.HttpsGitCredential("issue93-server", "fixture")
|
||||||
|
val protection = MobileSecretProtection.DEVICE_UNLOCKED
|
||||||
|
backend.unlock()
|
||||||
|
try {
|
||||||
|
backend.create(locator, protection, "public-token".toByteArray())
|
||||||
|
assertThrows(MobileSecretException.AlreadyExists::class.java) {
|
||||||
|
backend.create(locator, protection, "duplicate".toByteArray())
|
||||||
|
}
|
||||||
|
backend.replace(locator, protection, "replacement".toByteArray())
|
||||||
|
val clear = backend.retrieve(locator, protection)
|
||||||
|
try {
|
||||||
|
assertArrayEquals("replacement".toByteArray(), clear)
|
||||||
|
assertTrue(os.returned.all { it == 0.toByte() })
|
||||||
|
} finally {
|
||||||
|
clear.fill(0)
|
||||||
|
}
|
||||||
|
os.lockout = true
|
||||||
|
assertThrows(MobileSecretException.Lockout::class.java) {
|
||||||
|
backend.retrieve(locator, protection)
|
||||||
|
}
|
||||||
|
os.lockout = false
|
||||||
|
backend.lock()
|
||||||
|
assertThrows(MobileSecretException.Locked::class.java) {
|
||||||
|
backend.retrieve(locator, protection)
|
||||||
|
}
|
||||||
|
backend.unlock()
|
||||||
|
assertThrows(MobileSecretException.UnsupportedProtection::class.java) {
|
||||||
|
backend.create(
|
||||||
|
MobileSecretLocator.OpenPgpPassphrase("A".repeat(40)),
|
||||||
|
protection,
|
||||||
|
"public-passphrase".toByteArray()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
backend.delete(locator, protection)
|
||||||
|
}
|
||||||
|
assertTrue(os.keys.isEmpty())
|
||||||
|
os.corruptAliases = true
|
||||||
|
val error = assertThrows(MobilePrivateStorageFfiException.Failed::class.java) {
|
||||||
|
runtime.androidSecretBackend(os)
|
||||||
|
}
|
||||||
|
assertEquals(MobilePrivateStorageErrorKind.INVALID_SECURE_BINDING, error.kind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public fixture cipher only: production encryption is tested in the platform test APK.
|
||||||
|
private class FixtureKeystore : MobileAndroidKeystore {
|
||||||
|
val keys = mutableSetOf<String>()
|
||||||
|
var returned = byteArrayOf()
|
||||||
|
var lockout = false
|
||||||
|
var corruptAliases = false
|
||||||
|
override fun deviceState() = MobileAndroidDeviceState(37u, false, true, true, false)
|
||||||
|
override fun createKey(specification: MobileAndroidKeySpecification) {
|
||||||
|
assertEquals(MobileAndroidAuthorization.NONE, specification.authorization)
|
||||||
|
keys.add(specification.alias)
|
||||||
|
}
|
||||||
|
override fun encrypt(
|
||||||
|
alias: String,
|
||||||
|
authorization: MobileAndroidAuthorization,
|
||||||
|
aad: ByteArray,
|
||||||
|
value: ByteArray
|
||||||
|
): MobileAndroidCiphertext = try {
|
||||||
|
MobileAndroidCiphertext(ByteArray(12), value.copyOf(value.size + 16))
|
||||||
|
} finally {
|
||||||
|
value.fill(0)
|
||||||
|
}
|
||||||
|
override fun decrypt(
|
||||||
|
alias: String,
|
||||||
|
authorization: MobileAndroidAuthorization,
|
||||||
|
aad: ByteArray,
|
||||||
|
value: MobileAndroidCiphertext
|
||||||
|
): ByteArray {
|
||||||
|
if (lockout) throw MobileAndroidKeystoreException.Lockout()
|
||||||
|
returned = value.bytes.copyOf(value.bytes.size - 16)
|
||||||
|
return returned
|
||||||
|
}
|
||||||
|
override fun deleteKey(alias: String) {
|
||||||
|
keys.remove(alias)
|
||||||
|
}
|
||||||
|
override fun aliases(): List<String> {
|
||||||
|
if (corruptAliases) throw MobileAndroidKeystoreException.Corrupted()
|
||||||
|
return keys.toList()
|
||||||
|
}
|
||||||
|
override fun cancelPending() = Unit
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -608,6 +608,433 @@ fileprivate struct FfiConverterData: FfiConverterRustBuffer {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public protocol MobileAndroidKeystore: AnyObject, Sendable {
|
||||||
|
|
||||||
|
func deviceState() throws -> MobileAndroidDeviceState
|
||||||
|
|
||||||
|
func createKey(specification: MobileAndroidKeySpecification) throws
|
||||||
|
|
||||||
|
func encrypt(alias: String, authorization: MobileAndroidAuthorization, aad: Data, value: Data) throws -> MobileAndroidCiphertext
|
||||||
|
|
||||||
|
func decrypt(alias: String, authorization: MobileAndroidAuthorization, aad: Data, value: MobileAndroidCiphertext) throws -> Data
|
||||||
|
|
||||||
|
func deleteKey(alias: String) throws
|
||||||
|
|
||||||
|
func aliases() throws -> [String]
|
||||||
|
|
||||||
|
func cancelPending()
|
||||||
|
|
||||||
|
}
|
||||||
|
open class MobileAndroidKeystoreImpl: MobileAndroidKeystore, @unchecked Sendable {
|
||||||
|
fileprivate let handle: UInt64
|
||||||
|
|
||||||
|
/// Used to instantiate a [FFIObject] without an actual handle, for fakes in tests, mostly.
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
public struct NoHandle {
|
||||||
|
public init() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: We'd like this to be `private` but for Swifty reasons,
|
||||||
|
// we can't implement `FfiConverter` without making this `required` and we can't
|
||||||
|
// make it `required` without making it `public`.
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
required public init(unsafeFromHandle handle: UInt64) {
|
||||||
|
self.handle = handle
|
||||||
|
}
|
||||||
|
|
||||||
|
// This constructor can be used to instantiate a fake object.
|
||||||
|
// - Parameter noHandle: Placeholder value so we can have a constructor separate from the default empty one that may be implemented for classes extending [FFIObject].
|
||||||
|
//
|
||||||
|
// - Warning:
|
||||||
|
// Any object instantiated with this constructor cannot be passed to an actual Rust-backed object. Since there isn't a backing handle the FFI lower functions will crash.
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
public init(noHandle: NoHandle) {
|
||||||
|
self.handle = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
public func uniffiCloneHandle() -> UInt64 {
|
||||||
|
return try! rustCall { uniffi_ironstorage_mobile_fn_clone_mobileandroidkeystore(self.handle, $0) }
|
||||||
|
}
|
||||||
|
// No primary constructor declared for this class.
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
if handle == 0 {
|
||||||
|
// Mock objects have handle=0 don't try to free them
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try! rustCall { uniffi_ironstorage_mobile_fn_free_mobileandroidkeystore(handle, $0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
open func deviceState()throws -> MobileAndroidDeviceState {
|
||||||
|
return try FfiConverterTypeMobileAndroidDeviceState_lift(try rustCallWithError(FfiConverterTypeMobileAndroidKeystoreError_lift) {
|
||||||
|
uniffiCallStatus in
|
||||||
|
uniffi_ironstorage_mobile_fn_method_mobileandroidkeystore_device_state(
|
||||||
|
self.uniffiCloneHandle(),uniffiCallStatus
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
open func createKey(specification: MobileAndroidKeySpecification)throws {try rustCallWithError(FfiConverterTypeMobileAndroidKeystoreError_lift) {
|
||||||
|
uniffiCallStatus in
|
||||||
|
uniffi_ironstorage_mobile_fn_method_mobileandroidkeystore_create_key(
|
||||||
|
self.uniffiCloneHandle(),
|
||||||
|
FfiConverterTypeMobileAndroidKeySpecification_lower(specification),uniffiCallStatus
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open func encrypt(alias: String, authorization: MobileAndroidAuthorization, aad: Data, value: Data)throws -> MobileAndroidCiphertext {
|
||||||
|
return try FfiConverterTypeMobileAndroidCiphertext_lift(try rustCallWithError(FfiConverterTypeMobileAndroidKeystoreError_lift) {
|
||||||
|
uniffiCallStatus in
|
||||||
|
uniffi_ironstorage_mobile_fn_method_mobileandroidkeystore_encrypt(
|
||||||
|
self.uniffiCloneHandle(),
|
||||||
|
FfiConverterString.lower(alias),
|
||||||
|
FfiConverterTypeMobileAndroidAuthorization_lower(authorization),
|
||||||
|
FfiConverterData.lower(aad),
|
||||||
|
FfiConverterData.lower(value),uniffiCallStatus
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
open func decrypt(alias: String, authorization: MobileAndroidAuthorization, aad: Data, value: MobileAndroidCiphertext)throws -> Data {
|
||||||
|
return try FfiConverterData.lift(try rustCallWithError(FfiConverterTypeMobileAndroidKeystoreError_lift) {
|
||||||
|
uniffiCallStatus in
|
||||||
|
uniffi_ironstorage_mobile_fn_method_mobileandroidkeystore_decrypt(
|
||||||
|
self.uniffiCloneHandle(),
|
||||||
|
FfiConverterString.lower(alias),
|
||||||
|
FfiConverterTypeMobileAndroidAuthorization_lower(authorization),
|
||||||
|
FfiConverterData.lower(aad),
|
||||||
|
FfiConverterTypeMobileAndroidCiphertext_lower(value),uniffiCallStatus
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
open func deleteKey(alias: String)throws {try rustCallWithError(FfiConverterTypeMobileAndroidKeystoreError_lift) {
|
||||||
|
uniffiCallStatus in
|
||||||
|
uniffi_ironstorage_mobile_fn_method_mobileandroidkeystore_delete_key(
|
||||||
|
self.uniffiCloneHandle(),
|
||||||
|
FfiConverterString.lower(alias),uniffiCallStatus
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open func aliases()throws -> [String] {
|
||||||
|
return try FfiConverterSequenceString.lift(try rustCallWithError(FfiConverterTypeMobileAndroidKeystoreError_lift) {
|
||||||
|
uniffiCallStatus in
|
||||||
|
uniffi_ironstorage_mobile_fn_method_mobileandroidkeystore_aliases(
|
||||||
|
self.uniffiCloneHandle(),uniffiCallStatus
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
open func cancelPending() {try! rustCall() {
|
||||||
|
uniffiCallStatus in
|
||||||
|
uniffi_ironstorage_mobile_fn_method_mobileandroidkeystore_cancel_pending(
|
||||||
|
self.uniffiCloneHandle(),uniffiCallStatus
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Put the implementation in a struct so we don't pollute the top-level namespace
|
||||||
|
fileprivate struct UniffiCallbackInterfaceMobileAndroidKeystore {
|
||||||
|
|
||||||
|
// Create the VTable using a series of closures.
|
||||||
|
// Swift automatically converts these into C callback functions.
|
||||||
|
//
|
||||||
|
// Store the vtable directly.
|
||||||
|
static let vtable: UniffiVTableCallbackInterfaceMobileAndroidKeystore = UniffiVTableCallbackInterfaceMobileAndroidKeystore(
|
||||||
|
uniffiFree: { (uniffiHandle: UInt64) -> () in
|
||||||
|
do {
|
||||||
|
try FfiConverterTypeMobileAndroidKeystore.handleMap.remove(handle: uniffiHandle)
|
||||||
|
} catch {
|
||||||
|
print("Uniffi callback interface MobileAndroidKeystore: handle missing in uniffiFree")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
uniffiClone: { (uniffiHandle: UInt64) -> UInt64 in
|
||||||
|
do {
|
||||||
|
return try FfiConverterTypeMobileAndroidKeystore.handleMap.clone(handle: uniffiHandle)
|
||||||
|
} catch {
|
||||||
|
fatalError("Uniffi callback interface MobileAndroidKeystore: handle missing in uniffiClone")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
deviceState: { (
|
||||||
|
uniffiHandle: UInt64,
|
||||||
|
uniffiOutReturn: UnsafeMutablePointer<RustBuffer>,
|
||||||
|
uniffiCallStatus: UnsafeMutablePointer<RustCallStatus>
|
||||||
|
) in
|
||||||
|
let makeCall = {
|
||||||
|
() throws -> MobileAndroidDeviceState in
|
||||||
|
guard let uniffiObj = try? FfiConverterTypeMobileAndroidKeystore.handleMap.get(handle: uniffiHandle) else {
|
||||||
|
throw UniffiInternalError.unexpectedStaleHandle
|
||||||
|
}
|
||||||
|
return try uniffiObj.deviceState(
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let writeReturn = { uniffiOutReturn.pointee = FfiConverterTypeMobileAndroidDeviceState_lower($0) }
|
||||||
|
uniffiTraitInterfaceCallWithError(
|
||||||
|
callStatus: uniffiCallStatus,
|
||||||
|
makeCall: makeCall,
|
||||||
|
writeReturn: writeReturn,
|
||||||
|
lowerError: FfiConverterTypeMobileAndroidKeystoreError_lower
|
||||||
|
)
|
||||||
|
},
|
||||||
|
createKey: { (
|
||||||
|
uniffiHandle: UInt64,
|
||||||
|
specification: RustBuffer,
|
||||||
|
uniffiOutReturn: UnsafeMutableRawPointer,
|
||||||
|
uniffiCallStatus: UnsafeMutablePointer<RustCallStatus>
|
||||||
|
) in
|
||||||
|
let makeCall = {
|
||||||
|
() throws -> () in
|
||||||
|
guard let uniffiObj = try? FfiConverterTypeMobileAndroidKeystore.handleMap.get(handle: uniffiHandle) else {
|
||||||
|
throw UniffiInternalError.unexpectedStaleHandle
|
||||||
|
}
|
||||||
|
return try uniffiObj.createKey(
|
||||||
|
specification: try FfiConverterTypeMobileAndroidKeySpecification_lift(specification)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let writeReturn = { () }
|
||||||
|
uniffiTraitInterfaceCallWithError(
|
||||||
|
callStatus: uniffiCallStatus,
|
||||||
|
makeCall: makeCall,
|
||||||
|
writeReturn: writeReturn,
|
||||||
|
lowerError: FfiConverterTypeMobileAndroidKeystoreError_lower
|
||||||
|
)
|
||||||
|
},
|
||||||
|
encrypt: { (
|
||||||
|
uniffiHandle: UInt64,
|
||||||
|
alias: RustBuffer,
|
||||||
|
authorization: RustBuffer,
|
||||||
|
aad: RustBuffer,
|
||||||
|
value: RustBuffer,
|
||||||
|
uniffiOutReturn: UnsafeMutablePointer<RustBuffer>,
|
||||||
|
uniffiCallStatus: UnsafeMutablePointer<RustCallStatus>
|
||||||
|
) in
|
||||||
|
let makeCall = {
|
||||||
|
() throws -> MobileAndroidCiphertext in
|
||||||
|
guard let uniffiObj = try? FfiConverterTypeMobileAndroidKeystore.handleMap.get(handle: uniffiHandle) else {
|
||||||
|
throw UniffiInternalError.unexpectedStaleHandle
|
||||||
|
}
|
||||||
|
return try uniffiObj.encrypt(
|
||||||
|
alias: try FfiConverterString.lift(alias),
|
||||||
|
authorization: try FfiConverterTypeMobileAndroidAuthorization_lift(authorization),
|
||||||
|
aad: try FfiConverterData.lift(aad),
|
||||||
|
value: try FfiConverterData.lift(value)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let writeReturn = { uniffiOutReturn.pointee = FfiConverterTypeMobileAndroidCiphertext_lower($0) }
|
||||||
|
uniffiTraitInterfaceCallWithError(
|
||||||
|
callStatus: uniffiCallStatus,
|
||||||
|
makeCall: makeCall,
|
||||||
|
writeReturn: writeReturn,
|
||||||
|
lowerError: FfiConverterTypeMobileAndroidKeystoreError_lower
|
||||||
|
)
|
||||||
|
},
|
||||||
|
decrypt: { (
|
||||||
|
uniffiHandle: UInt64,
|
||||||
|
alias: RustBuffer,
|
||||||
|
authorization: RustBuffer,
|
||||||
|
aad: RustBuffer,
|
||||||
|
value: RustBuffer,
|
||||||
|
uniffiOutReturn: UnsafeMutablePointer<RustBuffer>,
|
||||||
|
uniffiCallStatus: UnsafeMutablePointer<RustCallStatus>
|
||||||
|
) in
|
||||||
|
let makeCall = {
|
||||||
|
() throws -> Data in
|
||||||
|
guard let uniffiObj = try? FfiConverterTypeMobileAndroidKeystore.handleMap.get(handle: uniffiHandle) else {
|
||||||
|
throw UniffiInternalError.unexpectedStaleHandle
|
||||||
|
}
|
||||||
|
return try uniffiObj.decrypt(
|
||||||
|
alias: try FfiConverterString.lift(alias),
|
||||||
|
authorization: try FfiConverterTypeMobileAndroidAuthorization_lift(authorization),
|
||||||
|
aad: try FfiConverterData.lift(aad),
|
||||||
|
value: try FfiConverterTypeMobileAndroidCiphertext_lift(value)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let writeReturn = { uniffiOutReturn.pointee = FfiConverterData.lower($0) }
|
||||||
|
uniffiTraitInterfaceCallWithError(
|
||||||
|
callStatus: uniffiCallStatus,
|
||||||
|
makeCall: makeCall,
|
||||||
|
writeReturn: writeReturn,
|
||||||
|
lowerError: FfiConverterTypeMobileAndroidKeystoreError_lower
|
||||||
|
)
|
||||||
|
},
|
||||||
|
deleteKey: { (
|
||||||
|
uniffiHandle: UInt64,
|
||||||
|
alias: RustBuffer,
|
||||||
|
uniffiOutReturn: UnsafeMutableRawPointer,
|
||||||
|
uniffiCallStatus: UnsafeMutablePointer<RustCallStatus>
|
||||||
|
) in
|
||||||
|
let makeCall = {
|
||||||
|
() throws -> () in
|
||||||
|
guard let uniffiObj = try? FfiConverterTypeMobileAndroidKeystore.handleMap.get(handle: uniffiHandle) else {
|
||||||
|
throw UniffiInternalError.unexpectedStaleHandle
|
||||||
|
}
|
||||||
|
return try uniffiObj.deleteKey(
|
||||||
|
alias: try FfiConverterString.lift(alias)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let writeReturn = { () }
|
||||||
|
uniffiTraitInterfaceCallWithError(
|
||||||
|
callStatus: uniffiCallStatus,
|
||||||
|
makeCall: makeCall,
|
||||||
|
writeReturn: writeReturn,
|
||||||
|
lowerError: FfiConverterTypeMobileAndroidKeystoreError_lower
|
||||||
|
)
|
||||||
|
},
|
||||||
|
aliases: { (
|
||||||
|
uniffiHandle: UInt64,
|
||||||
|
uniffiOutReturn: UnsafeMutablePointer<RustBuffer>,
|
||||||
|
uniffiCallStatus: UnsafeMutablePointer<RustCallStatus>
|
||||||
|
) in
|
||||||
|
let makeCall = {
|
||||||
|
() throws -> [String] in
|
||||||
|
guard let uniffiObj = try? FfiConverterTypeMobileAndroidKeystore.handleMap.get(handle: uniffiHandle) else {
|
||||||
|
throw UniffiInternalError.unexpectedStaleHandle
|
||||||
|
}
|
||||||
|
return try uniffiObj.aliases(
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let writeReturn = { uniffiOutReturn.pointee = FfiConverterSequenceString.lower($0) }
|
||||||
|
uniffiTraitInterfaceCallWithError(
|
||||||
|
callStatus: uniffiCallStatus,
|
||||||
|
makeCall: makeCall,
|
||||||
|
writeReturn: writeReturn,
|
||||||
|
lowerError: FfiConverterTypeMobileAndroidKeystoreError_lower
|
||||||
|
)
|
||||||
|
},
|
||||||
|
cancelPending: { (
|
||||||
|
uniffiHandle: UInt64,
|
||||||
|
uniffiOutReturn: UnsafeMutableRawPointer,
|
||||||
|
uniffiCallStatus: UnsafeMutablePointer<RustCallStatus>
|
||||||
|
) in
|
||||||
|
let makeCall = {
|
||||||
|
() throws -> () in
|
||||||
|
guard let uniffiObj = try? FfiConverterTypeMobileAndroidKeystore.handleMap.get(handle: uniffiHandle) else {
|
||||||
|
throw UniffiInternalError.unexpectedStaleHandle
|
||||||
|
}
|
||||||
|
return uniffiObj.cancelPending(
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let writeReturn = { () }
|
||||||
|
uniffiTraitInterfaceCall(
|
||||||
|
callStatus: uniffiCallStatus,
|
||||||
|
makeCall: makeCall,
|
||||||
|
writeReturn: writeReturn
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Rust stores this pointer for future callback invocations, so it must live
|
||||||
|
// for the process lifetime (not just for the init function call).
|
||||||
|
//
|
||||||
|
// `nonisolated(unsafe)` is needed under Swift 6 strict concurrency.
|
||||||
|
// This is safe because the pointee is initialized once during static init
|
||||||
|
// and never mutated by either side of the FFI. Its fields are C function pointers.
|
||||||
|
nonisolated(unsafe) static let vtablePtr: UnsafePointer<UniffiVTableCallbackInterfaceMobileAndroidKeystore> = {
|
||||||
|
let ptr = UnsafeMutablePointer<UniffiVTableCallbackInterfaceMobileAndroidKeystore>.allocate(capacity: 1)
|
||||||
|
ptr.initialize(to: vtable)
|
||||||
|
return UnsafePointer(ptr)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func uniffiCallbackInitMobileAndroidKeystore() {
|
||||||
|
uniffi_ironstorage_mobile_fn_init_callback_vtable_mobileandroidkeystore(UniffiCallbackInterfaceMobileAndroidKeystore.vtablePtr)
|
||||||
|
}
|
||||||
|
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
public struct FfiConverterTypeMobileAndroidKeystore: FfiConverter {
|
||||||
|
fileprivate static let handleMap = UniffiHandleMap<MobileAndroidKeystore>()
|
||||||
|
|
||||||
|
typealias FfiType = UInt64
|
||||||
|
typealias SwiftType = MobileAndroidKeystore
|
||||||
|
|
||||||
|
public static func lift(_ handle: UInt64) throws -> MobileAndroidKeystore {
|
||||||
|
if ((handle & 1) == 0) {
|
||||||
|
// Rust-generated handle, construct a new class that uses the handle to implement the
|
||||||
|
// interface
|
||||||
|
return MobileAndroidKeystoreImpl(unsafeFromHandle: handle)
|
||||||
|
} else {
|
||||||
|
// Swift-generated handle, get the object from the handle map
|
||||||
|
return try handleMap.remove(handle: handle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func lower(_ value: MobileAndroidKeystore) -> UInt64 {
|
||||||
|
if let rustImpl = value as? MobileAndroidKeystoreImpl {
|
||||||
|
// Rust-implemented object. Clone the handle and return it
|
||||||
|
return rustImpl.uniffiCloneHandle()
|
||||||
|
} else {
|
||||||
|
// Swift object, generate a new vtable handle and return that.
|
||||||
|
return handleMap.insert(obj: value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> MobileAndroidKeystore {
|
||||||
|
let handle: UInt64 = try readInt(&buf)
|
||||||
|
return try lift(handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func write(_ value: MobileAndroidKeystore, into buf: inout [UInt8]) {
|
||||||
|
writeInt(&buf, lower(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
public func FfiConverterTypeMobileAndroidKeystore_lift(_ handle: UInt64) throws -> MobileAndroidKeystore {
|
||||||
|
return try FfiConverterTypeMobileAndroidKeystore.lift(handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
public func FfiConverterTypeMobileAndroidKeystore_lower(_ value: MobileAndroidKeystore) -> UInt64 {
|
||||||
|
return FfiConverterTypeMobileAndroidKeystore.lower(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public protocol MobileAuthenticationProtocol: AnyObject, Sendable {
|
public protocol MobileAuthenticationProtocol: AnyObject, Sendable {
|
||||||
|
|
||||||
func acknowledgeWatchSnapshot(receipt: Data) throws -> MobileWatchSnapshotStatus
|
func acknowledgeWatchSnapshot(receipt: Data) throws -> MobileWatchSnapshotStatus
|
||||||
@@ -2528,6 +2955,8 @@ public protocol MobilePrivateRuntimeProtocol: AnyObject, Sendable {
|
|||||||
|
|
||||||
func activate() throws
|
func activate() throws
|
||||||
|
|
||||||
|
func androidSecretBackend(keystore: MobileAndroidKeystore) throws -> MobileSecretBackend
|
||||||
|
|
||||||
func authentication(backend: MobileSecretBackend, clock: MobileClock) throws -> MobileAuthentication
|
func authentication(backend: MobileSecretBackend, clock: MobileClock) throws -> MobileAuthentication
|
||||||
|
|
||||||
func clearDisposableCache() throws
|
func clearDisposableCache() throws
|
||||||
@@ -2602,6 +3031,16 @@ open func activate()throws {try rustCallWithError(FfiConverterTypeMobilePrivat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open func androidSecretBackend(keystore: MobileAndroidKeystore)throws -> MobileSecretBackend {
|
||||||
|
return try FfiConverterTypeMobileSecretBackend_lift(try rustCallWithError(FfiConverterTypeMobilePrivateStorageFfiError_lift) {
|
||||||
|
uniffiCallStatus in
|
||||||
|
uniffi_ironstorage_mobile_fn_method_mobileprivateruntime_android_secret_backend(
|
||||||
|
self.uniffiCloneHandle(),
|
||||||
|
FfiConverterTypeMobileAndroidKeystore_lower(keystore),uniffiCallStatus
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
open func authentication(backend: MobileSecretBackend, clock: MobileClock)throws -> MobileAuthentication {
|
open func authentication(backend: MobileSecretBackend, clock: MobileClock)throws -> MobileAuthentication {
|
||||||
return try FfiConverterTypeMobileAuthentication_lift(try rustCallWithError(FfiConverterTypeMobileAuthenticationFfiError_lift) {
|
return try FfiConverterTypeMobileAuthentication_lift(try rustCallWithError(FfiConverterTypeMobileAuthenticationFfiError_lift) {
|
||||||
uniffiCallStatus in
|
uniffiCallStatus in
|
||||||
@@ -3230,6 +3669,192 @@ public func FfiConverterTypeMobileTotpOperation_lower(_ value: MobileTotpOperati
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public struct MobileAndroidCiphertext: Equatable, Hashable {
|
||||||
|
public var nonce: Data
|
||||||
|
public var bytes: Data
|
||||||
|
|
||||||
|
// Default memberwise initializers are never public by default, so we
|
||||||
|
// declare one manually.
|
||||||
|
public init(nonce: Data, bytes: Data) {
|
||||||
|
self.nonce = nonce
|
||||||
|
self.bytes = bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#if compiler(>=6)
|
||||||
|
extension MobileAndroidCiphertext: Sendable {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
public struct FfiConverterTypeMobileAndroidCiphertext: FfiConverterRustBuffer {
|
||||||
|
public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> MobileAndroidCiphertext {
|
||||||
|
return
|
||||||
|
try MobileAndroidCiphertext(
|
||||||
|
nonce: FfiConverterData.read(from: &buf),
|
||||||
|
bytes: FfiConverterData.read(from: &buf)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func write(_ value: MobileAndroidCiphertext, into buf: inout [UInt8]) {
|
||||||
|
FfiConverterData.write(value.nonce, into: &buf)
|
||||||
|
FfiConverterData.write(value.bytes, into: &buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
public func FfiConverterTypeMobileAndroidCiphertext_lift(_ buf: RustBuffer) throws -> MobileAndroidCiphertext {
|
||||||
|
return try FfiConverterTypeMobileAndroidCiphertext.lift(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
public func FfiConverterTypeMobileAndroidCiphertext_lower(_ value: MobileAndroidCiphertext) -> RustBuffer {
|
||||||
|
return FfiConverterTypeMobileAndroidCiphertext.lower(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public struct MobileAndroidDeviceState: Equatable, Hashable {
|
||||||
|
public var api: UInt32
|
||||||
|
public var locked: Bool
|
||||||
|
public var secure: Bool
|
||||||
|
public var strongBiometric: Bool
|
||||||
|
public var strongbox: Bool
|
||||||
|
|
||||||
|
// Default memberwise initializers are never public by default, so we
|
||||||
|
// declare one manually.
|
||||||
|
public init(api: UInt32, locked: Bool, secure: Bool, strongBiometric: Bool, strongbox: Bool) {
|
||||||
|
self.api = api
|
||||||
|
self.locked = locked
|
||||||
|
self.secure = secure
|
||||||
|
self.strongBiometric = strongBiometric
|
||||||
|
self.strongbox = strongbox
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#if compiler(>=6)
|
||||||
|
extension MobileAndroidDeviceState: Sendable {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
public struct FfiConverterTypeMobileAndroidDeviceState: FfiConverterRustBuffer {
|
||||||
|
public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> MobileAndroidDeviceState {
|
||||||
|
return
|
||||||
|
try MobileAndroidDeviceState(
|
||||||
|
api: FfiConverterUInt32.read(from: &buf),
|
||||||
|
locked: FfiConverterBool.read(from: &buf),
|
||||||
|
secure: FfiConverterBool.read(from: &buf),
|
||||||
|
strongBiometric: FfiConverterBool.read(from: &buf),
|
||||||
|
strongbox: FfiConverterBool.read(from: &buf)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func write(_ value: MobileAndroidDeviceState, into buf: inout [UInt8]) {
|
||||||
|
FfiConverterUInt32.write(value.api, into: &buf)
|
||||||
|
FfiConverterBool.write(value.locked, into: &buf)
|
||||||
|
FfiConverterBool.write(value.secure, into: &buf)
|
||||||
|
FfiConverterBool.write(value.strongBiometric, into: &buf)
|
||||||
|
FfiConverterBool.write(value.strongbox, into: &buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
public func FfiConverterTypeMobileAndroidDeviceState_lift(_ buf: RustBuffer) throws -> MobileAndroidDeviceState {
|
||||||
|
return try FfiConverterTypeMobileAndroidDeviceState.lift(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
public func FfiConverterTypeMobileAndroidDeviceState_lower(_ value: MobileAndroidDeviceState) -> RustBuffer {
|
||||||
|
return FfiConverterTypeMobileAndroidDeviceState.lower(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public struct MobileAndroidKeySpecification: Equatable, Hashable {
|
||||||
|
public var alias: String
|
||||||
|
public var authorization: MobileAndroidAuthorization
|
||||||
|
public var unlockedDevice: Bool
|
||||||
|
public var invalidateOnEnrollment: Bool
|
||||||
|
public var strongbox: Bool
|
||||||
|
|
||||||
|
// Default memberwise initializers are never public by default, so we
|
||||||
|
// declare one manually.
|
||||||
|
public init(alias: String, authorization: MobileAndroidAuthorization, unlockedDevice: Bool, invalidateOnEnrollment: Bool, strongbox: Bool) {
|
||||||
|
self.alias = alias
|
||||||
|
self.authorization = authorization
|
||||||
|
self.unlockedDevice = unlockedDevice
|
||||||
|
self.invalidateOnEnrollment = invalidateOnEnrollment
|
||||||
|
self.strongbox = strongbox
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#if compiler(>=6)
|
||||||
|
extension MobileAndroidKeySpecification: Sendable {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
public struct FfiConverterTypeMobileAndroidKeySpecification: FfiConverterRustBuffer {
|
||||||
|
public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> MobileAndroidKeySpecification {
|
||||||
|
return
|
||||||
|
try MobileAndroidKeySpecification(
|
||||||
|
alias: FfiConverterString.read(from: &buf),
|
||||||
|
authorization: FfiConverterTypeMobileAndroidAuthorization.read(from: &buf),
|
||||||
|
unlockedDevice: FfiConverterBool.read(from: &buf),
|
||||||
|
invalidateOnEnrollment: FfiConverterBool.read(from: &buf),
|
||||||
|
strongbox: FfiConverterBool.read(from: &buf)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func write(_ value: MobileAndroidKeySpecification, into buf: inout [UInt8]) {
|
||||||
|
FfiConverterString.write(value.alias, into: &buf)
|
||||||
|
FfiConverterTypeMobileAndroidAuthorization.write(value.authorization, into: &buf)
|
||||||
|
FfiConverterBool.write(value.unlockedDevice, into: &buf)
|
||||||
|
FfiConverterBool.write(value.invalidateOnEnrollment, into: &buf)
|
||||||
|
FfiConverterBool.write(value.strongbox, into: &buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
public func FfiConverterTypeMobileAndroidKeySpecification_lift(_ buf: RustBuffer) throws -> MobileAndroidKeySpecification {
|
||||||
|
return try FfiConverterTypeMobileAndroidKeySpecification.lift(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
public func FfiConverterTypeMobileAndroidKeySpecification_lower(_ value: MobileAndroidKeySpecification) -> RustBuffer {
|
||||||
|
return FfiConverterTypeMobileAndroidKeySpecification.lower(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public struct MobileAuthenticationState: Equatable, Hashable {
|
public struct MobileAuthenticationState: Equatable, Hashable {
|
||||||
public var unlocked: Bool
|
public var unlocked: Bool
|
||||||
public var biometricUnlockEnabled: Bool
|
public var biometricUnlockEnabled: Bool
|
||||||
@@ -6359,6 +6984,210 @@ public func FfiConverterTypeMobileWatchSnapshotTransfer_lower(_ value: MobileWat
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public enum MobileAndroidAuthorization: Equatable, Hashable {
|
||||||
|
|
||||||
|
case none
|
||||||
|
case strongBiometric
|
||||||
|
case userPresence
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#if compiler(>=6)
|
||||||
|
extension MobileAndroidAuthorization: Sendable {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
public struct FfiConverterTypeMobileAndroidAuthorization: FfiConverterRustBuffer {
|
||||||
|
typealias SwiftType = MobileAndroidAuthorization
|
||||||
|
|
||||||
|
public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> MobileAndroidAuthorization {
|
||||||
|
let variant: Int32 = try readInt(&buf)
|
||||||
|
switch variant {
|
||||||
|
|
||||||
|
case 1: return .none
|
||||||
|
|
||||||
|
case 2: return .strongBiometric
|
||||||
|
|
||||||
|
case 3: return .userPresence
|
||||||
|
|
||||||
|
default: throw UniffiInternalError.unexpectedEnumCase
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func write(_ value: MobileAndroidAuthorization, into buf: inout [UInt8]) {
|
||||||
|
switch value {
|
||||||
|
|
||||||
|
|
||||||
|
case .none:
|
||||||
|
writeInt(&buf, Int32(1))
|
||||||
|
|
||||||
|
|
||||||
|
case .strongBiometric:
|
||||||
|
writeInt(&buf, Int32(2))
|
||||||
|
|
||||||
|
|
||||||
|
case .userPresence:
|
||||||
|
writeInt(&buf, Int32(3))
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
public func FfiConverterTypeMobileAndroidAuthorization_lift(_ buf: RustBuffer) throws -> MobileAndroidAuthorization {
|
||||||
|
return try FfiConverterTypeMobileAndroidAuthorization.lift(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
public func FfiConverterTypeMobileAndroidAuthorization_lower(_ value: MobileAndroidAuthorization) -> RustBuffer {
|
||||||
|
return FfiConverterTypeMobileAndroidAuthorization.lower(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public
|
||||||
|
enum MobileAndroidKeystoreError: Swift.Error, Equatable, Hashable, Foundation.LocalizedError {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
case MissingKey
|
||||||
|
case Invalidated
|
||||||
|
case Lockout
|
||||||
|
case Locked
|
||||||
|
case Denied
|
||||||
|
case Cancelled
|
||||||
|
case Corrupted
|
||||||
|
case UnsupportedProtection
|
||||||
|
case StrongboxUnavailable
|
||||||
|
case AlreadyExists
|
||||||
|
case Unavailable
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public var errorDescription: String? {
|
||||||
|
String(reflecting: self)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#if compiler(>=6)
|
||||||
|
extension MobileAndroidKeystoreError: Sendable {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
public struct FfiConverterTypeMobileAndroidKeystoreError: FfiConverterRustBuffer {
|
||||||
|
typealias SwiftType = MobileAndroidKeystoreError
|
||||||
|
|
||||||
|
public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> MobileAndroidKeystoreError {
|
||||||
|
let variant: Int32 = try readInt(&buf)
|
||||||
|
switch variant {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
case 1: return .MissingKey
|
||||||
|
case 2: return .Invalidated
|
||||||
|
case 3: return .Lockout
|
||||||
|
case 4: return .Locked
|
||||||
|
case 5: return .Denied
|
||||||
|
case 6: return .Cancelled
|
||||||
|
case 7: return .Corrupted
|
||||||
|
case 8: return .UnsupportedProtection
|
||||||
|
case 9: return .StrongboxUnavailable
|
||||||
|
case 10: return .AlreadyExists
|
||||||
|
case 11: return .Unavailable
|
||||||
|
|
||||||
|
default: throw UniffiInternalError.unexpectedEnumCase
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func write(_ value: MobileAndroidKeystoreError, into buf: inout [UInt8]) {
|
||||||
|
switch value {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
case .MissingKey:
|
||||||
|
writeInt(&buf, Int32(1))
|
||||||
|
|
||||||
|
|
||||||
|
case .Invalidated:
|
||||||
|
writeInt(&buf, Int32(2))
|
||||||
|
|
||||||
|
|
||||||
|
case .Lockout:
|
||||||
|
writeInt(&buf, Int32(3))
|
||||||
|
|
||||||
|
|
||||||
|
case .Locked:
|
||||||
|
writeInt(&buf, Int32(4))
|
||||||
|
|
||||||
|
|
||||||
|
case .Denied:
|
||||||
|
writeInt(&buf, Int32(5))
|
||||||
|
|
||||||
|
|
||||||
|
case .Cancelled:
|
||||||
|
writeInt(&buf, Int32(6))
|
||||||
|
|
||||||
|
|
||||||
|
case .Corrupted:
|
||||||
|
writeInt(&buf, Int32(7))
|
||||||
|
|
||||||
|
|
||||||
|
case .UnsupportedProtection:
|
||||||
|
writeInt(&buf, Int32(8))
|
||||||
|
|
||||||
|
|
||||||
|
case .StrongboxUnavailable:
|
||||||
|
writeInt(&buf, Int32(9))
|
||||||
|
|
||||||
|
|
||||||
|
case .AlreadyExists:
|
||||||
|
writeInt(&buf, Int32(10))
|
||||||
|
|
||||||
|
|
||||||
|
case .Unavailable:
|
||||||
|
writeInt(&buf, Int32(11))
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
public func FfiConverterTypeMobileAndroidKeystoreError_lift(_ buf: RustBuffer) throws -> MobileAndroidKeystoreError {
|
||||||
|
return try FfiConverterTypeMobileAndroidKeystoreError.lift(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
#if swift(>=5.8)
|
||||||
|
@_documentation(visibility: private)
|
||||||
|
#endif
|
||||||
|
public func FfiConverterTypeMobileAndroidKeystoreError_lower(_ value: MobileAndroidKeystoreError) -> RustBuffer {
|
||||||
|
return FfiConverterTypeMobileAndroidKeystoreError.lower(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public enum MobileAppearance: Equatable, Hashable {
|
public enum MobileAppearance: Equatable, Hashable {
|
||||||
|
|
||||||
case system
|
case system
|
||||||
@@ -9165,6 +9994,9 @@ enum MobileSecretError: Swift.Error, Equatable, Hashable, Foundation.LocalizedEr
|
|||||||
case Corrupted
|
case Corrupted
|
||||||
case UnsupportedProtection
|
case UnsupportedProtection
|
||||||
case Unavailable
|
case Unavailable
|
||||||
|
case DeviceKeyMissing
|
||||||
|
case Invalidated
|
||||||
|
case Lockout
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -9202,6 +10034,9 @@ public struct FfiConverterTypeMobileSecretError: FfiConverterRustBuffer {
|
|||||||
case 6: return .Corrupted
|
case 6: return .Corrupted
|
||||||
case 7: return .UnsupportedProtection
|
case 7: return .UnsupportedProtection
|
||||||
case 8: return .Unavailable
|
case 8: return .Unavailable
|
||||||
|
case 9: return .DeviceKeyMissing
|
||||||
|
case 10: return .Invalidated
|
||||||
|
case 11: return .Lockout
|
||||||
|
|
||||||
default: throw UniffiInternalError.unexpectedEnumCase
|
default: throw UniffiInternalError.unexpectedEnumCase
|
||||||
}
|
}
|
||||||
@@ -9245,6 +10080,18 @@ public struct FfiConverterTypeMobileSecretError: FfiConverterRustBuffer {
|
|||||||
case .Unavailable:
|
case .Unavailable:
|
||||||
writeInt(&buf, Int32(8))
|
writeInt(&buf, Int32(8))
|
||||||
|
|
||||||
|
|
||||||
|
case .DeviceKeyMissing:
|
||||||
|
writeInt(&buf, Int32(9))
|
||||||
|
|
||||||
|
|
||||||
|
case .Invalidated:
|
||||||
|
writeInt(&buf, Int32(10))
|
||||||
|
|
||||||
|
|
||||||
|
case .Lockout:
|
||||||
|
writeInt(&buf, Int32(11))
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10974,6 +11821,27 @@ private let initializationResult: InitializationResult = {
|
|||||||
if (uniffi_ironstorage_mobile_checksum_method_mobiletotpoperation_progress() != 30340) {
|
if (uniffi_ironstorage_mobile_checksum_method_mobiletotpoperation_progress() != 30340) {
|
||||||
return InitializationResult.apiChecksumMismatch
|
return InitializationResult.apiChecksumMismatch
|
||||||
}
|
}
|
||||||
|
if (uniffi_ironstorage_mobile_checksum_method_mobileandroidkeystore_device_state() != 19346) {
|
||||||
|
return InitializationResult.apiChecksumMismatch
|
||||||
|
}
|
||||||
|
if (uniffi_ironstorage_mobile_checksum_method_mobileandroidkeystore_create_key() != 7937) {
|
||||||
|
return InitializationResult.apiChecksumMismatch
|
||||||
|
}
|
||||||
|
if (uniffi_ironstorage_mobile_checksum_method_mobileandroidkeystore_encrypt() != 65449) {
|
||||||
|
return InitializationResult.apiChecksumMismatch
|
||||||
|
}
|
||||||
|
if (uniffi_ironstorage_mobile_checksum_method_mobileandroidkeystore_decrypt() != 39727) {
|
||||||
|
return InitializationResult.apiChecksumMismatch
|
||||||
|
}
|
||||||
|
if (uniffi_ironstorage_mobile_checksum_method_mobileandroidkeystore_delete_key() != 20162) {
|
||||||
|
return InitializationResult.apiChecksumMismatch
|
||||||
|
}
|
||||||
|
if (uniffi_ironstorage_mobile_checksum_method_mobileandroidkeystore_aliases() != 16519) {
|
||||||
|
return InitializationResult.apiChecksumMismatch
|
||||||
|
}
|
||||||
|
if (uniffi_ironstorage_mobile_checksum_method_mobileandroidkeystore_cancel_pending() != 39774) {
|
||||||
|
return InitializationResult.apiChecksumMismatch
|
||||||
|
}
|
||||||
if (uniffi_ironstorage_mobile_checksum_method_mobileclipboard_read() != 47092) {
|
if (uniffi_ironstorage_mobile_checksum_method_mobileclipboard_read() != 47092) {
|
||||||
return InitializationResult.apiChecksumMismatch
|
return InitializationResult.apiChecksumMismatch
|
||||||
}
|
}
|
||||||
@@ -11010,6 +11878,9 @@ private let initializationResult: InitializationResult = {
|
|||||||
if (uniffi_ironstorage_mobile_checksum_method_mobileprivateruntime_activate() != 64835) {
|
if (uniffi_ironstorage_mobile_checksum_method_mobileprivateruntime_activate() != 64835) {
|
||||||
return InitializationResult.apiChecksumMismatch
|
return InitializationResult.apiChecksumMismatch
|
||||||
}
|
}
|
||||||
|
if (uniffi_ironstorage_mobile_checksum_method_mobileprivateruntime_android_secret_backend() != 24373) {
|
||||||
|
return InitializationResult.apiChecksumMismatch
|
||||||
|
}
|
||||||
if (uniffi_ironstorage_mobile_checksum_method_mobileprivateruntime_authentication() != 21237) {
|
if (uniffi_ironstorage_mobile_checksum_method_mobileprivateruntime_authentication() != 21237) {
|
||||||
return InitializationResult.apiChecksumMismatch
|
return InitializationResult.apiChecksumMismatch
|
||||||
}
|
}
|
||||||
@@ -11029,6 +11900,7 @@ private let initializationResult: InitializationResult = {
|
|||||||
return InitializationResult.apiChecksumMismatch
|
return InitializationResult.apiChecksumMismatch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uniffiCallbackInitMobileAndroidKeystore()
|
||||||
uniffiCallbackInitMobileClipboard()
|
uniffiCallbackInitMobileClipboard()
|
||||||
uniffiCallbackInitMobileClock()
|
uniffiCallbackInitMobileClock()
|
||||||
uniffiCallbackInitMobileSecretBackend()
|
uniffiCallbackInitMobileSecretBackend()
|
||||||
@@ -11050,6 +11922,22 @@ public func uniffiEnsureIronstorageMobileInitialized() {
|
|||||||
|
|
||||||
// swiftlint:enable all
|
// swiftlint:enable all
|
||||||
// IronStorage diagnostic redaction; wire values and checksums remain generated.
|
// IronStorage diagnostic redaction; wire values and checksums remain generated.
|
||||||
|
extension MobileAndroidCiphertext: CustomStringConvertible, CustomDebugStringConvertible {
|
||||||
|
public var description: String { "MobileAndroidCiphertext([REDACTED])" }
|
||||||
|
public var debugDescription: String { description }
|
||||||
|
}
|
||||||
|
extension MobileAndroidDeviceState: CustomStringConvertible, CustomDebugStringConvertible {
|
||||||
|
public var description: String { "MobileAndroidDeviceState([REDACTED])" }
|
||||||
|
public var debugDescription: String { description }
|
||||||
|
}
|
||||||
|
extension MobileAndroidKeySpecification: CustomStringConvertible, CustomDebugStringConvertible {
|
||||||
|
public var description: String { "MobileAndroidKeySpecification([REDACTED])" }
|
||||||
|
public var debugDescription: String { description }
|
||||||
|
}
|
||||||
|
extension MobileAndroidKeystoreError: CustomStringConvertible, CustomDebugStringConvertible {
|
||||||
|
public var description: String { "MobileAndroidKeystoreError([REDACTED])" }
|
||||||
|
public var debugDescription: String { description }
|
||||||
|
}
|
||||||
extension MobileAuthenticationFfiError: CustomStringConvertible, CustomDebugStringConvertible {
|
extension MobileAuthenticationFfiError: CustomStringConvertible, CustomDebugStringConvertible {
|
||||||
public var description: String { "MobileAuthenticationFfiError([REDACTED])" }
|
public var description: String { "MobileAuthenticationFfiError([REDACTED])" }
|
||||||
public var debugDescription: String { description }
|
public var debugDescription: String { description }
|
||||||
|
|||||||
@@ -242,6 +242,55 @@ typedef struct UniffiForeignFutureResultVoid {
|
|||||||
typedef void (*UniffiForeignFutureCompleteVoid)(uint64_t, UniffiForeignFutureResultVoid
|
typedef void (*UniffiForeignFutureCompleteVoid)(uint64_t, UniffiForeignFutureResultVoid
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_MOBILE_ANDROID_KEYSTORE_METHOD0
|
||||||
|
#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_MOBILE_ANDROID_KEYSTORE_METHOD0
|
||||||
|
typedef void (*UniffiCallbackInterfaceMobileAndroidKeystoreMethod0)(uint64_t, RustBuffer* _Nonnull,
|
||||||
|
RustCallStatus *_Nonnull uniffiCallStatus
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_MOBILE_ANDROID_KEYSTORE_METHOD1
|
||||||
|
#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_MOBILE_ANDROID_KEYSTORE_METHOD1
|
||||||
|
typedef void (*UniffiCallbackInterfaceMobileAndroidKeystoreMethod1)(uint64_t, RustBuffer, void* _Nonnull,
|
||||||
|
RustCallStatus *_Nonnull uniffiCallStatus
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_MOBILE_ANDROID_KEYSTORE_METHOD2
|
||||||
|
#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_MOBILE_ANDROID_KEYSTORE_METHOD2
|
||||||
|
typedef void (*UniffiCallbackInterfaceMobileAndroidKeystoreMethod2)(uint64_t, RustBuffer, RustBuffer, RustBuffer, RustBuffer, RustBuffer* _Nonnull,
|
||||||
|
RustCallStatus *_Nonnull uniffiCallStatus
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_MOBILE_ANDROID_KEYSTORE_METHOD3
|
||||||
|
#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_MOBILE_ANDROID_KEYSTORE_METHOD3
|
||||||
|
typedef void (*UniffiCallbackInterfaceMobileAndroidKeystoreMethod3)(uint64_t, RustBuffer, RustBuffer, RustBuffer, RustBuffer, RustBuffer* _Nonnull,
|
||||||
|
RustCallStatus *_Nonnull uniffiCallStatus
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_MOBILE_ANDROID_KEYSTORE_METHOD4
|
||||||
|
#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_MOBILE_ANDROID_KEYSTORE_METHOD4
|
||||||
|
typedef void (*UniffiCallbackInterfaceMobileAndroidKeystoreMethod4)(uint64_t, RustBuffer, void* _Nonnull,
|
||||||
|
RustCallStatus *_Nonnull uniffiCallStatus
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_MOBILE_ANDROID_KEYSTORE_METHOD5
|
||||||
|
#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_MOBILE_ANDROID_KEYSTORE_METHOD5
|
||||||
|
typedef void (*UniffiCallbackInterfaceMobileAndroidKeystoreMethod5)(uint64_t, RustBuffer* _Nonnull,
|
||||||
|
RustCallStatus *_Nonnull uniffiCallStatus
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_MOBILE_ANDROID_KEYSTORE_METHOD6
|
||||||
|
#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_MOBILE_ANDROID_KEYSTORE_METHOD6
|
||||||
|
typedef void (*UniffiCallbackInterfaceMobileAndroidKeystoreMethod6)(uint64_t, void* _Nonnull,
|
||||||
|
RustCallStatus *_Nonnull uniffiCallStatus
|
||||||
|
);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_MOBILE_CLIPBOARD_METHOD0
|
#ifndef UNIFFI_FFIDEF_CALLBACK_INTERFACE_MOBILE_CLIPBOARD_METHOD0
|
||||||
#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_MOBILE_CLIPBOARD_METHOD0
|
#define UNIFFI_FFIDEF_CALLBACK_INTERFACE_MOBILE_CLIPBOARD_METHOD0
|
||||||
@@ -319,6 +368,21 @@ typedef void (*UniffiCallbackInterfaceMobileSecretBackendMethod5)(uint64_t, void
|
|||||||
RustCallStatus *_Nonnull uniffiCallStatus
|
RustCallStatus *_Nonnull uniffiCallStatus
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#ifndef UNIFFI_FFIDEF_V_TABLE_CALLBACK_INTERFACE_MOBILE_ANDROID_KEYSTORE
|
||||||
|
#define UNIFFI_FFIDEF_V_TABLE_CALLBACK_INTERFACE_MOBILE_ANDROID_KEYSTORE
|
||||||
|
typedef struct UniffiVTableCallbackInterfaceMobileAndroidKeystore {
|
||||||
|
UniffiCallbackInterfaceFree _Nonnull uniffiFree;
|
||||||
|
UniffiCallbackInterfaceClone _Nonnull uniffiClone;
|
||||||
|
UniffiCallbackInterfaceMobileAndroidKeystoreMethod0 _Nonnull deviceState;
|
||||||
|
UniffiCallbackInterfaceMobileAndroidKeystoreMethod1 _Nonnull createKey;
|
||||||
|
UniffiCallbackInterfaceMobileAndroidKeystoreMethod2 _Nonnull encrypt;
|
||||||
|
UniffiCallbackInterfaceMobileAndroidKeystoreMethod3 _Nonnull decrypt;
|
||||||
|
UniffiCallbackInterfaceMobileAndroidKeystoreMethod4 _Nonnull deleteKey;
|
||||||
|
UniffiCallbackInterfaceMobileAndroidKeystoreMethod5 _Nonnull aliases;
|
||||||
|
UniffiCallbackInterfaceMobileAndroidKeystoreMethod6 _Nonnull cancelPending;
|
||||||
|
} UniffiVTableCallbackInterfaceMobileAndroidKeystore;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#ifndef UNIFFI_FFIDEF_V_TABLE_CALLBACK_INTERFACE_MOBILE_CLIPBOARD
|
#ifndef UNIFFI_FFIDEF_V_TABLE_CALLBACK_INTERFACE_MOBILE_CLIPBOARD
|
||||||
#define UNIFFI_FFIDEF_V_TABLE_CALLBACK_INTERFACE_MOBILE_CLIPBOARD
|
#define UNIFFI_FFIDEF_V_TABLE_CALLBACK_INTERFACE_MOBILE_CLIPBOARD
|
||||||
@@ -760,6 +824,56 @@ void uniffi_ironstorage_mobile_fn_method_mobiletotpoperation_cancel(uint64_t ptr
|
|||||||
RustBuffer uniffi_ironstorage_mobile_fn_method_mobiletotpoperation_progress(uint64_t ptr, RustCallStatus *_Nonnull out_status
|
RustBuffer uniffi_ironstorage_mobile_fn_method_mobiletotpoperation_progress(uint64_t ptr, RustCallStatus *_Nonnull out_status
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_CLONE_MOBILEANDROIDKEYSTORE
|
||||||
|
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_CLONE_MOBILEANDROIDKEYSTORE
|
||||||
|
uint64_t uniffi_ironstorage_mobile_fn_clone_mobileandroidkeystore(uint64_t handle, RustCallStatus *_Nonnull out_status
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_FREE_MOBILEANDROIDKEYSTORE
|
||||||
|
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_FREE_MOBILEANDROIDKEYSTORE
|
||||||
|
void uniffi_ironstorage_mobile_fn_free_mobileandroidkeystore(uint64_t handle, RustCallStatus *_Nonnull out_status
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_INIT_CALLBACK_VTABLE_MOBILEANDROIDKEYSTORE
|
||||||
|
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_INIT_CALLBACK_VTABLE_MOBILEANDROIDKEYSTORE
|
||||||
|
void uniffi_ironstorage_mobile_fn_init_callback_vtable_mobileandroidkeystore(const UniffiVTableCallbackInterfaceMobileAndroidKeystore* _Nonnull vtable
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_METHOD_MOBILEANDROIDKEYSTORE_DEVICE_STATE
|
||||||
|
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_METHOD_MOBILEANDROIDKEYSTORE_DEVICE_STATE
|
||||||
|
RustBuffer uniffi_ironstorage_mobile_fn_method_mobileandroidkeystore_device_state(uint64_t ptr, RustCallStatus *_Nonnull out_status
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_METHOD_MOBILEANDROIDKEYSTORE_CREATE_KEY
|
||||||
|
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_METHOD_MOBILEANDROIDKEYSTORE_CREATE_KEY
|
||||||
|
void uniffi_ironstorage_mobile_fn_method_mobileandroidkeystore_create_key(uint64_t ptr, RustBuffer specification, RustCallStatus *_Nonnull out_status
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_METHOD_MOBILEANDROIDKEYSTORE_ENCRYPT
|
||||||
|
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_METHOD_MOBILEANDROIDKEYSTORE_ENCRYPT
|
||||||
|
RustBuffer uniffi_ironstorage_mobile_fn_method_mobileandroidkeystore_encrypt(uint64_t ptr, RustBuffer alias, RustBuffer authorization, RustBuffer aad, RustBuffer value, RustCallStatus *_Nonnull out_status
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_METHOD_MOBILEANDROIDKEYSTORE_DECRYPT
|
||||||
|
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_METHOD_MOBILEANDROIDKEYSTORE_DECRYPT
|
||||||
|
RustBuffer uniffi_ironstorage_mobile_fn_method_mobileandroidkeystore_decrypt(uint64_t ptr, RustBuffer alias, RustBuffer authorization, RustBuffer aad, RustBuffer value, RustCallStatus *_Nonnull out_status
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_METHOD_MOBILEANDROIDKEYSTORE_DELETE_KEY
|
||||||
|
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_METHOD_MOBILEANDROIDKEYSTORE_DELETE_KEY
|
||||||
|
void uniffi_ironstorage_mobile_fn_method_mobileandroidkeystore_delete_key(uint64_t ptr, RustBuffer alias, RustCallStatus *_Nonnull out_status
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_METHOD_MOBILEANDROIDKEYSTORE_ALIASES
|
||||||
|
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_METHOD_MOBILEANDROIDKEYSTORE_ALIASES
|
||||||
|
RustBuffer uniffi_ironstorage_mobile_fn_method_mobileandroidkeystore_aliases(uint64_t ptr, RustCallStatus *_Nonnull out_status
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_METHOD_MOBILEANDROIDKEYSTORE_CANCEL_PENDING
|
||||||
|
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_METHOD_MOBILEANDROIDKEYSTORE_CANCEL_PENDING
|
||||||
|
void uniffi_ironstorage_mobile_fn_method_mobileandroidkeystore_cancel_pending(uint64_t ptr, RustCallStatus *_Nonnull out_status
|
||||||
|
);
|
||||||
|
#endif
|
||||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_CLONE_MOBILECLIPBOARD
|
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_CLONE_MOBILECLIPBOARD
|
||||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_CLONE_MOBILECLIPBOARD
|
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_CLONE_MOBILECLIPBOARD
|
||||||
uint64_t uniffi_ironstorage_mobile_fn_clone_mobileclipboard(uint64_t handle, RustCallStatus *_Nonnull out_status
|
uint64_t uniffi_ironstorage_mobile_fn_clone_mobileclipboard(uint64_t handle, RustCallStatus *_Nonnull out_status
|
||||||
@@ -875,6 +989,11 @@ void uniffi_ironstorage_mobile_fn_free_mobileprivateruntime(uint64_t handle, Rus
|
|||||||
void uniffi_ironstorage_mobile_fn_method_mobileprivateruntime_activate(uint64_t ptr, RustCallStatus *_Nonnull out_status
|
void uniffi_ironstorage_mobile_fn_method_mobileprivateruntime_activate(uint64_t ptr, RustCallStatus *_Nonnull out_status
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_METHOD_MOBILEPRIVATERUNTIME_ANDROID_SECRET_BACKEND
|
||||||
|
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_METHOD_MOBILEPRIVATERUNTIME_ANDROID_SECRET_BACKEND
|
||||||
|
uint64_t uniffi_ironstorage_mobile_fn_method_mobileprivateruntime_android_secret_backend(uint64_t ptr, uint64_t keystore, RustCallStatus *_Nonnull out_status
|
||||||
|
);
|
||||||
|
#endif
|
||||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_METHOD_MOBILEPRIVATERUNTIME_AUTHENTICATION
|
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_METHOD_MOBILEPRIVATERUNTIME_AUTHENTICATION
|
||||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_METHOD_MOBILEPRIVATERUNTIME_AUTHENTICATION
|
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_FN_METHOD_MOBILEPRIVATERUNTIME_AUTHENTICATION
|
||||||
uint64_t uniffi_ironstorage_mobile_fn_method_mobileprivateruntime_authentication(uint64_t ptr, uint64_t backend, uint64_t clock, RustCallStatus *_Nonnull out_status
|
uint64_t uniffi_ironstorage_mobile_fn_method_mobileprivateruntime_authentication(uint64_t ptr, uint64_t backend, uint64_t clock, RustCallStatus *_Nonnull out_status
|
||||||
@@ -1803,6 +1922,48 @@ uint16_t uniffi_ironstorage_mobile_checksum_method_mobiletotpoperation_cancel(vo
|
|||||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_CHECKSUM_METHOD_MOBILETOTPOPERATION_PROGRESS
|
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_CHECKSUM_METHOD_MOBILETOTPOPERATION_PROGRESS
|
||||||
uint16_t uniffi_ironstorage_mobile_checksum_method_mobiletotpoperation_progress(void
|
uint16_t uniffi_ironstorage_mobile_checksum_method_mobiletotpoperation_progress(void
|
||||||
|
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_CHECKSUM_METHOD_MOBILEANDROIDKEYSTORE_DEVICE_STATE
|
||||||
|
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_CHECKSUM_METHOD_MOBILEANDROIDKEYSTORE_DEVICE_STATE
|
||||||
|
uint16_t uniffi_ironstorage_mobile_checksum_method_mobileandroidkeystore_device_state(void
|
||||||
|
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_CHECKSUM_METHOD_MOBILEANDROIDKEYSTORE_CREATE_KEY
|
||||||
|
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_CHECKSUM_METHOD_MOBILEANDROIDKEYSTORE_CREATE_KEY
|
||||||
|
uint16_t uniffi_ironstorage_mobile_checksum_method_mobileandroidkeystore_create_key(void
|
||||||
|
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_CHECKSUM_METHOD_MOBILEANDROIDKEYSTORE_ENCRYPT
|
||||||
|
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_CHECKSUM_METHOD_MOBILEANDROIDKEYSTORE_ENCRYPT
|
||||||
|
uint16_t uniffi_ironstorage_mobile_checksum_method_mobileandroidkeystore_encrypt(void
|
||||||
|
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_CHECKSUM_METHOD_MOBILEANDROIDKEYSTORE_DECRYPT
|
||||||
|
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_CHECKSUM_METHOD_MOBILEANDROIDKEYSTORE_DECRYPT
|
||||||
|
uint16_t uniffi_ironstorage_mobile_checksum_method_mobileandroidkeystore_decrypt(void
|
||||||
|
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_CHECKSUM_METHOD_MOBILEANDROIDKEYSTORE_DELETE_KEY
|
||||||
|
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_CHECKSUM_METHOD_MOBILEANDROIDKEYSTORE_DELETE_KEY
|
||||||
|
uint16_t uniffi_ironstorage_mobile_checksum_method_mobileandroidkeystore_delete_key(void
|
||||||
|
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_CHECKSUM_METHOD_MOBILEANDROIDKEYSTORE_ALIASES
|
||||||
|
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_CHECKSUM_METHOD_MOBILEANDROIDKEYSTORE_ALIASES
|
||||||
|
uint16_t uniffi_ironstorage_mobile_checksum_method_mobileandroidkeystore_aliases(void
|
||||||
|
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_CHECKSUM_METHOD_MOBILEANDROIDKEYSTORE_CANCEL_PENDING
|
||||||
|
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_CHECKSUM_METHOD_MOBILEANDROIDKEYSTORE_CANCEL_PENDING
|
||||||
|
uint16_t uniffi_ironstorage_mobile_checksum_method_mobileandroidkeystore_cancel_pending(void
|
||||||
|
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_CHECKSUM_METHOD_MOBILECLIPBOARD_READ
|
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_CHECKSUM_METHOD_MOBILECLIPBOARD_READ
|
||||||
@@ -1875,6 +2036,12 @@ uint16_t uniffi_ironstorage_mobile_checksum_method_mobilesecretbackend_unlock(vo
|
|||||||
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_CHECKSUM_METHOD_MOBILEPRIVATERUNTIME_ACTIVATE
|
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_CHECKSUM_METHOD_MOBILEPRIVATERUNTIME_ACTIVATE
|
||||||
uint16_t uniffi_ironstorage_mobile_checksum_method_mobileprivateruntime_activate(void
|
uint16_t uniffi_ironstorage_mobile_checksum_method_mobileprivateruntime_activate(void
|
||||||
|
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_CHECKSUM_METHOD_MOBILEPRIVATERUNTIME_ANDROID_SECRET_BACKEND
|
||||||
|
#define UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_CHECKSUM_METHOD_MOBILEPRIVATERUNTIME_ANDROID_SECRET_BACKEND
|
||||||
|
uint16_t uniffi_ironstorage_mobile_checksum_method_mobileprivateruntime_android_secret_backend(void
|
||||||
|
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_CHECKSUM_METHOD_MOBILEPRIVATERUNTIME_AUTHENTICATION
|
#ifndef UNIFFI_FFIDEF_UNIFFI_IRONSTORAGE_MOBILE_CHECKSUM_METHOD_MOBILEPRIVATERUNTIME_AUTHENTICATION
|
||||||
|
|||||||
@@ -0,0 +1,282 @@
|
|||||||
|
//! Android OS calls; all envelopes, policy and lifecycle remain in storage.
|
||||||
|
use crate::{MobileSecretBackend, MobileSecretError, MobileSecretLocator, MobileSecretProtection};
|
||||||
|
use ironstorage::{
|
||||||
|
repository::SecretBytes,
|
||||||
|
secret_store::{
|
||||||
|
SecretLocator, SecretProtection, SecretStoreBackend, SecretStoreError, android as os,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use std::{fmt, sync::Arc};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, uniffi::Record)]
|
||||||
|
pub struct MobileAndroidDeviceState {
|
||||||
|
pub api: u32,
|
||||||
|
pub locked: bool,
|
||||||
|
pub secure: bool,
|
||||||
|
pub strong_biometric: bool,
|
||||||
|
pub strongbox: bool,
|
||||||
|
}
|
||||||
|
#[derive(Clone, Copy, uniffi::Enum)]
|
||||||
|
pub enum MobileAndroidAuthorization {
|
||||||
|
None,
|
||||||
|
StrongBiometric,
|
||||||
|
UserPresence,
|
||||||
|
}
|
||||||
|
#[derive(Clone, uniffi::Record)]
|
||||||
|
pub struct MobileAndroidKeySpecification {
|
||||||
|
pub alias: String,
|
||||||
|
pub authorization: MobileAndroidAuthorization,
|
||||||
|
pub unlocked_device: bool,
|
||||||
|
pub invalidate_on_enrollment: bool,
|
||||||
|
pub strongbox: bool,
|
||||||
|
}
|
||||||
|
#[derive(Clone, uniffi::Record)]
|
||||||
|
pub struct MobileAndroidCiphertext {
|
||||||
|
pub nonce: Vec<u8>,
|
||||||
|
pub bytes: Vec<u8>,
|
||||||
|
}
|
||||||
|
#[derive(Clone, Copy, Debug, uniffi::Error)]
|
||||||
|
pub enum MobileAndroidKeystoreError {
|
||||||
|
MissingKey,
|
||||||
|
Invalidated,
|
||||||
|
Lockout,
|
||||||
|
Locked,
|
||||||
|
Denied,
|
||||||
|
Cancelled,
|
||||||
|
Corrupted,
|
||||||
|
UnsupportedProtection,
|
||||||
|
StrongboxUnavailable,
|
||||||
|
AlreadyExists,
|
||||||
|
Unavailable,
|
||||||
|
}
|
||||||
|
impl fmt::Display for MobileAndroidKeystoreError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.write_str("Android Keystore operation failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::error::Error for MobileAndroidKeystoreError {}
|
||||||
|
#[uniffi::export(with_foreign)]
|
||||||
|
pub trait MobileAndroidKeystore: Send + Sync {
|
||||||
|
fn device_state(&self) -> Result<MobileAndroidDeviceState, MobileAndroidKeystoreError>;
|
||||||
|
fn create_key(
|
||||||
|
&self,
|
||||||
|
specification: MobileAndroidKeySpecification,
|
||||||
|
) -> Result<(), MobileAndroidKeystoreError>;
|
||||||
|
fn encrypt(
|
||||||
|
&self,
|
||||||
|
alias: String,
|
||||||
|
authorization: MobileAndroidAuthorization,
|
||||||
|
aad: Vec<u8>,
|
||||||
|
value: Vec<u8>,
|
||||||
|
) -> Result<MobileAndroidCiphertext, MobileAndroidKeystoreError>;
|
||||||
|
fn decrypt(
|
||||||
|
&self,
|
||||||
|
alias: String,
|
||||||
|
authorization: MobileAndroidAuthorization,
|
||||||
|
aad: Vec<u8>,
|
||||||
|
value: MobileAndroidCiphertext,
|
||||||
|
) -> Result<Vec<u8>, MobileAndroidKeystoreError>;
|
||||||
|
fn delete_key(&self, alias: String) -> Result<(), MobileAndroidKeystoreError>;
|
||||||
|
fn aliases(&self) -> Result<Vec<String>, MobileAndroidKeystoreError>;
|
||||||
|
fn cancel_pending(&self);
|
||||||
|
}
|
||||||
|
pub(crate) struct KeystoreAdapter(pub Arc<dyn MobileAndroidKeystore>);
|
||||||
|
impl From<os::AndroidAuthorization> for MobileAndroidAuthorization {
|
||||||
|
fn from(value: os::AndroidAuthorization) -> Self {
|
||||||
|
match value {
|
||||||
|
os::AndroidAuthorization::None => Self::None,
|
||||||
|
os::AndroidAuthorization::StrongBiometric => Self::StrongBiometric,
|
||||||
|
os::AndroidAuthorization::UserPresence => Self::UserPresence,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<MobileAndroidKeystoreError> for os::AndroidKeystoreError {
|
||||||
|
fn from(value: MobileAndroidKeystoreError) -> Self {
|
||||||
|
match value {
|
||||||
|
MobileAndroidKeystoreError::MissingKey => Self::MissingKey,
|
||||||
|
MobileAndroidKeystoreError::Invalidated => Self::Invalidated,
|
||||||
|
MobileAndroidKeystoreError::Lockout => Self::Lockout,
|
||||||
|
MobileAndroidKeystoreError::Locked => Self::Locked,
|
||||||
|
MobileAndroidKeystoreError::Denied => Self::Denied,
|
||||||
|
MobileAndroidKeystoreError::Cancelled => Self::Cancelled,
|
||||||
|
MobileAndroidKeystoreError::Corrupted => Self::Corrupted,
|
||||||
|
MobileAndroidKeystoreError::UnsupportedProtection => Self::UnsupportedProtection,
|
||||||
|
MobileAndroidKeystoreError::StrongboxUnavailable => Self::StrongboxUnavailable,
|
||||||
|
MobileAndroidKeystoreError::AlreadyExists => Self::AlreadyExists,
|
||||||
|
MobileAndroidKeystoreError::Unavailable => Self::Unavailable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl os::AndroidKeystore for KeystoreAdapter {
|
||||||
|
fn device_state(&self) -> Result<os::AndroidDeviceState, os::AndroidKeystoreError> {
|
||||||
|
self.0
|
||||||
|
.device_state()
|
||||||
|
.map(|s| os::AndroidDeviceState {
|
||||||
|
api: s.api,
|
||||||
|
locked: s.locked,
|
||||||
|
secure: s.secure,
|
||||||
|
strong_biometric: s.strong_biometric,
|
||||||
|
strongbox: s.strongbox,
|
||||||
|
})
|
||||||
|
.map_err(Into::into)
|
||||||
|
}
|
||||||
|
fn create_key(&self, s: &os::AndroidKeySpecification) -> Result<(), os::AndroidKeystoreError> {
|
||||||
|
self.0
|
||||||
|
.create_key(MobileAndroidKeySpecification {
|
||||||
|
alias: s.alias.clone(),
|
||||||
|
authorization: s.authorization.into(),
|
||||||
|
unlocked_device: s.unlocked_device,
|
||||||
|
invalidate_on_enrollment: s.invalidate_on_enrollment,
|
||||||
|
strongbox: s.strongbox,
|
||||||
|
})
|
||||||
|
.map_err(Into::into)
|
||||||
|
}
|
||||||
|
fn encrypt(
|
||||||
|
&self,
|
||||||
|
alias: &str,
|
||||||
|
authorization: os::AndroidAuthorization,
|
||||||
|
aad: &[u8],
|
||||||
|
value: &SecretBytes,
|
||||||
|
) -> Result<os::AndroidCiphertext, os::AndroidKeystoreError> {
|
||||||
|
self.0
|
||||||
|
.encrypt(
|
||||||
|
alias.into(),
|
||||||
|
authorization.into(),
|
||||||
|
aad.to_vec(),
|
||||||
|
value.expose().to_vec(),
|
||||||
|
)
|
||||||
|
.map(|v| os::AndroidCiphertext {
|
||||||
|
nonce: v.nonce,
|
||||||
|
bytes: v.bytes,
|
||||||
|
})
|
||||||
|
.map_err(Into::into)
|
||||||
|
}
|
||||||
|
fn decrypt(
|
||||||
|
&self,
|
||||||
|
alias: &str,
|
||||||
|
authorization: os::AndroidAuthorization,
|
||||||
|
aad: &[u8],
|
||||||
|
value: &os::AndroidCiphertext,
|
||||||
|
) -> Result<SecretBytes, os::AndroidKeystoreError> {
|
||||||
|
self.0
|
||||||
|
.decrypt(
|
||||||
|
alias.into(),
|
||||||
|
authorization.into(),
|
||||||
|
aad.to_vec(),
|
||||||
|
MobileAndroidCiphertext {
|
||||||
|
nonce: value.nonce.clone(),
|
||||||
|
bytes: value.bytes.clone(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.map(SecretBytes::new)
|
||||||
|
.map_err(Into::into)
|
||||||
|
}
|
||||||
|
fn delete_key(&self, alias: &str) -> Result<(), os::AndroidKeystoreError> {
|
||||||
|
self.0.delete_key(alias.into()).map_err(Into::into)
|
||||||
|
}
|
||||||
|
fn aliases(&self) -> Result<Vec<String>, os::AndroidKeystoreError> {
|
||||||
|
self.0.aliases().map_err(Into::into)
|
||||||
|
}
|
||||||
|
fn cancel_pending(&self) {
|
||||||
|
self.0.cancel_pending();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub(crate) struct RustSecretBackend(pub os::AndroidSecretBackend);
|
||||||
|
impl TryFrom<MobileSecretLocator> for SecretLocator {
|
||||||
|
type Error = MobileSecretError;
|
||||||
|
fn try_from(value: MobileSecretLocator) -> Result<Self, Self::Error> {
|
||||||
|
Ok(match value {
|
||||||
|
MobileSecretLocator::ApplicationBinding => Self::ApplicationBinding,
|
||||||
|
MobileSecretLocator::OpenPgpPassphrase { fingerprint } => {
|
||||||
|
Self::OpenPgpPassphrase { fingerprint }
|
||||||
|
}
|
||||||
|
MobileSecretLocator::HttpsGitCredential {
|
||||||
|
server_id,
|
||||||
|
application_id,
|
||||||
|
} => Self::HttpsGitCredential {
|
||||||
|
server_id,
|
||||||
|
application_id,
|
||||||
|
},
|
||||||
|
MobileSecretLocator::SshKeyPassphrase { fingerprint } => Self::SshKeyPassphrase {
|
||||||
|
fingerprint: ironstorage::config::SshFingerprint::parse(&fingerprint)
|
||||||
|
.map_err(|_| MobileSecretError::Corrupted)?,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<MobileSecretProtection> for SecretProtection {
|
||||||
|
fn from(value: MobileSecretProtection) -> Self {
|
||||||
|
match value {
|
||||||
|
MobileSecretProtection::DeviceUnlocked => Self::DeviceUnlocked,
|
||||||
|
MobileSecretProtection::RequireUserPresence => Self::RequireUserPresence,
|
||||||
|
MobileSecretProtection::BiometryCurrentSet => Self::BiometryCurrentSet,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<SecretStoreError> for MobileSecretError {
|
||||||
|
fn from(value: SecretStoreError) -> Self {
|
||||||
|
match value {
|
||||||
|
SecretStoreError::AlreadyExists => Self::AlreadyExists,
|
||||||
|
SecretStoreError::Missing => Self::Missing,
|
||||||
|
SecretStoreError::Locked => Self::Locked,
|
||||||
|
SecretStoreError::Denied => Self::Denied,
|
||||||
|
SecretStoreError::Cancelled => Self::Cancelled,
|
||||||
|
SecretStoreError::Corrupted => Self::Corrupted,
|
||||||
|
SecretStoreError::UnsupportedProtection => Self::UnsupportedProtection,
|
||||||
|
SecretStoreError::Unavailable => Self::Unavailable,
|
||||||
|
SecretStoreError::DeviceKeyMissing => Self::DeviceKeyMissing,
|
||||||
|
SecretStoreError::Invalidated => Self::Invalidated,
|
||||||
|
SecretStoreError::Lockout => Self::Lockout,
|
||||||
|
_ => Self::Corrupted,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl MobileSecretBackend for RustSecretBackend {
|
||||||
|
fn create(
|
||||||
|
&self,
|
||||||
|
locator: MobileSecretLocator,
|
||||||
|
protection: MobileSecretProtection,
|
||||||
|
value: Vec<u8>,
|
||||||
|
) -> Result<(), MobileSecretError> {
|
||||||
|
let secret = SecretBytes::new(value);
|
||||||
|
self.0
|
||||||
|
.create(&locator.try_into()?, protection.into(), secret.expose())
|
||||||
|
.map_err(Into::into)
|
||||||
|
}
|
||||||
|
fn replace(
|
||||||
|
&self,
|
||||||
|
locator: MobileSecretLocator,
|
||||||
|
protection: MobileSecretProtection,
|
||||||
|
value: Vec<u8>,
|
||||||
|
) -> Result<(), MobileSecretError> {
|
||||||
|
let secret = SecretBytes::new(value);
|
||||||
|
self.0
|
||||||
|
.replace(&locator.try_into()?, protection.into(), secret.expose())
|
||||||
|
.map_err(Into::into)
|
||||||
|
}
|
||||||
|
fn retrieve(
|
||||||
|
&self,
|
||||||
|
locator: MobileSecretLocator,
|
||||||
|
protection: MobileSecretProtection,
|
||||||
|
) -> Result<Vec<u8>, MobileSecretError> {
|
||||||
|
self.0
|
||||||
|
.retrieve(&locator.try_into()?, protection.into())
|
||||||
|
.map(|v| v.expose().to_vec())
|
||||||
|
.map_err(Into::into)
|
||||||
|
}
|
||||||
|
fn delete(
|
||||||
|
&self,
|
||||||
|
locator: MobileSecretLocator,
|
||||||
|
protection: MobileSecretProtection,
|
||||||
|
) -> Result<(), MobileSecretError> {
|
||||||
|
self.0
|
||||||
|
.delete(&locator.try_into()?, protection.into())
|
||||||
|
.map_err(Into::into)
|
||||||
|
}
|
||||||
|
fn lock(&self) -> Result<(), MobileSecretError> {
|
||||||
|
self.0.lock().map_err(Into::into)
|
||||||
|
}
|
||||||
|
fn unlock(&self) -> Result<(), MobileSecretError> {
|
||||||
|
self.0.unlock().map_err(Into::into)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -79,6 +79,8 @@ use ironstorage::{
|
|||||||
|
|
||||||
uniffi::setup_scaffolding!();
|
uniffi::setup_scaffolding!();
|
||||||
|
|
||||||
|
mod android_keystore;
|
||||||
|
pub use android_keystore::*;
|
||||||
mod platform;
|
mod platform;
|
||||||
pub use platform::*;
|
pub use platform::*;
|
||||||
|
|
||||||
|
|||||||
@@ -130,6 +130,9 @@ pub enum MobileSecretError {
|
|||||||
Corrupted,
|
Corrupted,
|
||||||
UnsupportedProtection,
|
UnsupportedProtection,
|
||||||
Unavailable,
|
Unavailable,
|
||||||
|
DeviceKeyMissing,
|
||||||
|
Invalidated,
|
||||||
|
Lockout,
|
||||||
}
|
}
|
||||||
impl fmt::Display for MobileSecretError {
|
impl fmt::Display for MobileSecretError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
@@ -148,6 +151,9 @@ impl From<MobileSecretError> for SecretStoreError {
|
|||||||
MobileSecretError::Corrupted => Self::Corrupted,
|
MobileSecretError::Corrupted => Self::Corrupted,
|
||||||
MobileSecretError::UnsupportedProtection => Self::UnsupportedProtection,
|
MobileSecretError::UnsupportedProtection => Self::UnsupportedProtection,
|
||||||
MobileSecretError::Unavailable => Self::Unavailable,
|
MobileSecretError::Unavailable => Self::Unavailable,
|
||||||
|
MobileSecretError::DeviceKeyMissing => Self::DeviceKeyMissing,
|
||||||
|
MobileSecretError::Invalidated => Self::Invalidated,
|
||||||
|
MobileSecretError::Lockout => Self::Lockout,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,6 +100,17 @@ pub struct MobilePrivateRuntime {
|
|||||||
}
|
}
|
||||||
#[uniffi::export]
|
#[uniffi::export]
|
||||||
impl MobilePrivateRuntime {
|
impl MobilePrivateRuntime {
|
||||||
|
pub fn android_secret_backend(
|
||||||
|
&self,
|
||||||
|
keystore: Arc<dyn crate::MobileAndroidKeystore>,
|
||||||
|
) -> Result<Arc<dyn MobileSecretBackend>, MobilePrivateStorageFfiError> {
|
||||||
|
let backend = self
|
||||||
|
.storage
|
||||||
|
.android_secret_backend(Arc::new(crate::android_keystore::KeystoreAdapter(keystore)))?;
|
||||||
|
Ok(Arc::new(crate::android_keystore::RustSecretBackend(
|
||||||
|
backend,
|
||||||
|
)))
|
||||||
|
}
|
||||||
pub fn activate(&self) -> Result<(), MobilePrivateStorageFfiError> {
|
pub fn activate(&self) -> Result<(), MobilePrivateStorageFfiError> {
|
||||||
self.storage.activate().map_err(Into::into)
|
self.storage.activate().map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ zbus-secret-service-keyring-store = { workspace = true, optional = true }
|
|||||||
arboard = { workspace = true, optional = true }
|
arboard = { workspace = true, optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
aes-gcm = "0.11.1"
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
keepass = { workspace = true, features = ["save_kdbx4"] }
|
keepass = { workspace = true, features = ["save_kdbx4"] }
|
||||||
nix = { version = "0.31", features = ["fs"] }
|
nix = { version = "0.31", features = ["fs"] }
|
||||||
|
|||||||
@@ -107,11 +107,14 @@ impl MobileAuthenticationError {
|
|||||||
"IronStorage Locked",
|
"IronStorage Locked",
|
||||||
"The authentication lease expired.",
|
"The authentication lease expired.",
|
||||||
),
|
),
|
||||||
AuthenticationError::SecretStore(SecretStoreError::Missing) => {
|
AuthenticationError::SecretStore(
|
||||||
Self::passphrase_required("Enter the GPG key passphrase to continue.")
|
SecretStoreError::Missing
|
||||||
}
|
| SecretStoreError::DeviceKeyMissing
|
||||||
|
| SecretStoreError::Invalidated,
|
||||||
|
) => Self::passphrase_required("Enter the GPG key passphrase to continue."),
|
||||||
AuthenticationError::SecretStore(
|
AuthenticationError::SecretStore(
|
||||||
SecretStoreError::Denied
|
SecretStoreError::Denied
|
||||||
|
| SecretStoreError::Lockout
|
||||||
| SecretStoreError::UnsupportedProtection
|
| SecretStoreError::UnsupportedProtection
|
||||||
| SecretStoreError::Unavailable,
|
| SecretStoreError::Unavailable,
|
||||||
) => Self::new(
|
) => Self::new(
|
||||||
|
|||||||
@@ -275,6 +275,14 @@ impl PrivateStorage {
|
|||||||
Ok(storage)
|
Ok(storage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn android_secret_backend(
|
||||||
|
&self,
|
||||||
|
keystore: std::sync::Arc<dyn crate::secret_store::android::AndroidKeystore>,
|
||||||
|
) -> Result<crate::secret_store::android::AndroidSecretBackend, PrivateStorageError> {
|
||||||
|
let directory = private_directory(&self.data, "secrets")?;
|
||||||
|
crate::secret_store::android::AndroidSecretBackend::open(directory, keystore)
|
||||||
|
.map_err(secret_error)
|
||||||
|
}
|
||||||
pub fn root(&self) -> &Path {
|
pub fn root(&self) -> &Path {
|
||||||
&self.root
|
&self.root
|
||||||
}
|
}
|
||||||
@@ -476,8 +484,12 @@ fn secret_error(error: SecretStoreError) -> PrivateStorageError {
|
|||||||
SecretStoreError::Locked | SecretStoreError::Denied | SecretStoreError::Cancelled => {
|
SecretStoreError::Locked | SecretStoreError::Denied | SecretStoreError::Cancelled => {
|
||||||
PrivateStorageError::SecureStorageLocked
|
PrivateStorageError::SecureStorageLocked
|
||||||
}
|
}
|
||||||
SecretStoreError::Missing => PrivateStorageError::RestoredWithoutKeystore,
|
SecretStoreError::Missing | SecretStoreError::DeviceKeyMissing => {
|
||||||
SecretStoreError::Corrupted => PrivateStorageError::InvalidSecureBinding,
|
PrivateStorageError::RestoredWithoutKeystore
|
||||||
|
}
|
||||||
|
SecretStoreError::Corrupted | SecretStoreError::Invalidated => {
|
||||||
|
PrivateStorageError::InvalidSecureBinding
|
||||||
|
}
|
||||||
_ => PrivateStorageError::SecureStorageUnavailable,
|
_ => PrivateStorageError::SecureStorageUnavailable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ use crate::{
|
|||||||
repository::SecretBytes,
|
repository::SecretBytes,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub mod android;
|
||||||
mod platform;
|
mod platform;
|
||||||
|
|
||||||
pub(crate) use platform::NativeSecretBackend;
|
pub(crate) use platform::NativeSecretBackend;
|
||||||
@@ -283,6 +284,9 @@ impl SecretCachePolicy {
|
|||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
pub enum SecretStoreError {
|
pub enum SecretStoreError {
|
||||||
|
DeviceKeyMissing,
|
||||||
|
Invalidated,
|
||||||
|
Lockout,
|
||||||
InvalidReference,
|
InvalidReference,
|
||||||
InvalidCachePolicy,
|
InvalidCachePolicy,
|
||||||
AlreadyExists,
|
AlreadyExists,
|
||||||
@@ -298,6 +302,11 @@ pub enum SecretStoreError {
|
|||||||
impl fmt::Display for SecretStoreError {
|
impl fmt::Display for SecretStoreError {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let message = match self {
|
let message = match self {
|
||||||
|
Self::DeviceKeyMissing => {
|
||||||
|
"the device key is missing; recover the protected secret manually"
|
||||||
|
}
|
||||||
|
Self::Invalidated => "the protected key was invalidated; recover the secret manually",
|
||||||
|
Self::Lockout => "biometric authentication is locked out",
|
||||||
Self::InvalidReference => "the secret reference is invalid",
|
Self::InvalidReference => "the secret reference is invalid",
|
||||||
Self::InvalidCachePolicy => "the secret cache policy is invalid",
|
Self::InvalidCachePolicy => "the secret cache policy is invalid",
|
||||||
Self::AlreadyExists => "the referenced secret already exists",
|
Self::AlreadyExists => "the referenced secret already exists",
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,91 @@
|
|||||||
|
# Android protected secrets (#93)
|
||||||
|
|
||||||
|
`crates/storage::secret_store::android` implements the secure-secret backend.
|
||||||
|
`MobilePrivateRuntime.androidSecretBackend` connects it to a narrow UniFFI OS
|
||||||
|
callback. Core translates callback types; platform calls Android Keystore,
|
||||||
|
KeyguardManager and AndroidX BiometricPrompt. No frontend reads a password-store
|
||||||
|
repository, chooses a credential identity/protection, persists ciphertext, or
|
||||||
|
implements encryption itself. App startup verifies its existing private device
|
||||||
|
binding using this real backend before presenting the Rust shell.
|
||||||
|
|
||||||
|
The OS holds non-exportable AES-256-GCM keys. Rust stores versioned sealed
|
||||||
|
records under `noBackupFilesDir/ironstorage/secrets`, with 0700 directories and
|
||||||
|
0600 files. Service/account identities become SHA-256 names using
|
||||||
|
length-delimited namespace fields; OpenPGP fingerprints normalize to uppercase.
|
||||||
|
Each write creates a random generation-specific alias. GCM authenticates the
|
||||||
|
record version, identity, protection class and complete alias; its nonce is the
|
||||||
|
12-byte IV generated by the OS. Authentication happens before supplying AAD to
|
||||||
|
an authorization-bound cipher. No plaintext token, account record or passphrase
|
||||||
|
is serialized in ordinary settings, the layout marker or logs.
|
||||||
|
|
||||||
|
| Storage policy | Android key and operation |
|
||||||
|
| --- | --- |
|
||||||
|
| DeviceUnlocked (Git credentials/device binding) | No interactive authentication; Keyguard checks before and after each operation, plus `setUnlockedDeviceRequired` from API 28 |
|
||||||
|
| BiometryCurrentSet (optional enrolled GPG passphrase) | Per-operation `BIOMETRIC_STRONG` CryptoObject, enrollment invalidation enabled, secure lock required; no PIN fallback |
|
||||||
|
| RequireUserPresence | From API 30, per-operation `BIOMETRIC_STRONG \| DEVICE_CREDENTIAL` CryptoObject; the configured credential flow is explicit |
|
||||||
|
|
||||||
|
API 26–27 use the OS locked-state checks for DeviceUnlocked and the legacy
|
||||||
|
per-operation biometric key parameter. API 28–34 require a secure screen lock
|
||||||
|
because those releases have documented unlocked-key bugs. API 35+ support
|
||||||
|
unlocked keys without a secure lock. Unsupported protection returns a typed
|
||||||
|
error; it never downgrades an enrolled passphrase to device-only protection.
|
||||||
|
Rust restricts OpenPGP locators to the two interactive protection classes and
|
||||||
|
Git/device-binding locators to DeviceUnlocked. Factory failures become storage
|
||||||
|
recovery state in Rust; Kotlin only presents that state.
|
||||||
|
Android invalidates biometric-bound keys when a biometric is added or all
|
||||||
|
biometrics are removed; removing a secure lock also invalidates authentication
|
||||||
|
keys. Removing one of several original enrolled biometrics does not grant a new
|
||||||
|
biometric access. These are the [Android key-policy guarantees](https://developer.android.com/reference/android/security/keystore/KeyGenParameterSpec.Builder),
|
||||||
|
not a claim of extra OS enrollment APIs or physical-device validation.
|
||||||
|
|
||||||
|
StrongBox is requested only when the framework advertises it. A typed
|
||||||
|
StrongBox-unavailable generation failure retries the same specification using
|
||||||
|
ordinary Keystore; authentication and unlocked-device requirements stay exact.
|
||||||
|
Other generation/cipher failures never trigger a weaker key or a retry without
|
||||||
|
authentication. The persistent emulators exercise the non-StrongBox path; Rust
|
||||||
|
mocks exercise the advertised-but-unavailable fallback.
|
||||||
|
|
||||||
|
A private advisory lock serializes record transactions. Create rejects an
|
||||||
|
existing record; replace rejects an absent one. Replacement seals with a new
|
||||||
|
key, syncs a private atomic file, renames it and syncs the directory before
|
||||||
|
retiring the previous key. Cipher/authentication/write failure preserves the
|
||||||
|
previous record and removes the candidate key. If durability fails after rename,
|
||||||
|
the new key is retained because the new record may already be installed.
|
||||||
|
Delete unlinks the selected sealed record and deletes its key without requiring
|
||||||
|
biometric authentication, so disabling enrollment can remove protected data.
|
||||||
|
Startup removes only well-formed owned orphan aliases and unlocked owned atomic
|
||||||
|
files, retaining keys when any record cannot be parsed. Unrelated aliases are
|
||||||
|
left alone. Records are bounded to 16 KiB and startup enumeration is bounded.
|
||||||
|
|
||||||
|
Missing ciphertext, missing device keys, invalidated keys, corruption,
|
||||||
|
duplicate, cancellation, denial, device lock, lockout, unsupported policy and
|
||||||
|
unavailability have separate Rust-visible errors. Existing bound data with a
|
||||||
|
missing Keystore key reports restore recovery and never receives a replacement
|
||||||
|
binding. Tampering or changing the requested policy fails closed. Background
|
||||||
|
lock increments the Rust generation and cancels the pending OS prompt; a late
|
||||||
|
cipher result cannot return plaintext for an obsolete generation.
|
||||||
|
|
||||||
|
Kotlin uses the exact authorized Cipher returned in the CryptoObject callback,
|
||||||
|
one pending request, a bounded wait and cancellation. OS input arrays are
|
||||||
|
zeroed in `finally`; generated foreign callback return arrays are erased after
|
||||||
|
serialization. Rust immediately owns cleartext in `SecretBytes`, including
|
||||||
|
incoming create/replace buffers. Errors and generated diagnostics are redacted.
|
||||||
|
The JVM, OS cipher implementation and UniFFI serialization can still make
|
||||||
|
transient copies; this is not a guarantee of complete memory erasure. There is
|
||||||
|
no EncryptedSharedPreferences, MasterKey, alternative repository format or
|
||||||
|
application subprocess.
|
||||||
|
|
||||||
|
Tests use public fixture secrets and synthetic emulator fingers. Rust exercises
|
||||||
|
all record operations, policy mappings, failed replacement, tampering, restore,
|
||||||
|
orphan ownership, lock/generation races, shared credential encoding and actual
|
||||||
|
mobile biometric-disable deletion. Android instrumentation uses real Keystore
|
||||||
|
keys and real CryptoObject prompts; its host is confined to the test APK.
|
||||||
|
Enrollment/lock removal deliberately invalidate only disposable fixture keys.
|
||||||
|
|
||||||
|
Android 35 delivers the direct lockout callback, verified as `Lockout`. Android
|
||||||
|
37 instead offers an OS PIN screen to recover the sensor during biometric-only
|
||||||
|
authentication. The emulator test enters that PIN and verifies the operation
|
||||||
|
still requires a matching fingerprint; cancelling then returns `Cancelled` and
|
||||||
|
no cipher result. The PIN is never added to the biometric-only key's permitted
|
||||||
|
authenticators. Native callback tests also verify Rust-visible lockout, policy
|
||||||
|
rejection, factory recovery mapping and post-serialization array erasure.
|
||||||
@@ -65,7 +65,7 @@ milestone. This list gives ownership, not permission to skip acceptance criteria
|
|||||||
| [#90 Private paths/config/cache/backup](https://git.rfc1437.de/hugo/IronStorage/issues/90) | crates/storage plus Android path adapter | Context roots/capabilities, atomic layout/migrations, backup rules; Rust and sandbox/update tests |
|
| [#90 Private paths/config/cache/backup](https://git.rfc1437.de/hugo/IronStorage/issues/90) | crates/storage plus Android path adapter | Context roots/capabilities, atomic layout/migrations, backup rules; Rust and sandbox/update tests |
|
||||||
| [#91 Platform-neutral mobile contract](https://git.rfc1437.de/hugo/IronStorage/issues/91) | crates/storage and shared UniFFI bridge | Typed semantic actions/icons, opt-in Watch data, platform callbacks, shared Swift/Kotlin inventory tests |
|
| [#91 Platform-neutral mobile contract](https://git.rfc1437.de/hugo/IronStorage/issues/91) | crates/storage and shared UniFFI bridge | Typed semantic actions/icons, opt-in Watch data, platform callbacks, shared Swift/Kotlin inventory tests |
|
||||||
| [#92 Native Rust/UniFFI packaging](https://git.rfc1437.de/hugo/IronStorage/issues/92) | Shared/Android Rust bridge and Gradle rust-bridge | cargo-ndk, generated immutable Kotlin/JNA Android, three ABIs, checksums/16 KB/loading/debug symbols |
|
| [#92 Native Rust/UniFFI packaging](https://git.rfc1437.de/hugo/IronStorage/issues/92) | Shared/Android Rust bridge and Gradle rust-bridge | cargo-ndk, generated immutable Kotlin/JNA Android, three ABIs, checksums/16 KB/loading/debug symbols |
|
||||||
| [#93 Keystore adapter](https://git.rfc1437.de/hugo/IronStorage/issues/93) | crates/storage secure-secret orchestration and platform adapter | Framework Keystore AES-GCM; callback facts, sealed records, invalidation/recovery tests |
|
| [#93 Keystore adapter](https://git.rfc1437.de/hugo/IronStorage/issues/93) | Delivered: Rust sealed-record orchestration and Android OS adapter | [Keystore policy and recovery](keystore.md); native AES-GCM/CryptoObject and Rust lifecycle tests |
|
||||||
| [#94 CI/static analysis/reproducibility](https://git.rfc1437.de/hugo/IronStorage/issues/94) | Build/CI/test infrastructure | Cargo gates, Gradle build/Lint/ktlint, JVM/Compose/instrumented tests, verification/locks/SBOM/ABI checks |
|
| [#94 CI/static analysis/reproducibility](https://git.rfc1437.de/hugo/IronStorage/issues/94) | Build/CI/test infrastructure | Cargo gates, Gradle build/Lint/ktlint, JVM/Compose/instrumented tests, verification/locks/SBOM/ABI checks |
|
||||||
| [#95 Local-first/HTTPS onboarding](https://git.rfc1437.de/hugo/IronStorage/issues/95) | storage mobile_onboarding plus Compose features | Existing Rust initialization/discovery/clone/credentials; no Kotlin transport |
|
| [#95 Local-first/HTTPS onboarding](https://git.rfc1437.de/hugo/IronStorage/issues/95) | storage mobile_onboarding plus Compose features | Existing Rust initialization/discovery/clone/credentials; no Kotlin transport |
|
||||||
| [#96 Hierarchical navigation](https://git.rfc1437.de/hugo/IronStorage/issues/96) | storage mobile_passwords plus Compose features | Material 3 Adaptive list/detail, typed rows/stable IDs |
|
| [#96 Hierarchical navigation](https://git.rfc1437.de/hugo/IronStorage/issues/96) | storage mobile_passwords plus Compose features | Material 3 Adaptive list/detail, typed rows/stable IDs |
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ activation fail instead of consulting HOME, cwd, XDG or public storage.
|
|||||||
| version / device binding | `noBackupFilesDir/ironstorage/layout.toml` | Atomic version 1 marker; unknown versions require a compatible migration |
|
| version / device binding | `noBackupFilesDir/ironstorage/layout.toml` | Atomic version 1 marker; unknown versions require a compatible migration |
|
||||||
| transactional scratch | `noBackupFilesDir/ironstorage/scratch` | Per-owner file locks; startup removes orphaned transactions and skips live owners |
|
| transactional scratch | `noBackupFilesDir/ironstorage/scratch` | Per-owner file locks; startup removes orphaned transactions and skips live owners |
|
||||||
| disposable cache | `cacheDir/ironstorage` | Only this capability is cleared by `clearDisposableCache`; vault/key/catalog data is retained |
|
| disposable cache | `cacheDir/ironstorage` | Only this capability is cleared by `clearDisposableCache`; vault/key/catalog data is retained |
|
||||||
| protected binding and credentials | OS secure backend / no-backup ciphertext (#93) | No serialized token or passphrase in configuration or layout metadata |
|
| protected binding and credentials | Keystore AES-GCM keys / `noBackupFilesDir/ironstorage/secrets` (#93) | No serialized token or passphrase in configuration or layout metadata |
|
||||||
| `filesDir` | OS root fact only | No durable password-store object is placed here |
|
| `filesDir` | OS root fact only | No durable password-store object is placed here |
|
||||||
|
|
||||||
Directory opens use safe Rust `rustix` handles with `NOFOLLOW`; names are single
|
Directory opens use safe Rust `rustix` handles with `NOFOLLOW`; names are single
|
||||||
@@ -45,9 +45,9 @@ links without following their targets and cannot descend into the vault.
|
|||||||
persists only its SHA-256 in layout metadata. A missing or mismatched protected
|
persists only its SHA-256 in layout metadata. A missing or mismatched protected
|
||||||
record for an already bound layout reports `RestoredWithoutKeystore` or
|
record for an already bound layout reports `RestoredWithoutKeystore` or
|
||||||
`InvalidSecureBinding`; it never creates a replacement that would conceal key
|
`InvalidSecureBinding`; it never creates a replacement that would conceal key
|
||||||
loss. Locked/unavailable storage has separate recovery kinds. #93 supplies the
|
loss. Locked/unavailable storage has separate recovery kinds. #93 supplies the [real Android Keystore adapter](keystore.md); startup verifies
|
||||||
real Android Keystore adapter; the contract already executes through the
|
the binding through it before presenting the shell. The contract is tested with
|
||||||
injected backend and is tested with loss/mismatch fixtures.
|
loss/mismatch fixtures.
|
||||||
|
|
||||||
Errors distinguish full storage, read-only storage, access denial, missing
|
Errors distinguish full storage, read-only storage, access denial, missing
|
||||||
roots, concurrent initialization, corrupt configuration/layout and unsupported
|
roots, concurrent initialization, corrupt configuration/layout and unsupported
|
||||||
|
|||||||
@@ -61,6 +61,14 @@ fn harden_source(source: &str) -> Result<String, Box<dyn Error>> {
|
|||||||
}
|
}
|
||||||
let source = source.replace(internal, "class InternalException(@Suppress(\"UNUSED_PARAMETER\") message: String) : kotlin.Exception(\"Native Rust failure ([REDACTED])\")")
|
let source = source.replace(internal, "class InternalException(@Suppress(\"UNUSED_PARAMETER\") message: String) : kotlin.Exception(\"Native Rust failure ([REDACTED])\")")
|
||||||
.replace(callback, "val err = \"Native callback failed ([REDACTED])\"");
|
.replace(callback, "val err = \"Native callback failed ([REDACTED])\"");
|
||||||
|
// Callback results are operation-owned; erase plaintext after copying into the wire buffer.
|
||||||
|
let returned_secret = "val writeReturn = { value: kotlin.ByteArray -> uniffiOutReturn.setValue(FfiConverterByteArray.lower(value)) }";
|
||||||
|
if source.contains("internal object uniffiCallbackInterfaceMobileAndroidKeystore")
|
||||||
|
&& source.matches(returned_secret).count() != 2
|
||||||
|
{
|
||||||
|
return Err("UniFFI secret callback template changed; review byte-array lifetime".into());
|
||||||
|
}
|
||||||
|
let source = source.replace(returned_secret, "val writeReturn = { value: kotlin.ByteArray -> try { uniffiOutReturn.setValue(FfiConverterByteArray.lower(value)) } finally { value.fill(0) } }");
|
||||||
let records = Regex::new(r"(?ms)^([ \t]*)data class (\w+)\s*\((.*?)\)[^\{]*\{\n")?;
|
let records = Regex::new(r"(?ms)^([ \t]*)data class (\w+)\s*\((.*?)\)[^\{]*\{\n")?;
|
||||||
if !records.is_match(&source) {
|
if !records.is_match(&source) {
|
||||||
return Err("UniFFI record template changed; review diagnostic hardening".into());
|
return Err("UniFFI record template changed; review diagnostic hardening".into());
|
||||||
@@ -128,6 +136,21 @@ mod tests {
|
|||||||
assert!(!hardened.contains("kotlin.Exception(message)"));
|
assert!(!hardened.contains("kotlin.Exception(message)"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn erases_owned_callback_results_after_serialization_even_on_failure() {
|
||||||
|
let source = SOURCE.to_owned()
|
||||||
|
+ "val writeReturn = { value: kotlin.ByteArray -> uniffiOutReturn.setValue(FfiConverterByteArray.lower(value)) }";
|
||||||
|
let hardened = harden_source(&source).unwrap();
|
||||||
|
assert!(hardened.contains("finally { value.fill(0) }"));
|
||||||
|
assert!(hardened.contains("FfiConverterByteArray.lower(value)"));
|
||||||
|
assert!(
|
||||||
|
harden_source(
|
||||||
|
&(SOURCE.to_owned()
|
||||||
|
+ "internal object uniffiCallbackInterfaceMobileAndroidKeystore")
|
||||||
|
)
|
||||||
|
.is_err()
|
||||||
|
);
|
||||||
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn fails_closed_if_upstream_templates_or_integrity_checks_change() {
|
fn fails_closed_if_upstream_templates_or_integrity_checks_change() {
|
||||||
assert!(harden_source("data class Secret(val value: String)").is_err());
|
assert!(harden_source("data class Secret(val value: String)").is_err());
|
||||||
|
|||||||
Reference in new issue
Block a user