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
[expo-sqlite] Updated to allow usage with encrypted SQLite files #8242
Conversation
Very important to be resolved for the future of our app roadmap. |
@sjchmiela @mczernek I've gotten the builds succeeding to the best of my abilities. The remaining failures are both due to missing environment variables. Here's the output on CircleCI: #!/bin/bash -eo pipefail
yarn danger ci
yarn run v1.22.4
$ /home/circleci/project/docs/node_modules/.bin/danger ci
The DANGER_GITHUB_API_TOKEN/DANGER_BITBUCKETSERVER_HOST/DANGER_GITLAB_API_TOKEN environmental variable is missing
Without an api token, danger will be unable to comment on a PR
Error: Error: Cannot use authenticated API requests.
at Object.getPlatformForEnv (/home/circleci/project/docs/node_modules/danger/distribution/platforms/platform.js:76:11)
at Object.<anonymous> (/home/circleci/project/docs/node_modules/danger/distribution/commands/ci/runner.js:81:57)
at step (/home/circleci/project/docs/node_modules/danger/distribution/commands/ci/runner.js:32:23)
at Object.next (/home/circleci/project/docs/node_modules/danger/distribution/commands/ci/runner.js:13:53)
at fulfilled (/home/circleci/project/docs/node_modules/danger/distribution/commands/ci/runner.js:4:58)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
Exited with code exit status 1 |
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.
Apart from this couple of comments I'm afraid of:
- app size impact
- WebSQL compatibility — big feature of
expo-sqlite
and Expo modules as a whole is cross-platform compatibility — as far as I know it's currently not possible to use encrypted SQLite databases on Web. What do you think about it @ide?
packages/expo-sqlite/android/src/main/java/expo/modules/sqlite/SQLiteModule.java
Outdated
Show resolved
Hide resolved
Will need to think about the implications some more but I probably won't get around to this soon. Ease of installation and size are both important. Also want to think about the threat model here. Is there a way for an app to say to the OS that all of its data should be encrypted? If so, then encrypting just the SQLite DB is superficial. |
# Why I wanted to clear the way for #8242 to be landed (or not). I noticed that web support doesn't look like it should work and that it isn't tested anywhere. # How - added SQLite test suite to set run on web - changed the way we fetch values in test suite from using `._array[0]` to `.item(0)` - added explanations in `SQLite.types.ts` about why we may need a copy of `@types/websql` - added `Window` declaration to types declarations - removed `@types/websql` dependency as it's not even importable - fixed web counterpart — `SQLite.web.ts` — by fixing the method header and gracefully handling situation where `openDatabase` is not available (I think). # Test Plan Test suite passes.
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.
Thank you for this contribution. A couple of things still left to find out:
- how does this affect app size? If noticeably, we could make it an optional addition
- strip the
key
when run on Web - add tests to
test-suite
run on all platforms that will let us ensure that bothopenDatabase(string)
&openDatabase({…})
work and that an encrypted database is not readable when an invalid key is provided
@@ -81,16 +90,28 @@ function addExecMethod(db: any): WebSQLDatabase { | |||
} | |||
|
|||
export function openDatabase( | |||
name: string, | |||
fileInfo: SQLiteFileInfo | string, |
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.
Could you also add support for this to SQLite.web.ts
so it strips key
from the fileInfo
and uses only name
if an object is provided?
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.
I have made the change, but would appreciate if you could double-check SQLite.web.ts
to see if I did what you were expecting
Do you know of a good way to check this?
I've already added these tests. Is there anything specific that I missed? |
Co-authored-by: Stanisław Chmiela <sjchmiela@users.noreply.github.com>
@sjchmiela Just thought I'd give you a reminder |
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.
When it comes to measuring app size impact:
- first, assemble an APK release of
bare-expo
onmaster
, without your changes (you may need to use some temporary key to sign the app) - then, assemble an APK release of
bare-expo
on your branch, with the changes - see the difference in APK sizes
- in Xcode — archive the project on
master
, note the size of thexcarchive
- archive the project on your branch, see the difference.
Sorry for the delay! 😕
@@ -1,2 +1,11 @@ | |||
export const { openDatabase } = global; | |||
export function openDatabase(fileInfo, ...args) { |
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.
Ah, so… could you please rebase this PR on top of master
? Before getting back to you I've ensured that SQLite works on Web properly and changed this file a little bit — #8518.
@@ -58,6 +58,14 @@ - (NSValue *)openDatabase:(NSString *)dbName | |||
if (sqlite3_open([path UTF8String], &db) != SQLITE_OK) { | |||
return nil; | |||
}; | |||
|
|||
if (!dbKey) { |
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.
if (!dbKey) { | |
if (dbKey) { |
Sorry for making that suggestion before — I misunderstood dbKey != NULL
and proposed !dbKey
changing the if
completely. dbKey != NULL
means if dbKey is non-empty
which should translate to Obj-C-y if (dbKey)
(if dbKey is truthy
)
|
||
if (!dbKey) { | ||
const char *key = [dbKey UTF8String]; | ||
if (!key) { |
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.
if (!key) { | |
if (key) { |
@sjchmiela I'm running into too many issues when trying to build the app. I think it might be easier if someone who already has expo properly set up could do it. I've put up comment asking someone to help on https://expo.canny.io/feature-requests/p/sqlite-encrypted-database, but I'm not sure how soon we can get someone to do it. |
@sjchmiela I managed to work through the issues I faced building the apps. Here is what I found:
I can go through and rebase the PR off of the latest commit in |
A 14% increase is probably too much, especially coming from a proprietary library that we'll end up wanting to remove. I think the path forward is to use the OS's own encryption capabilities where possible. For example, this might be the appropriate approach on iOS: https://developer.apple.com/documentation/uikit/protecting_the_user_s_privacy/encrypting_your_app_s_files. Android also has some disk encryption too: https://source.android.com/security/encryption/file-based. The threat model we'd consider is an attacker getting physical access to someone else's device, especially if the device is off. We can't really prevent a user accessing data on their own device and consider that scenario to be out of scope. Fundamentally speaking, if an app has access to data, then the user using that app has access to the data -- to prevent a user from accessing data, it needs not to be sent to the device in the first place. The disk-level encryption on Android and iOS seem reasonable to adopt. Perhaps we need to identify a set of options that work across platforms (e.g. disallow access until first unlock) that map to Android and iOS's options, and then create a universal API to expose those options and apply them to the SQLite file. |
Though I would say that there definitely are reasons to encrypt the sqlite DB itself, I do understand how the app size increase is problematic. Anyways, thanks for entertaining the possibility of adding this feature. Guess we'll just have to use a bare workflow. |
Why
There is a need to be able to use encrypted SQLite files in Expo as expressed in several places, like: Expo feature requests (Canny), the Expo forums, StackOverflow, etc.
Here's a few examples:
https://expo.canny.io/feature-requests/p/sqlite-encrypted-database
https://forums.expo.io/t/expo-sqlite-encrypted-support/19493
https://forums.expo.io/t/storing-sqlite-file-securely/10377
https://stackoverflow.com/questions/58688148/encrypt-database-in-react-with-expo
How
In order to be able to use encrypted databases, I integrated SQLCipher into the existing
expo-sqlite
package.Test Plan
I've tested added tests, but sadly I wasn't able to run them properly on my machine. I think there was some sort of clash with the installed Expo Client. I'd appreciate if someone could confirm that these work as expected.
Along with tests, I managed to get this to work with a personal project and the expo examples/with-sqlite project (though I had to eject to be able to use my updated package).