diff --git a/Jenkinsfile b/Jenkinsfile index b2aecd67..4ce4c86d 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,5 +1,5 @@ library 'pipeline-library' buildModule { - sdkVersion = '7.5.2.GA' + sdkVersion = '8.2.0.GA' } diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml new file mode 100644 index 00000000..6e7e6e7c --- /dev/null +++ b/android/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/android/encrypteddatabase.iml b/android/encrypteddatabase.iml new file mode 100644 index 00000000..0b5476c4 --- /dev/null +++ b/android/encrypteddatabase.iml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/lib/sqlcipher.jar b/android/lib/sqlcipher.jar index 9da61c75..200330e8 100644 Binary files a/android/lib/sqlcipher.jar and b/android/lib/sqlcipher.jar differ diff --git a/android/libs/arm64-v8a/libsqlcipher.so b/android/libs/arm64-v8a/libsqlcipher.so index a92c5de8..f81c8e20 100644 Binary files a/android/libs/arm64-v8a/libsqlcipher.so and b/android/libs/arm64-v8a/libsqlcipher.so differ diff --git a/android/libs/armeabi-v7a/libsqlcipher.so b/android/libs/armeabi-v7a/libsqlcipher.so index adfec7a0..ff661db5 100644 Binary files a/android/libs/armeabi-v7a/libsqlcipher.so and b/android/libs/armeabi-v7a/libsqlcipher.so differ diff --git a/android/libs/x86/libsqlcipher.so b/android/libs/x86/libsqlcipher.so index 140a7125..41ea2b16 100644 Binary files a/android/libs/x86/libsqlcipher.so and b/android/libs/x86/libsqlcipher.so differ diff --git a/android/manifest b/android/manifest index 7dad753b..15bb673d 100644 --- a/android/manifest +++ b/android/manifest @@ -2,7 +2,7 @@ # this is your module manifest and used by Titanium # during compilation, packaging, distribution, etc. # -version: 3.0.4 +version: 3.1.0 apiversion: 4 architectures: arm64-v8a armeabi-v7a x86 description: Provides transparent, secure 256-bit AES encryption of SQLite database files. diff --git a/android/src/appcelerator/encrypteddatabase/EncrypteddatabaseModule.java b/android/src/appcelerator/encrypteddatabase/EncrypteddatabaseModule.java index e947699b..f0422c96 100644 --- a/android/src/appcelerator/encrypteddatabase/EncrypteddatabaseModule.java +++ b/android/src/appcelerator/encrypteddatabase/EncrypteddatabaseModule.java @@ -21,13 +21,13 @@ import org.appcelerator.titanium.TiFileProxy; import org.appcelerator.titanium.io.TiBaseFile; import org.appcelerator.titanium.io.TiFileFactory; -import org.appcelerator.titanium.util.TiConvert; import org.appcelerator.titanium.util.TiUrl; -import android.app.Activity; import android.content.Context; + import net.sqlcipher.SQLException; import net.sqlcipher.database.SQLiteDatabase; +import net.sqlcipher.database.SQLiteDatabaseHook; @Kroll.module(name = "Encrypteddatabase", id = "appcelerator.encrypteddatabase") public class EncrypteddatabaseModule extends KrollModule { @@ -64,6 +64,15 @@ public void setPassword(String value) { public TiDatabaseProxy open(Object file) { // Attempt to create/open the given database file/name. TiDatabaseProxy dbp = null; + + // Migrate database if necessary. + final SQLiteDatabaseHook migrationHook = new SQLiteDatabaseHook() { + public void preKey(SQLiteDatabase database) {} + public void postKey(SQLiteDatabase database) { + database.rawExecSQL("PRAGMA cipher_migrate;"); + } + }; + if (file instanceof TiFileProxy) { // File support is read-only for now. The NO_LOCALIZED_COLLATORS // flag means the database doesn't have Android metadata (i.e. @@ -73,7 +82,7 @@ public TiDatabaseProxy open(Object file) { Log.d(TAG, "Opening database from filesystem: " + absolutePath); SQLiteDatabase db = SQLiteDatabase.openDatabase(absolutePath, getPassword(), null, - SQLiteDatabase.OPEN_READONLY | SQLiteDatabase.NO_LOCALIZED_COLLATORS); + SQLiteDatabase.OPEN_READONLY | SQLiteDatabase.NO_LOCALIZED_COLLATORS, migrationHook); if (db != null) { dbp = new TiDatabaseProxy(db); } else { @@ -83,7 +92,7 @@ public TiDatabaseProxy open(Object file) { String name = (String) file; File dbPath = TiApplication.getInstance().getDatabasePath(name); dbPath.getParentFile().mkdirs(); - SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(dbPath, getPassword(), null); + SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(dbPath, getPassword(), null, migrationHook); if (db != null) { dbp = new TiDatabaseProxy(name, db); } else { diff --git a/android/src/appcelerator/encrypteddatabase/TiResultSetProxy.java b/android/src/appcelerator/encrypteddatabase/TiResultSetProxy.java index f8a902ca..8fd94cf9 100644 --- a/android/src/appcelerator/encrypteddatabase/TiResultSetProxy.java +++ b/android/src/appcelerator/encrypteddatabase/TiResultSetProxy.java @@ -14,7 +14,7 @@ import org.appcelerator.titanium.util.TiConvert; import android.database.Cursor; -import net.sqlcipher.CrossProcessCursorWrapper; +import net.sqlcipher.AbstractWindowedCursor; import net.sqlcipher.SQLException; import android.os.Build; @@ -95,16 +95,16 @@ private Object internalGetField(int index, int type) { boolean fromString = false; try { - if (rs instanceof CrossProcessCursorWrapper) { - CrossProcessCursorWrapper cursor = (CrossProcessCursorWrapper) rs; - int columnType = cursor.getType(index); - if (columnType == android.database.Cursor.FIELD_TYPE_FLOAT) { + if (rs instanceof AbstractWindowedCursor) { + AbstractWindowedCursor cursor = (AbstractWindowedCursor) rs; + + if (cursor.isFloat(index)) { result = cursor.getDouble(index); - } else if (columnType == android.database.Cursor.FIELD_TYPE_INTEGER) { + } else if (cursor.isLong(index)) { result = cursor.getLong(index); - } else if (columnType == android.database.Cursor.FIELD_TYPE_NULL) { + } else if (cursor.isNull(index)) { result = null; - } else if (columnType == android.database.Cursor.FIELD_TYPE_BLOB) { + } else if (cursor.isBlob(index)) { result = TiBlob.blobFromData(cursor.getBlob(index)); } else { fromString = true; @@ -123,11 +123,9 @@ private Object internalGetField(int index, int type) { throw new IllegalStateException("Requested column number " + index + " does not exist"); } } catch (RuntimeException e) { - // Both SQLException and IllegalStateException (exceptions known to - // occur + // Both SQLException and IllegalStateException (exceptions known to occur // in this block) are RuntimeExceptions and since we anyway re-throw - // and log the same error message, we're just catching all - // RuntimeExceptions. + // and log the same error message, we're just catching all RuntimeExceptions. Log.e(TAG, "Exception getting value for column " + index + ": " + e.getMessage(), e); throw e; } @@ -139,7 +137,7 @@ private Object internalGetField(int index, int type) { } break; case EncrypteddatabaseModule.FIELD_TYPE_INT: - if (!(result instanceof Integer)) { + if (!(result instanceof Integer) && !(result instanceof Long)) { result = TiConvert.toInt(result); } break; diff --git a/test/unit/specs/int.boundary.spec.js b/test/unit/specs/int.boundary.spec.js index 0a25fe5b..3e98984f 100644 --- a/test/unit/specs/int.boundary.spec.js +++ b/test/unit/specs/int.boundary.spec.js @@ -42,7 +42,7 @@ describe('appcelerator.encrypteddatabase', function () { const resultSet = dbConnection.execute('SELECT id, intValue FROM intTable ORDER BY id'); expect(resultSet.rowCount).toEqual(rows.length); for (let index = 0; resultSet.isValidRow(); resultSet.next(), index++) { - expect(resultSet.field(1)).toEqual(rows[index]); + expect(parseInt(resultSet.field(1))).toEqual(rows[index]); } dbConnection.close(); });