-
Notifications
You must be signed in to change notification settings - Fork 642
Use Device Encrypted storage context for locked state #7477
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -150,9 +150,7 @@ internal interface FirebaseSessionsComponent { | |
}, | ||
scope = CoroutineScope(blockingDispatcher), | ||
produceFile = { | ||
appContext.dataStoreFile("firebaseSessions/sessionConfigsDataStore.data").also { | ||
prepDataStoreFile(it) | ||
} | ||
produceFile(appContext, "firebaseSessions/sessionConfigsDataStore.data") | ||
}, | ||
) | ||
|
||
|
@@ -172,12 +170,22 @@ internal interface FirebaseSessionsComponent { | |
}, | ||
scope = CoroutineScope(blockingDispatcher), | ||
produceFile = { | ||
appContext.dataStoreFile("firebaseSessions/sessionDataStore.data").also { | ||
prepDataStoreFile(it) | ||
} | ||
produceFile(appContext, "firebaseSessions/sessionDataStore.data") | ||
}, | ||
) | ||
|
||
|
||
private fun produceFile(appContext: Context, fileName: String): File { | ||
val deContext = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { | ||
appContext.createDeviceProtectedStorageContext() | ||
} else { | ||
appContext | ||
} | ||
return deContext.dataStoreFile(fileName).also { | ||
prepDataStoreFile(it) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The prepDataStoreFile thing didn't work, we can just remove this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd like to keep it, since it contains validations to check if the parent path is a directory or not and also delete it if it is not a directory |
||
} | ||
} | ||
|
||
private fun <T> createDataStore( | ||
serializer: Serializer<T>, | ||
corruptionHandler: ReplaceFileCorruptionHandler<T>, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any consequences to using the DE storage permanently? After the device is unlocked, should there be some flow to move to CE storage?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any consequences to using the DE storage permanently?
Some research:
Reduced Security | This is the most critical consequence. Data in DE storage is encrypted, but the key is tied to the device hardware, not the user's PIN, password, or pattern. If a malicious actor gains physical access to the device and can bypass the lock screen through a software vulnerability (or has advanced forensic tools), they may be able to extract the contents of DE storage. In contrast, Credential Encrypted (CE) storage would remain safely encrypted.
No Real Performance Benefit | After the device is unlocked, there is no performance advantage to using DE storage over CE storage. Both are simply mounted file systems. The only benefit of DE storage is its availability before the first unlock.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After the device is unlocked, should there be some flow to move to CE storage?
We can use a "data handoff" strategy:
On Boot (Before Unlock): Use createDeviceProtectedStorageContext() to write essential, non-sensitive data required for immediate operation.
After User Unlocks: The Android system sends a broadcast action,
ACTION_USER_UNLOCKED
.Once the SDK receives the ACTION_USER_UNLOCKED broadcast
• Read the temporary data from DE storage.
• Migrate or merge this data into your main data store located in the now-accessible CE storage.
• FIND A WAY TO NOTIFY DATASTORE TO USE THE NEW LOCATION
• Delete the temporary data from DE storage to ensure it's not left behind.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Research update:
A DataStore instance is fundamentally tied to the file it was created with. The file path is provided once during initialization (via the produceFile lambda in your code) and is considered immutable for the lifetime of that singleton DataStore object.
The "correct approach" might be to use 2 instances of DataStores, one for DE and other for CE, after receiving the
ACTION_USER_UNLOCKED
broadcast