@capacitor-community/sqlite 5.2.3 → 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.
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/CapacitorSQLite.java +5 -6
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/CapacitorSQLitePlugin.java +12 -7
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/Database.java +20 -7
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/UtilsSQLCipher.java +62 -0
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/UtilsSQLStatement.java +20 -14
- package/dist/esm/definitions.d.ts +6 -6
- package/dist/esm/definitions.js +42 -21
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +42 -21
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +42 -21
- package/dist/plugin.js.map +1 -1
- package/electron/dist/plugin.js +72 -78
- package/electron/dist/plugin.js.map +1 -1
- package/ios/Plugin/CapacitorSQLite.swift +1082 -1139
- package/ios/Plugin/CapacitorSQLitePlugin.swift +3 -2
- package/ios/Plugin/Database.swift +27 -3
- package/ios/Plugin/ImportExportJson/ImportFromJson.swift +2 -2
- package/ios/Plugin/Utils/UtilsDelete.swift +2 -3
- package/ios/Plugin/Utils/UtilsEncryption.swift +75 -0
- package/ios/Plugin/Utils/UtilsSQLCipher.swift +3 -3
- package/ios/Plugin/Utils/UtilsSQLStatement.swift +81 -17
- package/ios/Plugin/Utils/UtilsSecret.swift +1 -0
- package/package.json +3 -3
- package/src/definitions.ts +88 -54
- package/src/web.ts +10 -4
|
@@ -6,7 +6,8 @@ import Capacitor
|
|
|
6
6
|
// swiftlint:disable type_body_length
|
|
7
7
|
public class CapacitorSQLitePlugin: CAPPlugin {
|
|
8
8
|
private var implementation: CapacitorSQLite?
|
|
9
|
-
private let modeList: [String] = ["no-encryption", "encryption", "secret",
|
|
9
|
+
private let modeList: [String] = ["no-encryption", "encryption", "secret",
|
|
10
|
+
"decryption", "newsecret", "wrongsecret"]
|
|
10
11
|
private let retHandler: ReturnHandler = ReturnHandler()
|
|
11
12
|
private var versionUpgrades: [String: [Int: [String: Any]]] = [:]
|
|
12
13
|
var importObserver: Any?
|
|
@@ -239,7 +240,7 @@ public class CapacitorSQLitePlugin: CAPPlugin {
|
|
|
239
240
|
if encrypted && !modeList.contains(inMode) {
|
|
240
241
|
var msg: String = "CreateConnection: inMode "
|
|
241
242
|
msg.append("must be in['encryption',")
|
|
242
|
-
msg.append("'secret','
|
|
243
|
+
msg.append("'secret','decryption']")
|
|
243
244
|
retHandler.rResult(call: call, message: msg)
|
|
244
245
|
return
|
|
245
246
|
}
|
|
@@ -107,7 +107,9 @@ class Database {
|
|
|
107
107
|
// swiftlint:disable function_body_length
|
|
108
108
|
func open () throws {
|
|
109
109
|
var password: String = ""
|
|
110
|
-
if isEncryption && encrypted && (mode == "secret"
|
|
110
|
+
if isEncryption && encrypted && (mode == "secret"
|
|
111
|
+
|| mode == "encryption"
|
|
112
|
+
|| mode == "decryption") {
|
|
111
113
|
let isPassphrase = try UtilsSecret.isPassphrase(account: account)
|
|
112
114
|
if !isPassphrase {
|
|
113
115
|
let msg: String = "No Passphrase stored"
|
|
@@ -135,6 +137,28 @@ class Database {
|
|
|
135
137
|
throw DatabaseError.open(message: msg)
|
|
136
138
|
}
|
|
137
139
|
|
|
140
|
+
}
|
|
141
|
+
if mode == "decryption" {
|
|
142
|
+
if isEncryption {
|
|
143
|
+
do {
|
|
144
|
+
let ret: Bool = try UtilsEncryption
|
|
145
|
+
.decryptDatabase(databaseLocation: databaseLocation,
|
|
146
|
+
filePath: path, password: password,
|
|
147
|
+
version: dbVersion)
|
|
148
|
+
if !ret {
|
|
149
|
+
let msg: String = "Failed in decryption"
|
|
150
|
+
throw DatabaseError.open(message: msg)
|
|
151
|
+
}
|
|
152
|
+
password = ""
|
|
153
|
+
} catch UtilsEncryptionError.decryptionFailed(let message) {
|
|
154
|
+
let msg: String = "Failed in decryption \(message)"
|
|
155
|
+
throw DatabaseError.open(message: msg)
|
|
156
|
+
}
|
|
157
|
+
} else {
|
|
158
|
+
let msg: String = "No Encryption set in capacitor.config"
|
|
159
|
+
throw DatabaseError.open(message: msg)
|
|
160
|
+
}
|
|
161
|
+
|
|
138
162
|
}
|
|
139
163
|
|
|
140
164
|
do {
|
|
@@ -236,7 +260,7 @@ class Database {
|
|
|
236
260
|
throw DatabaseError.isAvailTrans(message: msg)
|
|
237
261
|
}
|
|
238
262
|
}
|
|
239
|
-
|
|
263
|
+
|
|
240
264
|
// MARK: - SetIsTransActive
|
|
241
265
|
|
|
242
266
|
func setIsTransActive(newValue: Bool ) {
|
|
@@ -653,7 +677,7 @@ class Database {
|
|
|
653
677
|
// MARK: - ExportToJson
|
|
654
678
|
|
|
655
679
|
func exportToJson(expMode: String, isEncrypted: Bool)
|
|
656
|
-
|
|
680
|
+
throws -> [String: Any] {
|
|
657
681
|
var retObj: [String: Any] = [:]
|
|
658
682
|
|
|
659
683
|
do {
|
|
@@ -105,7 +105,7 @@ class ImportFromJson {
|
|
|
105
105
|
try UtilsSQLCipher
|
|
106
106
|
.rollbackTransaction(mDB: mDB)
|
|
107
107
|
mDB.setIsTransActive(newValue: false)
|
|
108
|
-
|
|
108
|
+
} catch UtilsSQLCipherError
|
|
109
109
|
.rollbackTransaction(let message) {
|
|
110
110
|
throw ImportFromJsonError
|
|
111
111
|
.createSchema(message: message)
|
|
@@ -615,7 +615,7 @@ class ImportFromJson {
|
|
|
615
615
|
try UtilsSQLCipher
|
|
616
616
|
.rollbackTransaction(mDB: mDB)
|
|
617
617
|
mDB.setIsTransActive(newValue: false)
|
|
618
|
-
|
|
618
|
+
throw ImportFromJsonError
|
|
619
619
|
.createViews(message: msg)
|
|
620
620
|
} catch UtilsSQLCipherError
|
|
621
621
|
.rollbackTransaction(let message) {
|
|
@@ -290,7 +290,7 @@ class UtilsDelete {
|
|
|
290
290
|
var relatedItems: [[String: Any]] = []
|
|
291
291
|
var key: String = ""
|
|
292
292
|
let t1Names = withRefsNames.map { "t1.\($0)" }
|
|
293
|
-
let t2Names = colNames.map
|
|
293
|
+
let t2Names = colNames.map{ "t2.\($0)" }
|
|
294
294
|
|
|
295
295
|
do {
|
|
296
296
|
var whereClause = try UtilsSQLStatement
|
|
@@ -301,9 +301,8 @@ class UtilsDelete {
|
|
|
301
301
|
whereClause = String(whereClause.dropLast())
|
|
302
302
|
}
|
|
303
303
|
let resultString = zip(t1Names, t2Names)
|
|
304
|
-
.map {"\($0) = \($1)" }
|
|
304
|
+
.map { "\($0) = \($1)" }
|
|
305
305
|
.joined(separator: " AND ")
|
|
306
|
-
|
|
307
306
|
let sql = "SELECT t1.rowid FROM \(updTableName) t1 " +
|
|
308
307
|
"JOIN \(tableName) t2 ON \(resultString) " +
|
|
309
308
|
"WHERE \(whereClause) AND t1.sql_deleted = 0;"
|
|
@@ -11,6 +11,7 @@ import SQLCipher
|
|
|
11
11
|
|
|
12
12
|
enum UtilsEncryptionError: Error {
|
|
13
13
|
case encryptionFailed(message: String)
|
|
14
|
+
case decryptionFailed(message: String)
|
|
14
15
|
}
|
|
15
16
|
class UtilsEncryption {
|
|
16
17
|
|
|
@@ -87,5 +88,79 @@ class UtilsEncryption {
|
|
|
87
88
|
return ret
|
|
88
89
|
}
|
|
89
90
|
|
|
91
|
+
// MARK: - DecryptDatabase
|
|
92
|
+
|
|
93
|
+
// swiftlint:disable function_body_length
|
|
94
|
+
class func decryptDatabase(databaseLocation: String, filePath: String,
|
|
95
|
+
password: String, version: Int) throws -> Bool {
|
|
96
|
+
var ret: Bool = false
|
|
97
|
+
var oDB: OpaquePointer?
|
|
98
|
+
var eDB: OpaquePointer?
|
|
99
|
+
do {
|
|
100
|
+
if UtilsFile.isFileExist(filePath: filePath) {
|
|
101
|
+
do {
|
|
102
|
+
let tempPath: String = try UtilsFile
|
|
103
|
+
.getFilePath(databaseLocation: databaseLocation,
|
|
104
|
+
fileName: "temp.db")
|
|
105
|
+
try UtilsFile.renameFile(filePath: filePath,
|
|
106
|
+
toFilePath: tempPath,
|
|
107
|
+
databaseLocation: databaseLocation)
|
|
108
|
+
oDB = try UtilsSQLCipher
|
|
109
|
+
.openOrCreateDatabase(filename: tempPath,
|
|
110
|
+
password: password,
|
|
111
|
+
readonly: false)
|
|
112
|
+
eDB = try UtilsSQLCipher
|
|
113
|
+
.openOrCreateDatabase(filename: filePath,
|
|
114
|
+
password: "",
|
|
115
|
+
readonly: false)
|
|
116
|
+
|
|
117
|
+
var stmt: String = "PRAGMA key = '\(password)';"
|
|
118
|
+
stmt.append("ATTACH DATABASE '\(filePath)' ")
|
|
119
|
+
stmt.append("AS plaintext KEY '';")
|
|
120
|
+
stmt.append("SELECT sqlcipher_export('plaintext');")
|
|
121
|
+
stmt.append("DETACH DATABASE plaintext;")
|
|
122
|
+
if sqlite3_exec(oDB, stmt, nil, nil, nil) ==
|
|
123
|
+
SQLITE_OK {
|
|
124
|
+
try _ = UtilsFile
|
|
125
|
+
.deleteFile(fileName: "temp.db",
|
|
126
|
+
databaseLocation: databaseLocation)
|
|
127
|
+
// set the version
|
|
128
|
+
let sqltr: String = "PRAGMA user_version = \(version);"
|
|
129
|
+
if sqlite3_exec(eDB, sqltr, nil, nil, nil) != SQLITE_OK {
|
|
130
|
+
throw UtilsEncryptionError
|
|
131
|
+
.decryptionFailed(message: "set version to \(version) failed")
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
ret = true
|
|
135
|
+
}
|
|
136
|
+
// close the db
|
|
137
|
+
try UtilsSQLCipher.close(oDB: oDB)
|
|
138
|
+
|
|
139
|
+
} catch UtilsFileError.getFilePathFailed {
|
|
140
|
+
throw UtilsEncryptionError
|
|
141
|
+
.decryptionFailed(message: "file path failed")
|
|
142
|
+
} catch UtilsFileError.renameFileFailed {
|
|
143
|
+
throw UtilsEncryptionError
|
|
144
|
+
.decryptionFailed(message: "file rename failed")
|
|
145
|
+
} catch UtilsSQLCipherError.openOrCreateDatabase(_) {
|
|
146
|
+
throw UtilsEncryptionError
|
|
147
|
+
.decryptionFailed(message: "open failed")
|
|
148
|
+
} catch UtilsSQLCipherError.close(_) {
|
|
149
|
+
throw UtilsEncryptionError
|
|
150
|
+
.decryptionFailed(message: "close failed")
|
|
151
|
+
} catch let error {
|
|
152
|
+
print("Error: \(error)")
|
|
153
|
+
throw UtilsEncryptionError
|
|
154
|
+
.decryptionFailed(message: "Error: \(error)")
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
} catch let error {
|
|
158
|
+
print("Error: \(error)")
|
|
159
|
+
throw UtilsEncryptionError
|
|
160
|
+
.decryptionFailed(message: "Error: \(error)")
|
|
161
|
+
}
|
|
162
|
+
return ret
|
|
163
|
+
}
|
|
164
|
+
|
|
90
165
|
}
|
|
91
166
|
// swiftlint:enable function_body_length
|
|
@@ -665,9 +665,9 @@ class UtilsSQLCipher {
|
|
|
665
665
|
"WHERE Statement"
|
|
666
666
|
throw UtilsSQLCipherError.deleteSQL(message: msg)
|
|
667
667
|
}
|
|
668
|
-
/*
|
|
669
|
-
|
|
670
|
-
*/
|
|
668
|
+
/*
|
|
669
|
+
let curTime = UtilsDelete.getCurrentTimeAsInteger()
|
|
670
|
+
*/
|
|
671
671
|
let setStmt = "sql_deleted = 1"
|
|
672
672
|
// Find REFERENCIES if any and update the sql_deleted
|
|
673
673
|
// column
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
|
|
8
8
|
import Foundation
|
|
9
9
|
enum UtilsSQLStatementError: Error {
|
|
10
|
-
case extractColumnNames(message: String)
|
|
11
10
|
case extractForeignKeyInfo(message: String)
|
|
12
11
|
case addPrefixToWhereClause(message: String)
|
|
13
12
|
}
|
|
@@ -69,8 +68,8 @@ class UtilsSQLStatement {
|
|
|
69
68
|
// MARK: - addPrefixToWhereClause
|
|
70
69
|
|
|
71
70
|
class func addPrefixToWhereClause(_ whereClause: String,
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
from: [String],
|
|
72
|
+
to: [String], prefix: String)
|
|
74
73
|
throws -> String {
|
|
75
74
|
var columnValuePairs: [String]
|
|
76
75
|
if whereClause.contains("AND") {
|
|
@@ -141,6 +140,7 @@ class UtilsSQLStatement {
|
|
|
141
140
|
}
|
|
142
141
|
// MARK: - extractForeignKeyInfo
|
|
143
142
|
|
|
143
|
+
// swiftlint:enable function_body_length
|
|
144
144
|
// swiftlint:enable type_body_length
|
|
145
145
|
class func extractForeignKeyInfo(from sqlStatement: String)
|
|
146
146
|
throws ->
|
|
@@ -225,32 +225,95 @@ class UtilsSQLStatement {
|
|
|
225
225
|
return foreignKeyInfo
|
|
226
226
|
}
|
|
227
227
|
// swiftlint:enable type_body_length
|
|
228
|
+
// swiftlint:disable function_body_length
|
|
228
229
|
|
|
229
230
|
// MARK: - extractColumnNames
|
|
230
231
|
|
|
232
|
+
// swiftlint:disable function_body_length
|
|
231
233
|
class func extractColumnNames(from whereClause: String) -> [String] {
|
|
232
234
|
let keywords: Set<String> = ["AND", "OR", "IN", "VALUES", "LIKE", "BETWEEN", "NOT"]
|
|
233
|
-
let
|
|
235
|
+
let operators: Set<String> = ["=", "<", "<=", ">=", ">", "<>"]
|
|
234
236
|
|
|
235
237
|
var columns = [String]()
|
|
236
238
|
var inClause = false
|
|
237
239
|
var inValues = false
|
|
240
|
+
var betweenClause = false
|
|
241
|
+
var andClause = false
|
|
242
|
+
var inPar = false
|
|
243
|
+
var inOper = false
|
|
244
|
+
var inLike = false
|
|
245
|
+
func extractString(from input: String) -> String {
|
|
246
|
+
// Check if the input string starts with "(" or ends with ")"
|
|
247
|
+
if input.hasPrefix("(") {
|
|
248
|
+
let startIndex = input.index(input.startIndex, offsetBy: 1)
|
|
249
|
+
let result = input[startIndex..<input.endIndex]
|
|
250
|
+
return String(result)
|
|
251
|
+
} else if input.hasSuffix(")") {
|
|
252
|
+
let endIndex = input.index(input.endIndex, offsetBy: -1)
|
|
253
|
+
let result = input[input.startIndex..<endIndex]
|
|
254
|
+
return String(result)
|
|
255
|
+
} else {
|
|
256
|
+
return input
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
func removeOperatorsAndFollowing(from input: String) -> String {
|
|
260
|
+
let operatorsPattern = "(=|<=|<|>|>=|<>)"
|
|
261
|
+
if let range = input.range(of: operatorsPattern, options: .regularExpression) {
|
|
262
|
+
let result = input.prefix(upTo: range.lowerBound)
|
|
263
|
+
return String(result)
|
|
264
|
+
} else {
|
|
265
|
+
return input // Return the input string unchanged if no operator is found
|
|
266
|
+
}
|
|
267
|
+
}
|
|
238
268
|
|
|
239
|
-
|
|
240
|
-
if token == "IN" {
|
|
269
|
+
func processToken(_ token: String) {
|
|
270
|
+
if token.uppercased() == "IN" {
|
|
241
271
|
inClause = true
|
|
242
|
-
} else if inClause && token == "("
|
|
272
|
+
} else if inClause && (token.prefix(7).uppercased() == "(VALUES" ||
|
|
273
|
+
token.prefix(8).uppercased() == "( VALUES") {
|
|
243
274
|
inValues = true
|
|
244
|
-
} else if inValues && token == ")"
|
|
275
|
+
} else if inValues && (token.suffix(2).uppercased() == "))" ||
|
|
276
|
+
token.suffix(3).uppercased() == ") )") {
|
|
245
277
|
inValues = false
|
|
278
|
+
} else if inClause && !inValues && token.prefix(1) == "(" {
|
|
279
|
+
inPar = true
|
|
280
|
+
} else if inClause && !inValues && token.suffix(1) == ")" {
|
|
281
|
+
inPar = false
|
|
282
|
+
inClause = false
|
|
283
|
+
} else if token.uppercased() == "BETWEEN" {
|
|
284
|
+
betweenClause = true
|
|
285
|
+
} else if betweenClause && token.uppercased() == "AND" {
|
|
286
|
+
andClause = true
|
|
287
|
+
} else if operators.contains(token) {
|
|
288
|
+
inOper = true
|
|
289
|
+
} else if token.uppercased() == "LIKE" {
|
|
290
|
+
inLike = true
|
|
246
291
|
} else if token.range(of: "\\b[a-zA-Z]\\w*\\b", options: .regularExpression) != nil
|
|
247
|
-
&& !
|
|
248
|
-
|
|
292
|
+
&& !inClause && (!inValues || !inPar)
|
|
293
|
+
&& !betweenClause && !andClause && !inOper && !inLike
|
|
294
|
+
&& !keywords.contains(token.uppercased()) {
|
|
295
|
+
var mToken = extractString(from: token)
|
|
296
|
+
mToken = removeOperatorsAndFollowing(from: mToken)
|
|
297
|
+
columns.append(mToken)
|
|
298
|
+
} else if token.range(of: "\\b[a-zA-Z]\\w*\\b", options: .regularExpression) != nil
|
|
299
|
+
&& betweenClause && andClause {
|
|
300
|
+
betweenClause = false
|
|
301
|
+
andClause = false
|
|
302
|
+
} else if token.range(of: "\\b[a-zA-Z]\\w*\\b", options: .regularExpression) != nil
|
|
303
|
+
&& inOper {
|
|
304
|
+
inOper = false
|
|
305
|
+
} else if token.range(of: "\\b[a-zA-Z]\\w*\\b", options: .regularExpression) != nil
|
|
306
|
+
&& inLike {
|
|
307
|
+
inLike = false
|
|
249
308
|
}
|
|
250
309
|
}
|
|
251
|
-
|
|
252
|
-
|
|
310
|
+
let tokens = whereClause.components(separatedBy: CharacterSet(charactersIn: " ,"))
|
|
311
|
+
for token in tokens {
|
|
312
|
+
processToken(token)
|
|
313
|
+
}
|
|
314
|
+
return Array(columns)
|
|
253
315
|
}
|
|
316
|
+
// swiftlint:enable function_body_length
|
|
254
317
|
|
|
255
318
|
// MARK: - flattenMultilineString
|
|
256
319
|
|
|
@@ -308,11 +371,12 @@ class UtilsSQLStatement {
|
|
|
308
371
|
|
|
309
372
|
for match in matches {
|
|
310
373
|
|
|
311
|
-
let keysRange = Range(match.range(at: 1), in: whereClause)
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
374
|
+
if let keysRange = Range(match.range(at: 1), in: whereClause) {
|
|
375
|
+
let keysString = String(whereClause[keysRange])
|
|
376
|
+
let keys = keysString.split(separator: ",").map {
|
|
377
|
+
String($0.trimmingCharacters(in: .whitespaces)) }
|
|
378
|
+
primaryKeySets.append(keys)
|
|
379
|
+
}
|
|
316
380
|
}
|
|
317
381
|
return primaryKeySets.isEmpty ? nil : primaryKeySets
|
|
318
382
|
}
|
|
@@ -255,6 +255,7 @@ class UtilsSecret {
|
|
|
255
255
|
if !getPassphrase(account: account).isEmpty {
|
|
256
256
|
try setPassphrase(account: account, passphrase: "")
|
|
257
257
|
}
|
|
258
|
+
|
|
258
259
|
} catch UtilsSecretError.setPassphrase(let message) {
|
|
259
260
|
throw UtilsSecretError.clearEncryptionSecret(message: message)
|
|
260
261
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capacitor-community/sqlite",
|
|
3
|
-
"version": "5.2.
|
|
3
|
+
"version": "5.2.4",
|
|
4
4
|
"description": "Community plugin for native & electron SQLite databases",
|
|
5
5
|
"main": "dist/plugin.cjs.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"@ionic/swiftlint-config": "^1.1.2",
|
|
70
70
|
"@rollup/plugin-commonjs": "^20.0.0",
|
|
71
71
|
"@rollup/plugin-node-resolve": "^13.0.4",
|
|
72
|
-
"electron": "^
|
|
72
|
+
"electron": "^25.2.0",
|
|
73
73
|
"eslint": "^7.11.0",
|
|
74
74
|
"prettier": "~2.3.0",
|
|
75
75
|
"prettier-plugin-java": "~1.0.2",
|
|
@@ -98,6 +98,6 @@
|
|
|
98
98
|
}
|
|
99
99
|
},
|
|
100
100
|
"dependencies": {
|
|
101
|
-
"jeep-sqlite": "^2.5.
|
|
101
|
+
"jeep-sqlite": "^2.5.3"
|
|
102
102
|
}
|
|
103
103
|
}
|