@capacitor-community/sqlite 5.7.2 → 5.7.3-2

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.
package/README.md CHANGED
@@ -18,7 +18,7 @@
18
18
  <a href="https://www.npmjs.com/package/@capacitor-community/sqlite"><img src="https://img.shields.io/npm/dw/@capacitor-community/sqlite?style=flat-square" /></a>
19
19
  <a href="https://www.npmjs.com/package/@capacitor-community/sqlite"><img src="https://img.shields.io/npm/v/@capacitor-community/sqlite?style=flat-square" /></a>
20
20
  <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
21
- <a href="#contributors-"><img src="https://img.shields.io/badge/all%20contributors-40-orange?style=flat-square" /></a>
21
+ <a href="#contributors-"><img src="https://img.shields.io/badge/all%20contributors-43-orange?style=flat-square" /></a>
22
22
  <!-- ALL-CONTRIBUTORS-BADGE:END -->
23
23
  </p>
24
24
 
@@ -357,7 +357,7 @@ npm install --save-dev electron-builder@24.6.4
357
357
 
358
358
  The iOS and Android codes are using `SQLCipher` allowing for database encryption.
359
359
  The iOS codes is using `ZIPFoundation` for unzipping assets files
360
- The Electron code is using `better-sqlite3-multiple-ciphers` , `electron-json-storage and `node-fetch` from 5.0.4.
360
+ The Electron code is using `better-sqlite3-multiple-ciphers` , `electron-json-storage` and `node-fetch` from 5.0.4.
361
361
  The Web code is using the Stencil component `jeep-sqlite` based on `sql.js`, `localforage`. and `jszip`
362
362
 
363
363
  ## Contributors ✨
@@ -408,6 +408,12 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
408
408
  <a href="https://github.com/DawidWetzler" title="DawidWetzler"><img src="https://avatars.githubusercontent.com/u/49675685?v=4" width="50" height="50" /></a>
409
409
  <a href="https://github.com/mmouterde" title="mmouterde"><img src="https://avatars.githubusercontent.com/u/733538?v=4" width="50" height="50" /></a>
410
410
  <a href="https://github.com/msfstef" title="msfstef"><img src="https://avatars.githubusercontent.com/u/12274098?v=4" width="50" height="50" /></a>
411
+ <a href="https://github.com/ChrisHSandN" title="
412
+ ChrisHSandN"><img src="https://avatars.githubusercontent.com/u/13466620?v=4" width="50" height="50" /></a>
413
+ <a href="https://github.com/lasher23" title="
414
+ lasher23"><img src="https://avatars.githubusercontent.com/u/24244618?v=4" width="50" height="50" /></a>
415
+ <a href="https://github.com/mirsella" title="
416
+ mirsella"><img src="https://avatars.githubusercontent.com/u/45905567?v=4" width="50" height="50" /></a>
411
417
  </p>
412
418
 
413
419
 
@@ -12,6 +12,7 @@ import static com.getcapacitor.community.database.sqlite.SQLite.UtilsSQLStatemen
12
12
 
13
13
  import android.content.Context;
14
14
  import android.content.SharedPreferences;
15
+ import android.database.DatabaseUtils;
15
16
  import android.os.Build;
16
17
  import android.util.Log;
17
18
  import androidx.sqlite.db.SimpleSQLiteQuery;
@@ -503,7 +504,7 @@ public class Database {
503
504
  String elementValue = "";
504
505
 
505
506
  if (innerElement instanceof String) {
506
- elementValue = "'" + innerElement + "'";
507
+ elementValue = DatabaseUtils.sqlEscapeString((String) innerElement);
507
508
  } else {
508
509
  elementValue = String.valueOf(innerElement);
509
510
  }
@@ -520,7 +521,6 @@ public class Database {
520
521
  sqlBuilder.append(",");
521
522
  }
522
523
  }
523
- sqlBuilder.append(";");
524
524
  String questionMark = extractQuestionMarkValues(statement);
525
525
  String finalSql = "";
526
526
  if (questionMark != null) {
@@ -537,7 +537,7 @@ public class Database {
537
537
  }
538
538
 
539
539
  public String extractQuestionMarkValues(String input) {
540
- Pattern pattern = Pattern.compile("VALUES \\((\\?(?:,\\s*\\?\\s*)*)\\)");
540
+ Pattern pattern = Pattern.compile("(?i)VALUES \\((\\?(?:,\\s*\\?\\s*)*)\\)");
541
541
  Matcher matcher = pattern.matcher(input);
542
542
 
543
543
  if (matcher.find()) {
@@ -1,13 +1,17 @@
1
1
  package com.getcapacitor.community.database.sqlite.SQLite;
2
2
 
3
+ import java.net.MalformedURLException;
3
4
  import android.content.Context;
4
- import android.content.res.AssetManager;
5
5
  import java.io.File;
6
6
  import java.io.FileOutputStream;
7
7
  import java.io.IOException;
8
8
  import java.io.InputStream;
9
9
  import java.net.HttpURLConnection;
10
10
  import java.net.URL;
11
+ import java.util.regex.Matcher;
12
+ import java.util.regex.Pattern;
13
+ import java.net.URLDecoder;
14
+ import java.nio.charset.StandardCharsets;
11
15
 
12
16
  public class UtilsDownloadFromHTTP {
13
17
 
@@ -16,34 +20,46 @@ public class UtilsDownloadFromHTTP {
16
20
  private final UtilsFile _uFile = new UtilsFile();
17
21
 
18
22
  public void download(Context context, String fileUrl) throws Exception {
19
- AssetManager assetManager = context.getAssets();
20
- String fileName = fileUrl.substring(fileUrl.lastIndexOf('/') + 1);
21
- String dbName = fileName;
22
- Boolean isZip = false;
23
- if (!fileName.contains("SQLite.db")) {
24
- if (_uFile.getFileExtension((fileName)).equals("db")) {
25
- dbName = fileName.substring(0, fileName.length() - 3) + "SQLite.db";
26
- }
27
- if (_uFile.isLast(fileName, ".zip")) {
28
- isZip = true;
23
+ Boolean isZip = false;
24
+ String fileName = "";
25
+ try {
26
+ String[] fileDetails = getFileDetails(fileUrl);
27
+ fileName = fileDetails[0];
28
+ String extension = fileDetails[1];
29
+ if (!fileName.contains("SQLite.db")) {
30
+ switch(extension) {
31
+ case "db":
32
+ fileName = fileName.substring(0, fileName.length() - 3) + "SQLite.db";
33
+ break;
34
+ case "zip":
35
+ isZip = true;
36
+ break;
37
+ default:
38
+ throw new Exception("Unknown file type. Filename: " + fileName);
39
+ }
29
40
  }
41
+
42
+ } catch (Exception e) {
43
+ throw new Exception(e.getMessage());
30
44
  }
45
+
46
+
31
47
  File cacheDir = context.getCacheDir();
32
48
  String cachePath = cacheDir.getAbsolutePath();
33
- String tmpFilePath = cachePath + File.separator + dbName;
49
+ String tmpFilePath = cachePath + File.separator + fileName;
34
50
  String databasePath = _uFile.getDatabaseDirectoryPath(context);
35
51
  File databaseDir = new File(databasePath);
36
52
  try {
37
53
  // delete file if exists in cache
38
54
  Boolean isExists = _uFile.isPathExists(tmpFilePath);
39
55
  if (isExists) {
40
- _uFile.deleteFile(cachePath, dbName);
56
+ _uFile.deleteFile(cachePath, fileName);
41
57
  }
42
- downloadFileToCache(fileUrl, cachePath);
58
+ downloadFileToCache(fileUrl, fileName, cachePath);
43
59
  if (isZip) {
44
60
  _uFile.unzipCopyDatabase(cachePath, null, tmpFilePath, true);
45
61
  // delete zip file from cache
46
- _uFile.deleteFile(cachePath, dbName);
62
+ _uFile.deleteFile(cachePath, fileName);
47
63
  }
48
64
  // move files to database folder
49
65
  _uFile.moveAllDBs(cacheDir, databaseDir);
@@ -52,28 +68,41 @@ public class UtilsDownloadFromHTTP {
52
68
  }
53
69
  }
54
70
 
55
- public static void downloadFileToCache(String fileURL, String cacheDir) throws Exception {
71
+ public static String[] getFileDetails(String url) throws Exception {
72
+ try {
73
+ URL javaUrl = new URL(url);
74
+ String path = javaUrl.getPath();
75
+ String decodedPath = URLDecoder.decode(path, StandardCharsets.UTF_8.toString()); // Decode URL-encoded path
76
+ String filename = decodedPath.substring(decodedPath.lastIndexOf('/') + 1); // Extract filename from decoded path
77
+ String extension = getFileExtension(filename);
78
+ if(extension == null) {
79
+ throw new Exception("extension db or zip not found");
80
+ }
81
+ return new String[]{filename, extension};
82
+ } catch (MalformedURLException e) {
83
+ e.printStackTrace();
84
+ throw new Exception(e.getMessage());
85
+ }
86
+ }
87
+ public static String getFileExtension(String filename) {
88
+ Pattern pattern = Pattern.compile("\\.([a-zA-Z0-9]+)(?:[\\?#]|$)");
89
+ Matcher matcher = pattern.matcher(filename);
90
+
91
+ if (matcher.find()) {
92
+ return matcher.group(1).toLowerCase(); // returns the matched extension in lowercase
93
+ }
94
+
95
+ return null; // no extension found
96
+ }
97
+ public static void downloadFileToCache(String fileURL, String fileName, String cacheDir) throws Exception {
56
98
  HttpURLConnection httpConn = null;
57
99
  try {
58
100
  URL url = new URL(fileURL);
59
101
  httpConn = (HttpURLConnection) url.openConnection();
102
+ httpConn.setRequestMethod("GET");
60
103
  int responseCode = httpConn.getResponseCode();
61
104
  if (responseCode == HttpURLConnection.HTTP_OK) {
62
- String fileName = "";
63
- String disposition = httpConn.getHeaderField("Content-Disposition");
64
- // String contentType = httpConn.getContentType();
65
105
  int contentLength = httpConn.getContentLength();
66
-
67
- if (disposition != null) {
68
- // extracts file name from header field
69
- int index = disposition.indexOf("filename=");
70
- if (index > 0) {
71
- fileName = disposition.substring(index + 10, disposition.length() - 1);
72
- }
73
- } else {
74
- // extracts file name from URL
75
- fileName = fileURL.substring(fileURL.lastIndexOf("/") + 1);
76
- }
77
106
  String dbName = fileName;
78
107
  if (!fileName.contains("SQLite.db")) {
79
108
  if (fileName.substring(fileName.length() - 3).equals(".db")) {
@@ -81,26 +110,22 @@ public class UtilsDownloadFromHTTP {
81
110
  }
82
111
  }
83
112
 
84
- // System.out.println("Content-Type = " + contentType);
85
- // System.out.println("Content-Disposition = " + disposition);
86
- // System.out.println("Content-Length = " + contentLength);
87
- // System.out.println("fileName = " + fileName);
88
- // opens input stream from the HTTP connection
89
- InputStream inputStream = httpConn.getInputStream();
90
113
  // create temporary file path
91
114
  String tmpFilePath = cacheDir + File.separator + dbName;
92
- // opens an output stream to save into file
93
- FileOutputStream outputStream = new FileOutputStream(tmpFilePath);
94
- int bytesRead = -1;
95
- byte[] buffer = new byte[BUFFER_SIZE];
96
- while ((bytesRead = inputStream.read(buffer)) != -1) {
97
- outputStream.write(buffer, 0, bytesRead);
98
- }
115
+ // opens input stream from the HTTP connection
116
+ try (InputStream inputStream = httpConn.getInputStream();
117
+ FileOutputStream outputStream = new FileOutputStream(tmpFilePath)) {
99
118
 
100
- outputStream.close();
101
- inputStream.close();
119
+ byte[] buffer = new byte[1024];
120
+ int bytesRead;
121
+ while ((bytesRead = inputStream.read(buffer)) != -1) {
122
+ outputStream.write(buffer, 0, bytesRead);
123
+ }
124
+ outputStream.close();
125
+ inputStream.close();
102
126
 
103
- System.out.println("File " + fileName + " downloaded (" + contentLength + ")");
127
+ System.out.println("File " + fileName + " downloaded (" + contentLength + ")");
128
+ }
104
129
  } else {
105
130
  String msg = "No file to download. Server replied HTTP code: " + responseCode;
106
131
  throw new IOException(msg);
@@ -447,10 +447,14 @@ class UtilsFile {
447
447
  * @returns
448
448
  */
449
449
  getExtName(filePath) {
450
- return this.Path.extname(filePath);
450
+ const matches = filePath.match(/\.([a-zA-Z0-9]+)(?:[\\?#]|$)/);
451
+ return matches ? `.${matches[1].toLowerCase()}` : ''; // returns the matched extension in lowercase
452
+ // return this.Path.extname(filePath);
451
453
  }
452
454
  getBaseName(filePath) {
453
- return this.Path.basename(filePath, this.Path.extname(filePath));
455
+ const decodedUrl = decodeURIComponent(filePath); // Decode the URL component
456
+ const baseName = this.Path.basename(decodedUrl, this.Path.extname(filePath));
457
+ return baseName;
454
458
  }
455
459
  /**
456
460
  * IsPathExists
@@ -589,34 +593,38 @@ class UtilsFile {
589
593
  */
590
594
  async unzipDatabase(db, fPath, overwrite) {
591
595
  const pZip = this.Path.join(fPath, db);
592
- // Read the Zip file
593
- this.NodeFs.readFile(pZip, (err, data) => {
594
- if (err) {
595
- console.log(err);
596
- return Promise.reject(`unzipDatabase ${JSON.stringify(err)}`);
597
- }
596
+ try {
597
+ // Read the Zip file
598
+ const data = await this.NodeFs.promises.readFile(pZip);
598
599
  const zip = new this.JSZip();
599
- zip.loadAsync(data).then((contents) => {
600
- Object.keys(contents.files).forEach(filename => {
601
- zip
602
- .file(filename)
603
- .async('nodebuffer')
604
- .then(async (content) => {
605
- const toDb = this.setPathSuffix(filename);
606
- const pDb = this.Path.join(this.getDatabasesPath(), toDb);
607
- // check filePath exists
608
- const isPath = this.isPathExists(pDb);
609
- if (!isPath || overwrite) {
610
- if (overwrite && isPath) {
611
- await this.deleteFilePath(pDb);
612
- }
613
- this.NodeFs.writeFileSync(pDb, content);
600
+ const contents = await zip.loadAsync(data);
601
+ // Create an array to store promises for writing files
602
+ const writePromises = [];
603
+ Object.keys(contents.files).forEach(filename => {
604
+ writePromises.push(zip
605
+ .file(filename)
606
+ .async('nodebuffer')
607
+ .then(async (content) => {
608
+ const toDb = this.setPathSuffix(filename);
609
+ const pDb = this.Path.join(this.getDatabasesPath(), toDb);
610
+ // check filePath exists
611
+ const isPath = this.isPathExists(pDb);
612
+ if (!isPath || overwrite) {
613
+ if (overwrite && isPath) {
614
+ await this.deleteFilePath(pDb);
614
615
  }
615
- return Promise.resolve();
616
- });
617
- });
616
+ await this.NodeFs.promises.writeFile(pDb, content);
617
+ }
618
+ }));
618
619
  });
619
- });
620
+ // Wait for all write promises to resolve
621
+ await Promise.all(writePromises);
622
+ return Promise.resolve();
623
+ }
624
+ catch (err) {
625
+ console.log(err);
626
+ return Promise.reject(`unzipDatabase ${JSON.stringify(err)}`);
627
+ }
620
628
  }
621
629
  /**
622
630
  * CopyFileName
@@ -871,6 +879,7 @@ class UtilsFile {
871
879
  }
872
880
  }
873
881
  }
882
+ return Promise.resolve();
874
883
  }
875
884
  /**
876
885
  * RestoreFileName
@@ -5893,6 +5902,7 @@ class CapacitorSQLite {
5893
5902
  else {
5894
5903
  throw new Error(`getFromHTTPRequest: cannot move file from cache overwrite: ${overwrite}`);
5895
5904
  }
5905
+ return;
5896
5906
  }
5897
5907
  async getDatabaseList() {
5898
5908
  // get the database folder