Skip to content

Commit cc7d1ba

Browse files
authored
Merge pull request #1 from journeyapps/chore/16kb-support
[Chore] 16KB Support
2 parents f1f2c88 + 921c876 commit cc7d1ba

File tree

6 files changed

+171
-37
lines changed

6 files changed

+171
-37
lines changed

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"name": "cordova-sqlcipher-adapter",
3-
"version": "0.6.0",
2+
"name": "@journeyapps/cordova-sqlcipher-adapter",
3+
"version": "0.6.0-journey3",
44
"description": "SQLCipher database adapter for PhoneGap/Cordova, based on cordova-sqlite-storage",
55
"cordova": {
66
"id": "cordova-sqlcipher-adapter",
@@ -13,7 +13,7 @@
1313
},
1414
"repository": {
1515
"type": "git",
16-
"url": "https://github.com/brodybits/cordova-sqlcipher-adapter.git"
16+
"url": "git+https://github.com/journeyapps/cordova-sqlcipher-adapter.git"
1717
},
1818
"keywords": [
1919
"sqlite",
@@ -27,9 +27,9 @@
2727
"author": "various",
2828
"license": "MIT",
2929
"bugs": {
30-
"url": "https://github.com/brodybits/cordova-sqlcipher-adapter/issues"
30+
"url": "https://github.com/journeyapps/cordova-sqlcipher-adapter/issues"
3131
},
32-
"homepage": "https://github.com/brodybits/cordova-sqlcipher-adapter",
32+
"homepage": "https://github.com/journeyapps/cordova-sqlcipher-adapter",
3333
"scripts": {
3434
"clean-spec": "rm -rf spec/[mnp]* && git checkout -- spec/package.json && git status --ignored",
3535
"prepare-js": "coffee -p SQLitePlugin.coffee.md > www/SQLitePlugin.js",

plugin.xml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<plugin xmlns="http://www.phonegap.com/ns/plugins/1.0"
3-
xmlns:android="http://schemas.android.com/apk/res/android"
4-
id="cordova-sqlcipher-adapter"
5-
version="0.6.0">
3+
xmlns:android="http://schemas.android.com/apk/res/android"
4+
id="cordova-sqlcipher-adapter"
5+
version="0.6.0-journey3">
66

77
<name>Cordova sqlcipher adapter</name>
88

@@ -42,9 +42,10 @@
4242
<source-file src="node_modules/cordova-sqlite-storage-dependencies/libs/sqlite-connector.jar" target-dir="libs"/>
4343
...
4444
-->
45-
<lib-file src="src/android/libs/android-database-sqlcipher.jar" />
4645
<!-- androidx.sqlite now required -->
47-
<framework src="androidx.sqlite:sqlite:2.1.0" />
46+
<!-- https://mvnrepository.com/artifact/net.zetetic/sqlcipher-android -->
47+
<framework src="net.zetetic:sqlcipher-android:4.10.0" />
48+
<framework src="androidx.sqlite:sqlite:2.2.0" />
4849

4950
<!-- [FUTURE TBD] consider using external aar again -->
5051
<!-- THANKS to @jcesarmobile for GUIDANCE in accepted answer:

src/android/io/sqlc/SQLiteAndroidDatabase.java

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@
77
package io.sqlc;
88

99
// SQLCipher version of database classes:
10-
import net.sqlcipher.*;
11-
import net.sqlcipher.database.*;
10+
import net.zetetic.database.*;
11+
import net.zetetic.database.sqlcipher.*;
12+
import android.database.Cursor;
13+
import android.database.sqlite.SQLiteConstraintException;
14+
import android.database.sqlite.SQLiteException;
1215

1316
/* ** NOT USED in this plugin version:
1417
import android.database.Cursor;
@@ -73,7 +76,7 @@ class SQLiteAndroidDatabase
7376
//@Override
7477
static
7578
public void initialize(CordovaInterface cordova) {
76-
SQLiteDatabase.loadLibs(cordova.getActivity());
79+
System.loadLibrary("sqlcipher");
7780
}
7881

7982
/**
@@ -83,7 +86,35 @@ public void initialize(CordovaInterface cordova) {
8386
* @param dbfile The database File specification
8487
*/
8588
void open(File dbfile, String key) throws Exception {
86-
mydb = SQLiteDatabase.openOrCreateDatabase(dbfile, key, null);
89+
mydb = SQLiteDatabase.openOrCreateDatabase(dbfile, key, null, null);
90+
}
91+
92+
/**
93+
*
94+
* Open a database.
95+
*
96+
* @param dbfile The database File specification
97+
*/
98+
void open(File dbfile, String key, boolean cipherMigrate) throws Exception {
99+
try {
100+
mydb = SQLiteDatabase.openOrCreateDatabase(dbfile, key, null, null);
101+
} catch (RuntimeException e) {
102+
if (cipherMigrate) {
103+
mydb = SQLiteDatabase.openOrCreateDatabase(dbfile, key, null, null, new SQLiteDatabaseHook() {
104+
@Override
105+
public void preKey(SQLiteConnection sqLiteConnection) {
106+
107+
}
108+
109+
@Override
110+
public void postKey(SQLiteConnection sqLiteConnection) {
111+
sqLiteConnection.execute("PRAGMA cipher_migrate", null, null);
112+
}
113+
});
114+
} else {
115+
throw e;
116+
}
117+
}
87118
}
88119

89120
/**

src/android/io/sqlc/SQLitePlugin.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ private void startDatabase(String dbname, JSONObject options, CallbackContext cb
211211
*
212212
* @param dbName The name of the database file
213213
*/
214-
private SQLiteAndroidDatabase openDatabase(String dbname, String key, CallbackContext cbc, boolean old_impl) throws Exception {
214+
private SQLiteAndroidDatabase openDatabase(String dbname, String key, CallbackContext cbc, boolean cipherMigrate) throws Exception {
215215
try {
216216
// ASSUMPTION: no db (connection/handle) is already stored in the map
217217
// [should be true according to the code in DBRunner.run()]
@@ -225,7 +225,7 @@ private SQLiteAndroidDatabase openDatabase(String dbname, String key, CallbackCo
225225
Log.v("info", "Open sqlite db: " + dbfile.getAbsolutePath());
226226

227227
SQLiteAndroidDatabase mydb = new SQLiteAndroidDatabase();
228-
mydb.open(dbfile, key);
228+
mydb.open(dbfile, key, cipherMigrate);
229229

230230
// NOTE: NO Android locking/closing BUG workaround needed here
231231
cbc.success();
@@ -322,6 +322,7 @@ private boolean deleteDatabaseNow(String dbname) {
322322
private class DBRunner implements Runnable {
323323
final String dbname;
324324
final String dbkey;
325+
final boolean cipherMigrate;
325326

326327
final BlockingQueue<DBQuery> q;
327328
final CallbackContext openCbc;
@@ -342,13 +343,24 @@ private class DBRunner implements Runnable {
342343
}
343344
this.dbkey = key;
344345

346+
boolean cipherMigrate = false;
347+
if (options.has("cipherMigrate")) {
348+
try {
349+
cipherMigrate = options.getBoolean("cipherMigrate");
350+
} catch (JSONException e) {
351+
// NOTE: this should not happen!
352+
Log.e(SQLitePlugin.class.getSimpleName(), "unexpected JSON error getting password cipherMigrate, ignored", e);
353+
}
354+
}
355+
this.cipherMigrate = cipherMigrate;
356+
345357
this.q = new LinkedBlockingQueue<DBQuery>();
346358
this.openCbc = cbc;
347359
}
348360

349361
public void run() {
350362
try {
351-
this.mydb = openDatabase(dbname, this.dbkey, this.openCbc, false);
363+
this.mydb = openDatabase(dbname, this.dbkey, this.openCbc, this.cipherMigrate);
352364
} catch (Exception e) {
353365
Log.e(SQLitePlugin.class.getSimpleName(), "unexpected error, stopping db thread", e);
354366
dbrmap.remove(dbname);
-5.6 MB
Binary file not shown.

src/ios/SQLitePlugin.m

Lines changed: 110 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -178,34 +178,33 @@ -(void)openNow: (CDVInvokedUrlCommand*)command
178178
// NOTE: create DB from resource [pre-populated] NOT supported with sqlcipher.
179179

180180
if (sqlite3_open(name, &db) != SQLITE_OK) {
181+
[self logSqlError:db message:@"Unable to open DB"];
181182
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Unable to open DB"];
182183
[self.commandDelegate sendPluginResult:pluginResult callbackId: command.callbackId];
183-
return;
184184
} else {
185-
sqlite3_db_config(db, SQLITE_DBCONFIG_DEFENSIVE, 1, NULL);
186-
187-
#if 0
188-
sqlite3_create_function(db, "REGEXP", 2, SQLITE_ANY, NULL, &sqlite_regexp, NULL, NULL);
189-
#endif
190-
191-
// SQLCipher key:
192-
NSString *dbkey = [options objectForKey:@"key"];
193-
const char *key = NULL;
194-
if (dbkey != NULL && dbkey.length != 0) key = [dbkey UTF8String];
195-
NSLog((key != NULL) ? @"Open DB with encryption" : @"Open DB with NO encryption");
196-
if (key != NULL) sqlite3_key(db, key, strlen(key));
197-
185+
[self prepareDatabase:db options:options];
198186
// XXX Brody TODO check this in Javascript instead.
199187
// Attempt to read the SQLite master table [to support SQLCipher version]:
200-
if(sqlite3_exec(db, (const char*)"SELECT count(*) FROM sqlite_master;", NULL, NULL, NULL) == SQLITE_OK) {
201-
NSLog(@"DB open, check sqlite master table OK");
202-
dbPointer = [NSValue valueWithPointer:db];
203-
[openDBs setObject: dbPointer forKey: dbfilename];
188+
189+
Boolean databaseCheck = NO;
190+
if ([self checkDatabaseConnection: db dbfilename: dbfilename]) {
191+
databaseCheck = YES;
192+
} else {
193+
NSString *sCipherMigrate = [options objectForKey:@"cipherMigrate"];
194+
Boolean cipherMigrate = sCipherMigrate ? [sCipherMigrate boolValue] : NO;
195+
196+
if (cipherMigrate) {
197+
db = [self executeCipherMigration:db name:name options:options];
198+
if (db != NULL) {
199+
databaseCheck = [self checkDatabaseConnection: db dbfilename: dbfilename];
200+
}
201+
}
202+
}
203+
204+
if (databaseCheck) {
204205
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:@"Database opened"];
205206
} else {
206-
NSLog(@"ERROR reading sqlite master table");
207207
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Unable to open DB with key"];
208-
// XXX TODO: close the db handle & [perhaps] remove from openDBs!!
209208
}
210209
}
211210
}
@@ -216,6 +215,97 @@ -(void)openNow: (CDVInvokedUrlCommand*)command
216215
// DLog(@"open cb finished ok");
217216
}
218217

218+
-(Boolean) prepareDatabase: (sqlite3*) db options: (NSMutableDictionary*) options
219+
{
220+
sqlite3_db_config(db, SQLITE_DBCONFIG_DEFENSIVE, 1, NULL);
221+
222+
#if 0
223+
sqlite3_create_function(db, "REGEXP", 2, SQLITE_ANY, NULL, &sqlite_regexp, NULL, NULL);
224+
#endif
225+
226+
// SQLCipher key:
227+
NSString *dbkey = [options objectForKey:@"key"];
228+
const char *key = NULL;
229+
if (dbkey != NULL && dbkey.length != 0) key = [dbkey UTF8String];
230+
NSLog((key != NULL) ? @"Open DB with encryption" : @"Open DB with NO encryption");
231+
if (key != NULL) {
232+
if (sqlite3_key(db, key, strlen(key)) != SQLITE_OK) {
233+
[self logSqlError: db message: @"Error setting key: "];
234+
return NO;
235+
}
236+
}
237+
238+
return YES;
239+
}
240+
241+
-(sqlite3*) reopenDatabase: (sqlite3*) db name: (const char *) name options: (NSMutableDictionary*) options
242+
{
243+
sqlite3_close(db);
244+
245+
sqlite3* newDb;
246+
247+
if (sqlite3_open(name, &newDb) != SQLITE_OK) {
248+
[self logSqlError:db message:@"Unable to open DB"];
249+
return NULL;
250+
} else {
251+
[self prepareDatabase:newDb options:options];
252+
return newDb;
253+
}
254+
}
255+
256+
-(sqlite3*) executeCipherMigration: (sqlite3*) db name: (const char *) name options: (NSMutableDictionary*) options
257+
{
258+
db = [self reopenDatabase:db name:name options:options];
259+
if (db == NULL) {
260+
NSLog(@"%@", @"Unable to reopen database for cipher migration");
261+
return NULL;
262+
} else {
263+
sqlite3_stmt *statement;
264+
265+
sqlite3_prepare_v2(db, "PRAGMA CIPHER_MIGRATE", -1, &statement, NULL);
266+
267+
while (sqlite3_step(statement) == SQLITE_ROW) {
268+
NSString *result = [[NSString alloc] initWithUTF8String:
269+
(const char *) sqlite3_column_text(statement, 0)];
270+
NSLog(@"%@%@", @"Pragma migrate: ", result);
271+
}
272+
273+
if (sqlite3_finalize(statement) != SQLITE_OK) {
274+
[self logSqlError:db message:@"Unable to finalize cipher migrate statement: "];
275+
return NULL;
276+
}
277+
278+
db = [self reopenDatabase:db name:name options:options];
279+
if (db == NULL) {
280+
NSLog(@"%@", @"Unable to reopen database after cipher migration");
281+
return NULL;
282+
} else {
283+
return db;
284+
}
285+
}
286+
}
287+
288+
-(void) logSqlError: (sqlite3*)db message:(NSString*) message
289+
{
290+
const char *errmsg = sqlite3_errmsg(db);
291+
NSLog(@"%@%@", message, [NSString stringWithUTF8String:errmsg]);
292+
}
293+
294+
-(Boolean) checkDatabaseConnection: (sqlite3*)db dbfilename: (NSString*) dbfilename
295+
{
296+
int checkResult = sqlite3_exec(db, (const char*)"SELECT count(*) FROM sqlite_master;", NULL, NULL, NULL);
297+
298+
if (checkResult == SQLITE_OK) {
299+
NSLog(@"DB open, check sqlite master table OK");
300+
NSValue *dbPointer = [NSValue valueWithPointer:db];
301+
[openDBs setObject: dbPointer forKey: dbfilename];
302+
return YES;
303+
} else {
304+
[self logSqlError: db message: @"Error checking connection: "];
305+
return NO;
306+
}
307+
}
308+
219309
-(void) close: (CDVInvokedUrlCommand*)command
220310
{
221311
[self.commandDelegate runInBackground:^{

0 commit comments

Comments
 (0)