@capacitor-community/sqlite 5.0.8 → 5.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -451,6 +451,7 @@ public class CapacitorSQLite {
451
451
  throw new Exception(msg);
452
452
  }
453
453
  }
454
+
454
455
  /**
455
456
  * BeginTransaction
456
457
  *
@@ -466,7 +467,7 @@ public class CapacitorSQLite {
466
467
  if (db != null) {
467
468
  if (!db.isNCDB() && db.isOpen()) {
468
469
  try {
469
- Integer res = db.beginTransaction();
470
+ Integer res = db.beginTransaction();
470
471
  retObj.put("changes", res);
471
472
  return retObj;
472
473
  } catch (Exception e) {
@@ -497,7 +498,7 @@ public class CapacitorSQLite {
497
498
  if (db != null) {
498
499
  if (!db.isNCDB() && db.isOpen()) {
499
500
  try {
500
- Integer res = db.commitTransaction();
501
+ Integer res = db.commitTransaction();
501
502
  retObj.put("changes", res);
502
503
  return retObj;
503
504
  } catch (Exception e) {
@@ -528,7 +529,7 @@ public class CapacitorSQLite {
528
529
  if (db != null) {
529
530
  if (!db.isNCDB() && db.isOpen()) {
530
531
  try {
531
- Integer res = db.rollbackTransaction();
532
+ Integer res = db.rollbackTransaction();
532
533
  retObj.put("changes", res);
533
534
  return retObj;
534
535
  } catch (Exception e) {
@@ -563,7 +564,6 @@ public class CapacitorSQLite {
563
564
  } catch (Exception e) {
564
565
  throw new Exception(e.getMessage());
565
566
  }
566
-
567
567
  } else {
568
568
  String msg = "database " + dbName + " not opened";
569
569
  throw new Exception(msg);
@@ -1269,8 +1269,7 @@ public class CapacitorSQLite {
1269
1269
  }
1270
1270
  }
1271
1271
 
1272
- public JSObject exportToJson(String dbName, String expMode,
1273
- Boolean readonly, Boolean encrypted) throws Exception {
1272
+ public JSObject exportToJson(String dbName, String expMode, Boolean readonly, Boolean encrypted) throws Exception {
1274
1273
  dbName = getDatabaseName(dbName);
1275
1274
  String connName = readonly ? "RO_" + dbName : "RW_" + dbName;
1276
1275
  Database db = dbDict.get(connName);
@@ -9,6 +9,8 @@ import com.getcapacitor.PluginCall;
9
9
  import com.getcapacitor.PluginMethod;
10
10
  import com.getcapacitor.annotation.CapacitorPlugin;
11
11
  import com.getcapacitor.community.database.sqlite.SQLite.SqliteConfig;
12
+ import java.util.ArrayList;
13
+ import java.util.Arrays;
12
14
  import java.util.Collections;
13
15
  import java.util.Dictionary;
14
16
  import java.util.Hashtable;
@@ -28,6 +30,9 @@ public class CapacitorSQLitePlugin extends Plugin {
28
30
  private String passphrase = null;
29
31
  private String oldpassphrase = null;
30
32
  private String loadMessage = "";
33
+ private final ArrayList<String> modeList = new ArrayList<>(
34
+ Arrays.asList("no-encryption", "encryption", "secret", "decryption", "wrongsecret")
35
+ );
31
36
 
32
37
  /**
33
38
  * Load Method
@@ -287,12 +292,9 @@ public class CapacitorSQLitePlugin extends Plugin {
287
292
  Boolean encrypted = call.getBoolean("encrypted", false);
288
293
  if (encrypted) {
289
294
  inMode = call.getString("mode", "no-encryption");
290
- if (
291
- !inMode.equals("no-encryption") && !inMode.equals("encryption") && !inMode.equals("secret") && !inMode.equals("wrongsecret")
292
- ) {
295
+ if (!modeList.contains(inMode)) {
293
296
  String msg = "CreateConnection: inMode must ";
294
- msg += "be in ['encryption','secret'] ";
295
- msg += "** 'newsecret' has been deprecated";
297
+ msg += "be in ['encryption','secret', 'decryption'] ";
296
298
  rHandler.retResult(call, null, msg);
297
299
  return;
298
300
  }
@@ -369,6 +371,7 @@ public class CapacitorSQLitePlugin extends Plugin {
369
371
  rHandler.retResult(call, null, loadMessage);
370
372
  }
371
373
  }
374
+
372
375
  /**
373
376
  * BeginTransaction Method
374
377
  * Begin a Database Transaction
@@ -398,6 +401,7 @@ public class CapacitorSQLitePlugin extends Plugin {
398
401
  rHandler.retChanges(call, retRes, loadMessage);
399
402
  }
400
403
  }
404
+
401
405
  /**
402
406
  * CommitTransaction Method
403
407
  * Commit a Database Transaction
@@ -457,6 +461,7 @@ public class CapacitorSQLitePlugin extends Plugin {
457
461
  rHandler.retChanges(call, retRes, loadMessage);
458
462
  }
459
463
  }
464
+
460
465
  /**
461
466
  * IsTransactionActive Method
462
467
  * Check if a Database Transaction is Active
@@ -482,6 +487,7 @@ public class CapacitorSQLitePlugin extends Plugin {
482
487
  rHandler.retResult(call, null, loadMessage);
483
488
  }
484
489
  }
490
+
485
491
  /**
486
492
  * GetUrl Method
487
493
  * Get a database Url
@@ -1452,8 +1458,7 @@ public class CapacitorSQLitePlugin extends Plugin {
1452
1458
 
1453
1459
  if (implementation != null) {
1454
1460
  try {
1455
- JSObject res = implementation.exportToJson(dbName, expMode,
1456
- readOnly, encrypted);
1461
+ JSObject res = implementation.exportToJson(dbName, expMode, readOnly, encrypted);
1457
1462
  rHandler.retJSObject(call, res, null);
1458
1463
  } catch (Exception e) {
1459
1464
  String msg = "ExportToJson: " + e.getMessage();
@@ -144,6 +144,7 @@ public class Database {
144
144
  public boolean isAvailTrans() {
145
145
  return _db.inTransaction();
146
146
  }
147
+
147
148
  /**
148
149
  * BeginTransaction method
149
150
  *
@@ -152,7 +153,7 @@ public class Database {
152
153
  public Integer beginTransaction() throws Exception {
153
154
  if (_db.isOpen()) {
154
155
  try {
155
- if( isAvailTrans()) {
156
+ if (isAvailTrans()) {
156
157
  throw new Exception("Already in transaction");
157
158
  }
158
159
  _db.beginTransaction();
@@ -165,8 +166,8 @@ public class Database {
165
166
  } else {
166
167
  throw new Exception("Database not opened");
167
168
  }
168
-
169
169
  }
170
+
170
171
  /**
171
172
  * CommitTransaction method
172
173
  *
@@ -175,7 +176,7 @@ public class Database {
175
176
  public Integer commitTransaction() throws Exception {
176
177
  if (_db.isOpen()) {
177
178
  try {
178
- if(!isAvailTrans()) {
179
+ if (!isAvailTrans()) {
179
180
  throw new Exception("No transaction active");
180
181
  }
181
182
  _db.setTransactionSuccessful();
@@ -188,7 +189,6 @@ public class Database {
188
189
  } else {
189
190
  throw new Exception("Database not opened");
190
191
  }
191
-
192
192
  }
193
193
 
194
194
  /**
@@ -199,7 +199,7 @@ public class Database {
199
199
  public Integer rollbackTransaction() throws Exception {
200
200
  if (_db.isOpen()) {
201
201
  try {
202
- if( isAvailTrans()) {
202
+ if (isAvailTrans()) {
203
203
  _db.endTransaction();
204
204
  }
205
205
  return 0;
@@ -211,7 +211,6 @@ public class Database {
211
211
  } else {
212
212
  throw new Exception("Database not opened");
213
213
  }
214
-
215
214
  }
216
215
 
217
216
  /**
@@ -233,7 +232,7 @@ public class Database {
233
232
  int curVersion;
234
233
 
235
234
  String password = "";
236
- if (_encrypted && (_mode.equals("secret") || _mode.equals("encryption"))) {
235
+ if (_encrypted && (_mode.equals("secret") || _mode.equals("encryption") || _mode.equals("decryption"))) {
237
236
  if (!_uSecret.isPassphrase()) {
238
237
  throw new Exception("No Passphrase stored");
239
238
  }
@@ -252,6 +251,20 @@ public class Database {
252
251
  throw new Exception("No Encryption set in capacitor.config");
253
252
  }
254
253
  }
254
+ if (_mode.equals("decryption")) {
255
+ if (_isEncryption) {
256
+ try {
257
+ _uCipher.decrypt(_context, _file, SQLiteDatabase.getBytes(password.toCharArray()));
258
+ password = "";
259
+ } catch (Exception e) {
260
+ String msg = "Failed in decryption " + e.getMessage();
261
+ Log.v(TAG, msg);
262
+ throw new Exception(msg);
263
+ }
264
+ } else {
265
+ throw new Exception("No Encryption set in capacitor.config");
266
+ }
267
+ }
255
268
  try {
256
269
  if (!isNCDB() && !this._readOnly) {
257
270
  _db = SQLiteDatabase.openOrCreateDatabase(_file, password, null);
@@ -134,6 +134,68 @@ public class UtilsSQLCipher {
134
134
  }
135
135
  }
136
136
 
137
+ public void decrypt(Context ctxt, File originalFile, byte[] passphrase) throws IOException {
138
+ SQLiteDatabase.loadLibs(ctxt);
139
+
140
+ if (originalFile.exists()) {
141
+ // Create a temporary file for the decrypted database in the cache directory
142
+ File decryptedFile = File.createTempFile("sqlcipherutils", "tmp", ctxt.getCacheDir());
143
+
144
+ // Open the decrypted database
145
+ SQLiteDatabase decryptedDb = SQLiteDatabase.openDatabase(
146
+ decryptedFile.getAbsolutePath(),
147
+ "",
148
+ null,
149
+ SQLiteDatabase.OPEN_READWRITE
150
+ );
151
+
152
+ // Open the encrypted database with the provided passphrase
153
+ SQLiteDatabase encryptedDb = SQLiteDatabase.openDatabase(
154
+ originalFile.getAbsolutePath(),
155
+ new String(passphrase),
156
+ null,
157
+ SQLiteDatabase.OPEN_READWRITE
158
+ );
159
+
160
+ int version = encryptedDb.getVersion();
161
+ decryptedDb.setVersion(version);
162
+
163
+ decryptedDb.close();
164
+
165
+ // Attach the encrypted database to itself using an empty key
166
+ StringBuilder attachSql = new StringBuilder();
167
+ attachSql.append("ATTACH DATABASE ? AS plaintext KEY '';");
168
+ final SQLiteStatement attachStatement = encryptedDb.compileStatement(attachSql.toString());
169
+
170
+ attachStatement.bindString(1, decryptedFile.getAbsolutePath());
171
+ attachStatement.execute();
172
+
173
+ // Export data from the encrypted database to the plaintext database
174
+ StringBuilder exportSql = new StringBuilder();
175
+ exportSql.append("SELECT sqlcipher_export('plaintext');");
176
+ encryptedDb.rawExecSQL(exportSql.toString());
177
+
178
+ // Detach the plaintext database
179
+ StringBuilder detachSql = new StringBuilder();
180
+ detachSql.append("DETACH DATABASE plaintext;");
181
+ encryptedDb.rawExecSQL(detachSql.toString());
182
+
183
+ attachStatement.close();
184
+ encryptedDb.close();
185
+
186
+ boolean delFile = originalFile.delete();
187
+ if (!delFile) {
188
+ throw new FileNotFoundException(originalFile.getAbsolutePath() + " not deleted");
189
+ }
190
+ boolean renFile = decryptedFile.renameTo(originalFile);
191
+ if (!renFile) {
192
+ throw new FileNotFoundException(originalFile.getAbsolutePath() + " not renamed");
193
+ }
194
+ } else {
195
+ throw new FileNotFoundException(originalFile.getAbsolutePath() + " not found");
196
+ }
197
+ }
198
+
137
199
  public void changePassword(Context ctxt, File file, String password, String nwpassword) throws IOException {
138
200
  SQLiteDatabase.loadLibs(ctxt);
139
201
 
@@ -134,25 +134,31 @@ public class UtilsSQLStatement {
134
134
 
135
135
  public static List<String> extractColumnNames(String whereClause) {
136
136
  Set<String> keywords = new HashSet<>(Arrays.asList("AND", "OR", "IN", "VALUES", "LIKE", "BETWEEN", "NOT"));
137
- String[] tokens = whereClause.split("\\s|,|\\(|\\)");
138
137
 
138
+ Pattern pattern = Pattern.compile(
139
+ "\\b[a-zA-Z]\\w*\\b(?=\\s*(?:<=?|>=?|<>?|=|AND|OR|BETWEEN|NOT|IN|LIKE))|" +
140
+ "\\b[a-zA-Z]\\w*\\b\\s+BETWEEN\\s+'[^']+'\\s+AND\\s+'[^']+'|" +
141
+ "\\(([^)]+)\\)\\s+IN\\s+\\(VALUES"
142
+ );
143
+ Matcher matcher = pattern.matcher(whereClause);
139
144
  List<String> columns = new ArrayList<>();
140
- boolean inClause = false;
141
- boolean inValues = false;
142
-
143
- for (String token : tokens) {
144
- if (token.equals("IN")) {
145
- inClause = true;
146
- } else if (inClause && token.equals("(")) {
147
- inValues = true;
148
- } else if (inValues && token.equals(")")) {
149
- inValues = false;
150
- } else if (token.matches("\\b[a-zA-Z]\\w*\\b") && !inValues && !keywords.contains(token.toUpperCase())) {
151
- columns.add(token);
145
+
146
+ while (matcher.find()) {
147
+ String columnList = matcher.group(1);
148
+ if (columnList != null) {
149
+ String[] columnNamesArray = columnList.split(",");
150
+ for (String columnName : columnNamesArray) {
151
+ columns.add(columnName.trim());
152
+ }
153
+ } else {
154
+ String matchedText = matcher.group();
155
+ if (!keywords.contains(matchedText.trim().toUpperCase())) {
156
+ columns.add(matchedText.trim());
157
+ }
152
158
  }
153
159
  }
154
160
 
155
- return new ArrayList<>(new HashSet<>(columns));
161
+ return columns;
156
162
  }
157
163
 
158
164
  public static List<Integer> indicesOf(String str, String searchStr, int fromIndex) {
@@ -127,11 +127,11 @@ export interface CapacitorSQLitePlugin {
127
127
  */
128
128
  commitTransaction(options: capSQLiteOptions): Promise<capSQLiteChanges>;
129
129
  /**
130
- * Rollback Database Transaction
131
- * @param options
132
- * @returns capSQLiteChanges
133
- * @since 5.0.7
134
- */
130
+ * Rollback Database Transaction
131
+ * @param options
132
+ * @returns capSQLiteChanges
133
+ * @since 5.0.7
134
+ */
135
135
  rollbackTransaction(options: capSQLiteOptions): Promise<capSQLiteChanges>;
136
136
  /**
137
137
  * Is Database Transaction Active
@@ -1087,7 +1087,7 @@ export interface ISQLiteConnection {
1087
1087
  clearEncryptionSecret(): Promise<void>;
1088
1088
  /**
1089
1089
  * Check the passphrase stored in a secure store
1090
- * @param passphrase
1090
+ * @param oldPassphrase
1091
1091
  * @returns Promise<capSQLiteResult>
1092
1092
  * @since 4.6.1
1093
1093
  */
@@ -135,6 +135,12 @@ export class SQLiteConnection {
135
135
  const conn = new SQLiteDBConnection(database, readonly, this.sqlite);
136
136
  const connName = readonly ? `RO_${database}` : `RW_${database}`;
137
137
  this._connectionDict.set(connName, conn);
138
+ /*
139
+ console.log(`*** in createConnection connectionDict: ***`)
140
+ this._connectionDict.forEach((connection, key) => {
141
+ console.log(`Key: ${key}, Value: ${connection}`);
142
+ });
143
+ */
138
144
  return Promise.resolve(conn);
139
145
  }
140
146
  catch (err) {
@@ -148,6 +154,11 @@ export class SQLiteConnection {
148
154
  await this.sqlite.closeConnection({ database, readonly });
149
155
  const connName = readonly ? `RO_${database}` : `RW_${database}`;
150
156
  this._connectionDict.delete(connName);
157
+ /* console.log(`*** in closeConnection connectionDict: ***`)
158
+ this._connectionDict.forEach((connection, key) => {
159
+ console.log(`Key: ${key}, Value: ${connection}`);
160
+ });
161
+ */
151
162
  return Promise.resolve();
152
163
  }
153
164
  catch (err) {
@@ -251,6 +262,11 @@ export class SQLiteConnection {
251
262
  async closeAllConnections() {
252
263
  const delDict = new Map();
253
264
  try {
265
+ /* console.log(`*** in closeAllConnections connectionDict: ***`)
266
+ this._connectionDict.forEach((connection, key) => {
267
+ console.log(`Key: ${key}, Value: ${connection}`);
268
+ });
269
+ */
254
270
  for (const key of this._connectionDict.keys()) {
255
271
  const database = key.substring(3);
256
272
  const readonly = key.substring(0, 3) === 'RO_' ? true : false;
@@ -263,6 +279,7 @@ export class SQLiteConnection {
263
279
  return Promise.resolve();
264
280
  }
265
281
  catch (err) {
282
+ console.log(`in definition closeAllConnections err: `, err);
266
283
  return Promise.reject(err);
267
284
  }
268
285
  }
@@ -445,8 +462,6 @@ export class SQLiteDBConnection {
445
462
  return this.readonly;
446
463
  }
447
464
  async open() {
448
- const jeepSQlEL = document.querySelector("jeep-sqlite");
449
- console.log(`in definition open jeepSQlEL: `, jeepSQlEL);
450
465
  try {
451
466
  await this.sqlite.open({
452
467
  database: this.dbName,
@@ -472,8 +487,9 @@ export class SQLiteDBConnection {
472
487
  }
473
488
  async beginTransaction() {
474
489
  try {
475
- const changes = await this.sqlite
476
- .beginTransaction({ database: this.dbName });
490
+ const changes = await this.sqlite.beginTransaction({
491
+ database: this.dbName,
492
+ });
477
493
  return Promise.resolve(changes);
478
494
  }
479
495
  catch (err) {
@@ -482,8 +498,9 @@ export class SQLiteDBConnection {
482
498
  }
483
499
  async commitTransaction() {
484
500
  try {
485
- const changes = await this.sqlite
486
- .commitTransaction({ database: this.dbName });
501
+ const changes = await this.sqlite.commitTransaction({
502
+ database: this.dbName,
503
+ });
487
504
  return Promise.resolve(changes);
488
505
  }
489
506
  catch (err) {
@@ -492,8 +509,9 @@ export class SQLiteDBConnection {
492
509
  }
493
510
  async rollbackTransaction() {
494
511
  try {
495
- const changes = await this.sqlite
496
- .rollbackTransaction({ database: this.dbName });
512
+ const changes = await this.sqlite.rollbackTransaction({
513
+ database: this.dbName,
514
+ });
497
515
  return Promise.resolve(changes);
498
516
  }
499
517
  catch (err) {
@@ -502,8 +520,9 @@ export class SQLiteDBConnection {
502
520
  }
503
521
  async isTransactionActive() {
504
522
  try {
505
- const result = await this.sqlite
506
- .isTransactionActive({ database: this.dbName });
523
+ const result = await this.sqlite.isTransactionActive({
524
+ database: this.dbName,
525
+ });
507
526
  return Promise.resolve(result);
508
527
  }
509
528
  catch (err) {
@@ -580,7 +599,7 @@ export class SQLiteDBConnection {
580
599
  statements: statements,
581
600
  transaction: transaction,
582
601
  readonly: false,
583
- isSQL92: isSQL92
602
+ isSQL92: isSQL92,
584
603
  });
585
604
  return Promise.resolve(res);
586
605
  }
@@ -601,7 +620,7 @@ export class SQLiteDBConnection {
601
620
  statement: statement,
602
621
  values: values,
603
622
  readonly: this.readonly,
604
- isSql92: true
623
+ isSql92: true,
605
624
  });
606
625
  }
607
626
  else {
@@ -610,7 +629,7 @@ export class SQLiteDBConnection {
610
629
  statement: statement,
611
630
  values: [],
612
631
  readonly: this.readonly,
613
- isSQL92: isSQL92
632
+ isSQL92: isSQL92,
614
633
  });
615
634
  }
616
635
  // reorder rows for ios
@@ -636,7 +655,7 @@ export class SQLiteDBConnection {
636
655
  transaction: transaction,
637
656
  readonly: false,
638
657
  returnMode: mRetMode,
639
- isSQL92: true
658
+ isSQL92: true,
640
659
  });
641
660
  // }
642
661
  }
@@ -651,7 +670,7 @@ export class SQLiteDBConnection {
651
670
  transaction: transaction,
652
671
  readonly: false,
653
672
  returnMode: mRetMode,
654
- isSQL92: isSQL92
673
+ isSQL92: isSQL92,
655
674
  });
656
675
  }
657
676
  // reorder rows for ios
@@ -676,7 +695,7 @@ export class SQLiteDBConnection {
676
695
  transaction: transaction,
677
696
  readonly: false,
678
697
  returnMode: returnMode,
679
- isSQL92: isSQL92
698
+ isSQL92: isSQL92,
680
699
  });
681
700
  // }
682
701
  // reorder rows for ios
@@ -832,10 +851,10 @@ export class SQLiteDBConnection {
832
851
  if (!this.readonly) {
833
852
  try {
834
853
  await this.sqlite.beginTransaction({
835
- database: this.dbName
854
+ database: this.dbName,
836
855
  });
837
856
  isActive = await this.sqlite.isTransactionActive({
838
- database: this.dbName
857
+ database: this.dbName,
839
858
  });
840
859
  if (!isActive) {
841
860
  return Promise.reject('After Begin Transaction, no transaction active');
@@ -857,7 +876,7 @@ export class SQLiteDBConnection {
857
876
  transaction: false,
858
877
  readonly: false,
859
878
  returnMode: retMode,
860
- isSQL92: isSQL92
879
+ isSQL92: isSQL92,
861
880
  });
862
881
  if (ret.changes.changes <= 0) {
863
882
  throw new Error('Error in transaction method run ');
@@ -872,7 +891,7 @@ export class SQLiteDBConnection {
872
891
  readonly: false,
873
892
  });
874
893
  isActive = await this.sqlite.isTransactionActive({
875
- database: this.dbName
894
+ database: this.dbName,
876
895
  });
877
896
  if (ret.changes.changes < 0) {
878
897
  throw new Error('Error in transaction method execute ');
@@ -881,11 +900,11 @@ export class SQLiteDBConnection {
881
900
  }
882
901
  }
883
902
  isActive = await this.sqlite.isTransactionActive({
884
- database: this.dbName
903
+ database: this.dbName,
885
904
  });
886
905
  if (isActive) {
887
906
  const retC = await this.sqlite.commitTransaction({
888
- database: this.dbName
907
+ database: this.dbName,
889
908
  });
890
909
  changes += retC.changes.changes;
891
910
  }
@@ -895,7 +914,7 @@ export class SQLiteDBConnection {
895
914
  catch (err) {
896
915
  const msg = err.message ? err.message : err;
897
916
  isActive = await this.sqlite.isTransactionActive({
898
- database: this.dbName
917
+ database: this.dbName,
899
918
  });
900
919
  if (isActive) {
901
920
  await this.sqlite.rollbackTransaction({