@capacitor-community/sqlite 5.0.5-2 → 5.0.6
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 +118 -156
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/CapacitorSQLitePlugin.java +81 -249
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/NotificationCenter.java +1 -1
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/RetHandler.java +0 -12
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/Database.java +184 -40
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/ImportExportJson/ExportToJson.java +141 -135
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/ImportExportJson/ImportFromJson.java +2 -1
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/ImportExportJson/UtilsEncryption.java +111 -0
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/UtilsBiometric.java +0 -4
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/UtilsFile.java +30 -18
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/UtilsMigrate.java +12 -4
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/UtilsNCDatabase.java +4 -1
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/UtilsSQLCipher.java +8 -6
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/UtilsSQLite.java +14 -28
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/UtilsSecret.java +3 -4
- package/android/src/main/java/com/getcapacitor/community/database/sqlite/SQLite/UtilsUpgrade.java +0 -1
- package/dist/esm/definitions.d.ts +91 -4
- package/dist/esm/definitions.js +79 -19
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +3 -1
- package/dist/esm/web.js +8 -0
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +87 -19
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +87 -19
- package/dist/plugin.js.map +1 -1
- package/electron/dist/plugin.js +333 -148
- package/electron/dist/plugin.js.map +1 -1
- package/electron/rollup.config.js +2 -0
- package/ios/Plugin/CapacitorSQLite.swift +125 -92
- package/ios/Plugin/CapacitorSQLitePlugin.swift +6 -3
- package/ios/Plugin/Database.swift +45 -19
- package/ios/Plugin/ImportExportJson/ExportToJson.swift +10 -5
- package/ios/Plugin/ImportExportJson/ImportData.swift +434 -0
- package/ios/Plugin/ImportExportJson/ImportFromJson.swift +47 -59
- package/ios/Plugin/ImportExportJson/JsonSQLite.swift +7 -0
- package/ios/Plugin/Utils/UtilsDownloadFromHTTP.swift +61 -61
- package/ios/Plugin/Utils/UtilsDrop.swift +2 -1
- package/ios/Plugin/Utils/UtilsJson.swift +123 -1
- package/ios/Plugin/Utils/UtilsSQLCipher.swift +254 -23
- package/ios/Plugin/Utils/UtilsUpgrade.swift +0 -1
- package/package.json +2 -2
- package/src/definitions.ts +171 -18
- package/src/web.ts +10 -0
|
@@ -34,25 +34,24 @@ class ImportFromJson {
|
|
|
34
34
|
|
|
35
35
|
// MARK: - ImportFromJson - CreateDatabaseSchema
|
|
36
36
|
|
|
37
|
-
class func createDatabaseSchema(mDB: Database,
|
|
38
|
-
|
|
37
|
+
class func createDatabaseSchema(mDB: Database, tables: [ImportTable],
|
|
38
|
+
mode: String, version: Int)
|
|
39
39
|
throws -> Int {
|
|
40
40
|
let msg = "importFromJson: "
|
|
41
41
|
var changes: Int = -1
|
|
42
|
-
let version: Int = jsonSQLite.version
|
|
43
42
|
|
|
44
43
|
do {
|
|
45
44
|
// Set PRAGMAS
|
|
46
45
|
try UtilsSQLCipher.setVersion(mDB: mDB,
|
|
47
46
|
version: version)
|
|
48
|
-
if
|
|
47
|
+
if mode == "full" {
|
|
49
48
|
// Drop All Tables, Indexes and Triggers
|
|
50
49
|
try _ = UtilsDrop.dropAll(mDB: mDB)
|
|
51
50
|
}
|
|
52
51
|
// create database schema
|
|
53
52
|
changes = try ImportFromJson
|
|
54
53
|
.createSchema(mDB: mDB,
|
|
55
|
-
|
|
54
|
+
tables: tables, mode: mode)
|
|
56
55
|
let msg = "Schema creation completed changes: \(changes)"
|
|
57
56
|
notifyImportProgressEvent(msg: msg)
|
|
58
57
|
return changes
|
|
@@ -76,8 +75,8 @@ class ImportFromJson {
|
|
|
76
75
|
// MARK: - ImportFromJson - createSchema
|
|
77
76
|
|
|
78
77
|
// swiftlint:disable function_body_length
|
|
79
|
-
class func createSchema(mDB: Database,
|
|
80
|
-
|
|
78
|
+
class func createSchema(mDB: Database, tables: [ImportTable],
|
|
79
|
+
mode: String) throws -> Int {
|
|
81
80
|
var changes: Int = 0
|
|
82
81
|
var initChanges: Int = 0
|
|
83
82
|
do {
|
|
@@ -88,7 +87,7 @@ class ImportFromJson {
|
|
|
88
87
|
}
|
|
89
88
|
// Create a Schema Statements
|
|
90
89
|
let statements = ImportFromJson
|
|
91
|
-
.createSchemaStatement(
|
|
90
|
+
.createSchemaStatement(tables: tables, mode: mode )
|
|
92
91
|
if statements.count > 0 {
|
|
93
92
|
let joined = statements.joined(separator: "\n")
|
|
94
93
|
let mStmt: String = joined.replacingOccurrences(of: "\'", with: "'")
|
|
@@ -132,7 +131,7 @@ class ImportFromJson {
|
|
|
132
131
|
.createSchema(message: message)
|
|
133
132
|
}
|
|
134
133
|
} else {
|
|
135
|
-
if
|
|
134
|
+
if mode == "partial" {
|
|
136
135
|
changes = 0
|
|
137
136
|
// Commit the transaction
|
|
138
137
|
try UtilsSQLCipher.commitTransaction(mDB: mDB)
|
|
@@ -144,16 +143,15 @@ class ImportFromJson {
|
|
|
144
143
|
|
|
145
144
|
// MARK: - ImportFromJson - createSchemaStatement
|
|
146
145
|
|
|
147
|
-
class func createSchemaStatement(
|
|
148
|
-
|
|
146
|
+
class func createSchemaStatement(tables: [ImportTable],
|
|
147
|
+
mode: String) -> [String] {
|
|
149
148
|
// Create the Database Schema
|
|
150
149
|
var statements: [String] = []
|
|
151
150
|
// Loop through Tables
|
|
152
|
-
for ipos in 0..<
|
|
153
|
-
let mode: String =
|
|
154
|
-
let tableName: String =
|
|
155
|
-
if let mSchema: [
|
|
156
|
-
jsonSQLite.tables[ipos].schema {
|
|
151
|
+
for ipos in 0..<tables.count {
|
|
152
|
+
let mode: String = mode
|
|
153
|
+
let tableName: String = tables[ipos].name
|
|
154
|
+
if let mSchema: [ImportColumn] = tables[ipos].schema {
|
|
157
155
|
if mSchema.count > 0 {
|
|
158
156
|
let stmt: [String] =
|
|
159
157
|
ImportFromJson.createTableSchema(
|
|
@@ -162,8 +160,7 @@ class ImportFromJson {
|
|
|
162
160
|
statements.append(contentsOf: stmt)
|
|
163
161
|
}
|
|
164
162
|
}
|
|
165
|
-
if let mIndexes: [
|
|
166
|
-
jsonSQLite.tables[ipos].indexes {
|
|
163
|
+
if let mIndexes: [ImportIndex] = tables[ipos].indexes {
|
|
167
164
|
if mIndexes.count > 0 {
|
|
168
165
|
let stmt: [String] =
|
|
169
166
|
ImportFromJson.createTableIndexes(
|
|
@@ -171,8 +168,7 @@ class ImportFromJson {
|
|
|
171
168
|
statements.append(contentsOf: stmt)
|
|
172
169
|
}
|
|
173
170
|
}
|
|
174
|
-
if let mTriggers: [
|
|
175
|
-
jsonSQLite.tables[ipos].triggers {
|
|
171
|
+
if let mTriggers: [ImportTrigger] = tables[ipos].triggers {
|
|
176
172
|
if mTriggers.count > 0 {
|
|
177
173
|
let stmt: [String] =
|
|
178
174
|
ImportFromJson.createTableTriggers(
|
|
@@ -188,7 +184,7 @@ class ImportFromJson {
|
|
|
188
184
|
|
|
189
185
|
// swiftlint:disable function_body_length
|
|
190
186
|
// swiftlint:disable cyclomatic_complexity
|
|
191
|
-
class func createTableSchema(mSchema: [
|
|
187
|
+
class func createTableSchema(mSchema: [ImportColumn],
|
|
192
188
|
tableName: String, mode: String)
|
|
193
189
|
-> [String] {
|
|
194
190
|
var statements: [String] = []
|
|
@@ -251,7 +247,7 @@ class ImportFromJson {
|
|
|
251
247
|
|
|
252
248
|
// MARK: - ImportFromJson - CreateTableIndexes
|
|
253
249
|
|
|
254
|
-
class func createTableIndexes(mIndexes: [
|
|
250
|
+
class func createTableIndexes(mIndexes: [ImportIndex],
|
|
255
251
|
tableName: String) -> [String] {
|
|
256
252
|
var statements: [String] = []
|
|
257
253
|
for jpos in 0..<mIndexes.count {
|
|
@@ -279,7 +275,7 @@ class ImportFromJson {
|
|
|
279
275
|
|
|
280
276
|
// MARK: - ImportFromJson - CreateTableTriggers
|
|
281
277
|
|
|
282
|
-
class func createTableTriggers(mTriggers: [
|
|
278
|
+
class func createTableTriggers(mTriggers: [ImportTrigger],
|
|
283
279
|
tableName: String) -> [String] {
|
|
284
280
|
var statements: [String] = []
|
|
285
281
|
|
|
@@ -308,8 +304,8 @@ class ImportFromJson {
|
|
|
308
304
|
|
|
309
305
|
// swiftlint:disable function_body_length
|
|
310
306
|
class func createDatabaseData(mDB: Database,
|
|
311
|
-
|
|
312
|
-
|
|
307
|
+
tables: [ImportTable],
|
|
308
|
+
mode: String) throws -> Int {
|
|
313
309
|
var changes: Int = -1
|
|
314
310
|
var initChanges: Int = -1
|
|
315
311
|
var isValue: Bool = false
|
|
@@ -322,19 +318,19 @@ class ImportFromJson {
|
|
|
322
318
|
throw ImportFromJsonError.createDatabaseData(message: message)
|
|
323
319
|
}
|
|
324
320
|
// Loop on tables to create Data
|
|
325
|
-
for ipos in 0..<
|
|
326
|
-
if let mValues =
|
|
321
|
+
for ipos in 0..<tables.count {
|
|
322
|
+
if let mValues = tables[ipos].values {
|
|
327
323
|
if mValues.count > 0 {
|
|
328
324
|
isValue = true
|
|
329
325
|
do {
|
|
330
|
-
let tableName =
|
|
326
|
+
let tableName = tables[ipos].name
|
|
331
327
|
try ImportFromJson.createTableData(
|
|
332
328
|
mDB: mDB,
|
|
333
|
-
mode:
|
|
329
|
+
mode: mode,
|
|
334
330
|
mValues: mValues,
|
|
335
331
|
tableName: tableName)
|
|
336
332
|
let msg = "Table \(tableName) data creation completed " +
|
|
337
|
-
"\(ipos + 1)/\(
|
|
333
|
+
"\(ipos + 1)/\(tables.count) ..."
|
|
338
334
|
notifyImportProgressEvent(msg: msg)
|
|
339
335
|
|
|
340
336
|
} catch ImportFromJsonError
|
|
@@ -382,8 +378,9 @@ class ImportFromJson {
|
|
|
382
378
|
// swiftlint:disable function_body_length
|
|
383
379
|
class func createTableData(
|
|
384
380
|
mDB: Database, mode: String,
|
|
385
|
-
mValues: [[
|
|
381
|
+
mValues: [[Any]],
|
|
386
382
|
tableName: String) throws {
|
|
383
|
+
var lastId: Int64 = -1
|
|
387
384
|
// Check if table exists
|
|
388
385
|
do {
|
|
389
386
|
let isTab: Bool = try UtilsJson
|
|
@@ -409,8 +406,7 @@ class ImportFromJson {
|
|
|
409
406
|
}
|
|
410
407
|
for jpos in 0..<mValues.count {
|
|
411
408
|
// Check row validity
|
|
412
|
-
|
|
413
|
-
mValues[jpos]
|
|
409
|
+
var rowValues = mValues[jpos]
|
|
414
410
|
var isRun: Bool = true
|
|
415
411
|
|
|
416
412
|
/* Remove types checking for allowing RDBMS Types
|
|
@@ -429,10 +425,9 @@ class ImportFromJson {
|
|
|
429
425
|
"tableName": tableName]
|
|
430
426
|
let stmt: String = try ImportFromJson
|
|
431
427
|
.createRowStatement(mDB: mDB, data: data,
|
|
432
|
-
row:
|
|
428
|
+
row: rowValues,
|
|
433
429
|
jsonNamesTypes: jsonNamesTypes)
|
|
434
|
-
|
|
435
|
-
rowValues: row)
|
|
430
|
+
|
|
436
431
|
isRun = try UtilsJson.checkUpdate(mDB: mDB, stmt: stmt,
|
|
437
432
|
values: rowValues,
|
|
438
433
|
tableName: tableName,
|
|
@@ -443,8 +438,9 @@ class ImportFromJson {
|
|
|
443
438
|
if stmt.prefix(6) == "DELETE" {
|
|
444
439
|
rowValues = []
|
|
445
440
|
}
|
|
446
|
-
let
|
|
447
|
-
mDB: mDB, sql: stmt, values: rowValues, fromJson: true)
|
|
441
|
+
let resp = try UtilsSQLCipher.prepareSQL(
|
|
442
|
+
mDB: mDB, sql: stmt, values: rowValues, fromJson: true, returnMode: "no")
|
|
443
|
+
lastId = resp.0
|
|
448
444
|
if lastId < 0 {
|
|
449
445
|
throw ImportFromJsonError.createTableData(
|
|
450
446
|
message: "lastId < 0")
|
|
@@ -469,7 +465,7 @@ class ImportFromJson {
|
|
|
469
465
|
class func createRowStatement(
|
|
470
466
|
mDB: Database,
|
|
471
467
|
data: [String: Any],
|
|
472
|
-
row: [
|
|
468
|
+
row: [Any],
|
|
473
469
|
jsonNamesTypes: JsonNamesTypes) throws -> String {
|
|
474
470
|
var stmt: String = ""
|
|
475
471
|
var retisIdExists: Bool = false
|
|
@@ -487,19 +483,11 @@ class ImportFromJson {
|
|
|
487
483
|
message: message + " tableName")
|
|
488
484
|
}
|
|
489
485
|
do {
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
} else {
|
|
496
|
-
var message: String = "createRowStatement: Table "
|
|
497
|
-
message.append("\(tableName) values row[0] does not ")
|
|
498
|
-
message.append("exist")
|
|
499
|
-
throw ImportFromJsonError.createRowStatement(
|
|
500
|
-
message: message)
|
|
501
|
-
}
|
|
502
|
-
|
|
486
|
+
let rwValue = row[0]
|
|
487
|
+
retisIdExists = try UtilsJson.isIdExist(
|
|
488
|
+
mDB: mDB, tableName: tableName,
|
|
489
|
+
firstColumnName: jsonNamesTypes.names[0],
|
|
490
|
+
key: rwValue)
|
|
503
491
|
} catch UtilsJsonError.isIdExists(let message) {
|
|
504
492
|
throw ImportFromJsonError.createRowStatement(
|
|
505
493
|
message: message)
|
|
@@ -518,13 +506,13 @@ class ImportFromJson {
|
|
|
518
506
|
let idxDelete: Int = jsonNamesTypes
|
|
519
507
|
.names.firstIndex(where: {$0 == "sql_deleted"}) ?? -1
|
|
520
508
|
if idxDelete >= 0 {
|
|
521
|
-
if let delValue = row[idxDelete]
|
|
509
|
+
if let delValue = row[idxDelete] as? Int {
|
|
522
510
|
if delValue == 1 {
|
|
523
511
|
isUpdate = false
|
|
524
512
|
stmt = "DELETE FROM \(tableName) WHERE "
|
|
525
|
-
if let rwValue = row[0]
|
|
513
|
+
if let rwValue = row[0] as? String {
|
|
526
514
|
stmt += "\(jsonNamesTypes.names[0]) = '\(rwValue)';"
|
|
527
|
-
} else if let rwValue = row[0]
|
|
515
|
+
} else if let rwValue = row[0] as? Int {
|
|
528
516
|
stmt += "\(jsonNamesTypes.names[0]) = \(rwValue);"
|
|
529
517
|
} else {
|
|
530
518
|
var msg: String = "importFromJson: Table "
|
|
@@ -548,9 +536,9 @@ class ImportFromJson {
|
|
|
548
536
|
}
|
|
549
537
|
|
|
550
538
|
stmt = "UPDATE \(tableName) SET \(setString) WHERE "
|
|
551
|
-
if let rwValue = row[0]
|
|
539
|
+
if let rwValue = row[0] as? String {
|
|
552
540
|
stmt += "\(jsonNamesTypes.names[0]) = '\(rwValue)';"
|
|
553
|
-
} else if let rwValue = row[0]
|
|
541
|
+
} else if let rwValue = row[0] as? Int {
|
|
554
542
|
stmt += "\(jsonNamesTypes.names[0]) = \(rwValue);"
|
|
555
543
|
} else {
|
|
556
544
|
var msg: String = "importFromJson: Table "
|
|
@@ -568,7 +556,7 @@ class ImportFromJson {
|
|
|
568
556
|
// MARK: - ImportFromJson - createViews
|
|
569
557
|
|
|
570
558
|
// swiftlint:disable function_body_length
|
|
571
|
-
class func createViews(mDB: Database, views: [
|
|
559
|
+
class func createViews(mDB: Database, views: [ImportView]) throws -> Int {
|
|
572
560
|
var changes: Int = 0
|
|
573
561
|
var initChanges: Int = -1
|
|
574
562
|
var isView: Bool = false
|
|
@@ -631,7 +619,7 @@ class ImportFromJson {
|
|
|
631
619
|
return changes
|
|
632
620
|
|
|
633
621
|
}
|
|
634
|
-
class func createView(mDB: Database, view:
|
|
622
|
+
class func createView(mDB: Database, view: ImportView) throws {
|
|
635
623
|
let stmt = "CREATE VIEW IF NOT EXISTS \(view.name) AS \(view.value);"
|
|
636
624
|
do {
|
|
637
625
|
try UtilsSQLCipher.execute(mDB: mDB, sql: stmt)
|
|
@@ -39,80 +39,80 @@ class UtilsDownloadFromHTTP {
|
|
|
39
39
|
isDirectory: false
|
|
40
40
|
)
|
|
41
41
|
|
|
42
|
-
let task = URLSession.shared
|
|
43
|
-
(tempURL, response, error) in
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Copy the tempURL to file
|
|
63
|
-
try FileManager.default.copyItem(
|
|
64
|
-
at: tempURL,
|
|
65
|
-
to: fileCacheURL
|
|
66
|
-
)
|
|
67
|
-
// Delete the tempUrl file
|
|
68
|
-
try FileManager.default.removeItem(at: tempURL)
|
|
69
|
-
let dbURL = try UtilsFile.getDatabaseLocationURL(
|
|
70
|
-
databaseLocation: databaseLocation)
|
|
71
|
-
if isZip {
|
|
72
|
-
// get the zip files
|
|
73
|
-
let zipList: [String] = try UtilsFile
|
|
74
|
-
.getFileList(path: cacheURL.path,
|
|
75
|
-
ext: ".zip")
|
|
76
|
-
// loop through the database files
|
|
77
|
-
for zip in zipList {
|
|
78
|
-
_ = try UtilsFile.unzipToDatabase(
|
|
79
|
-
fromURL: cacheURL,
|
|
80
|
-
databaseLocation: tmp,
|
|
81
|
-
zip: zip,
|
|
82
|
-
overwrite: true)
|
|
42
|
+
let task = URLSession.shared
|
|
43
|
+
.downloadTask(with: mUrl) {(tempURL, response, error) in
|
|
44
|
+
// Early exit on error
|
|
45
|
+
guard let tempURL = tempURL else {
|
|
46
|
+
let msg = "\(String(describing: error?.localizedDescription))"
|
|
47
|
+
print("\(msg)")
|
|
48
|
+
completion(.failure(UtilsDownloadError.downloadFromHTTPFailed))
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
if let httpResponse = response as? HTTPURLResponse {
|
|
52
|
+
switch httpResponse.statusCode {
|
|
53
|
+
case 200:
|
|
54
|
+
do {
|
|
55
|
+
// Remove any existing document at file
|
|
56
|
+
if FileManager.default.fileExists(
|
|
57
|
+
atPath: fileCacheURL.path) {
|
|
58
|
+
try FileManager.default.removeItem(
|
|
59
|
+
atPath: fileCacheURL.path)
|
|
83
60
|
}
|
|
84
|
-
// Delete the zip file
|
|
85
|
-
try FileManager.default.removeItem(
|
|
86
|
-
at: fileCacheURL)
|
|
87
61
|
|
|
62
|
+
// Copy the tempURL to file
|
|
63
|
+
try FileManager.default.copyItem(
|
|
64
|
+
at: tempURL,
|
|
65
|
+
to: fileCacheURL
|
|
66
|
+
)
|
|
67
|
+
// Delete the tempUrl file
|
|
68
|
+
try FileManager.default.removeItem(at: tempURL)
|
|
69
|
+
let dbURL = try UtilsFile.getDatabaseLocationURL(
|
|
70
|
+
databaseLocation: databaseLocation)
|
|
71
|
+
if isZip {
|
|
72
|
+
// get the zip files
|
|
73
|
+
let zipList: [String] = try UtilsFile
|
|
74
|
+
.getFileList(path: cacheURL.path,
|
|
75
|
+
ext: ".zip")
|
|
76
|
+
// loop through the database files
|
|
77
|
+
for zip in zipList {
|
|
78
|
+
_ = try UtilsFile.unzipToDatabase(
|
|
79
|
+
fromURL: cacheURL,
|
|
80
|
+
databaseLocation: tmp,
|
|
81
|
+
zip: zip,
|
|
82
|
+
overwrite: true)
|
|
83
|
+
}
|
|
84
|
+
// Delete the zip file
|
|
85
|
+
try FileManager.default.removeItem(
|
|
86
|
+
at: fileCacheURL)
|
|
87
|
+
|
|
88
|
+
}
|
|
89
|
+
try UtilsFile.moveAllDBSQLite(
|
|
90
|
+
fromURL: cacheURL,
|
|
91
|
+
dirUrl: dbURL)
|
|
92
|
+
completion(.success(true))
|
|
93
|
+
return
|
|
88
94
|
}
|
|
89
|
-
try UtilsFile.moveAllDBSQLite(
|
|
90
|
-
fromURL: cacheURL,
|
|
91
|
-
dirUrl: dbURL)
|
|
92
|
-
completion(.success(true))
|
|
93
|
-
return
|
|
94
|
-
}
|
|
95
95
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
96
|
+
// Handle potential file system errors
|
|
97
|
+
catch let error {
|
|
98
|
+
let msg = "\(error.localizedDescription)"
|
|
99
|
+
print("\(msg)")
|
|
100
|
+
completion(.failure(UtilsDownloadError.downloadFromHTTPFailed))
|
|
101
|
+
return
|
|
102
|
+
}
|
|
103
|
+
default:
|
|
104
|
+
let msg = "Download: GET resquest not successful. http status code \(httpResponse.statusCode)"
|
|
99
105
|
print("\(msg)")
|
|
100
106
|
completion(.failure(UtilsDownloadError.downloadFromHTTPFailed))
|
|
101
107
|
return
|
|
102
108
|
}
|
|
103
|
-
|
|
104
|
-
let msg = "Download:
|
|
109
|
+
} else {
|
|
110
|
+
let msg = "Download: not a valid http response"
|
|
105
111
|
print("\(msg)")
|
|
106
112
|
completion(.failure(UtilsDownloadError.downloadFromHTTPFailed))
|
|
107
113
|
return
|
|
108
114
|
}
|
|
109
|
-
} else {
|
|
110
|
-
let msg = "Download: not a valid http response"
|
|
111
|
-
print("\(msg)")
|
|
112
|
-
completion(.failure(UtilsDownloadError.downloadFromHTTPFailed))
|
|
113
|
-
return
|
|
114
115
|
}
|
|
115
|
-
}
|
|
116
116
|
// Start the download
|
|
117
117
|
task.resume()
|
|
118
118
|
}
|
|
@@ -233,7 +233,8 @@ class UtilsDrop {
|
|
|
233
233
|
retChanges = try self.dropViews(mDB: mDB)
|
|
234
234
|
if changes >= 0 {
|
|
235
235
|
_ = try UtilsSQLCipher.prepareSQL(mDB: mDB, sql: "VACUUM;",
|
|
236
|
-
values: [], fromJson: false
|
|
236
|
+
values: [], fromJson: false,
|
|
237
|
+
returnMode: "no")
|
|
237
238
|
changes = UtilsSQLCipher.dbChanges(mDB: mDB.mDb) -
|
|
238
239
|
initChanges
|
|
239
240
|
}
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
//
|
|
7
7
|
|
|
8
8
|
import Foundation
|
|
9
|
+
import CryptoKit
|
|
10
|
+
import CommonCrypto
|
|
9
11
|
|
|
10
12
|
enum UtilsJsonError: Error {
|
|
11
13
|
case tableNotExists(message: String)
|
|
@@ -20,7 +22,12 @@ enum UtilsJsonError: Error {
|
|
|
20
22
|
case isLastModified(message: String)
|
|
21
23
|
case isSqlDeleted(message: String)
|
|
22
24
|
case checkUpdate(message: String)
|
|
23
|
-
case checkValues(message: String)
|
|
25
|
+
case checkValues(message: String)
|
|
26
|
+
case encryptDictionaryToBase64(message: String)
|
|
27
|
+
case decryptBase64ToDictionary(message: String)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
var mSalt = "jeep_capacitor_sqlite"
|
|
24
31
|
|
|
25
32
|
// swiftlint:disable file_length
|
|
26
33
|
// swiftlint:disable type_body_length
|
|
@@ -466,6 +473,121 @@ class UtilsJson {
|
|
|
466
473
|
return isViews
|
|
467
474
|
}
|
|
468
475
|
|
|
476
|
+
// MARK: encryptDictionaryToBase64
|
|
477
|
+
|
|
478
|
+
class func encryptDictionaryToBase64(_ dictionary: [String: Any], forAccount account: String) throws -> String {
|
|
479
|
+
// Encryption using Swift Crypto and Keychain-stored passphrase
|
|
480
|
+
|
|
481
|
+
let jsonData = try JSONSerialization.data(withJSONObject: dictionary)
|
|
482
|
+
|
|
483
|
+
let isPassPhrase = try UtilsSecret.isPassphrase(account: account)
|
|
484
|
+
if !isPassPhrase {
|
|
485
|
+
throw UtilsJsonError.encryptDictionaryToBase64(
|
|
486
|
+
message: "No passphrase stored")
|
|
487
|
+
}
|
|
488
|
+
let passphrase = UtilsSecret.getPassphrase(account: account)
|
|
489
|
+
// Generate a constant salt
|
|
490
|
+
let salt = Data(mSalt.utf8)
|
|
491
|
+
|
|
492
|
+
// Derive the encryption key using the passphrase and salt
|
|
493
|
+
guard let key = deriveSymmetricKeyFromPassphrase(passphrase, salt: salt) else {
|
|
494
|
+
throw UtilsJsonError.encryptDictionaryToBase64(
|
|
495
|
+
message: "No Encryption key returned")
|
|
496
|
+
}
|
|
497
|
+
let symKey = SymmetricKey(data: key)
|
|
498
|
+
|
|
499
|
+
// Use Swift Crypto to perform AES encryption with GCM mode
|
|
500
|
+
let sealedBox = try AES.GCM.seal(jsonData, using: symKey, nonce: AES.GCM.Nonce())
|
|
501
|
+
|
|
502
|
+
if let combined = sealedBox.combined {
|
|
503
|
+
// combined the salt and the encrypted data
|
|
504
|
+
var saltAndEncryptedData = salt
|
|
505
|
+
saltAndEncryptedData.append(combined)
|
|
506
|
+
// Convert to base64 string
|
|
507
|
+
|
|
508
|
+
let base64String = saltAndEncryptedData.base64EncodedString()
|
|
509
|
+
return base64String
|
|
510
|
+
} else {
|
|
511
|
+
throw UtilsJsonError.encryptDictionaryToBase64(
|
|
512
|
+
message: "Conversion to base64String failed")
|
|
513
|
+
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// MARK: decrypt DictionaryToBase64
|
|
519
|
+
|
|
520
|
+
class func decryptBase64ToDictionary(_ base64String: String,
|
|
521
|
+
forAccount account: String)
|
|
522
|
+
throws -> [String: Any] {
|
|
523
|
+
guard let data = Data(base64Encoded: base64String) else {
|
|
524
|
+
throw UtilsJsonError.decryptBase64ToDictionary(
|
|
525
|
+
message: "Conversion from Base64 to Dictionary failed")
|
|
526
|
+
|
|
527
|
+
}
|
|
528
|
+
let isPassPhrase = try UtilsSecret.isPassphrase(account: account)
|
|
529
|
+
if !isPassPhrase {
|
|
530
|
+
throw UtilsJsonError.decryptBase64ToDictionary(
|
|
531
|
+
message: "No passphrase stored")
|
|
532
|
+
}
|
|
533
|
+
let passphrase = UtilsSecret.getPassphrase(account: account)
|
|
534
|
+
// Generate a constant salt
|
|
535
|
+
let salt = Data(mSalt.utf8)
|
|
536
|
+
|
|
537
|
+
// Derive the encryption key using the passphrase and salt
|
|
538
|
+
guard let key = deriveSymmetricKeyFromPassphrase(passphrase,
|
|
539
|
+
salt: salt) else {
|
|
540
|
+
throw UtilsJsonError.encryptDictionaryToBase64(
|
|
541
|
+
message: "No Encryption key returned")
|
|
542
|
+
}
|
|
543
|
+
let symKey = SymmetricKey(data: key)
|
|
544
|
+
|
|
545
|
+
// Extract the encrypted data from the remaining bytes
|
|
546
|
+
let encryptedData = data.suffix(from: salt.count)
|
|
547
|
+
|
|
548
|
+
// Convert the base64 string to a sealed box
|
|
549
|
+
let sealedBox = try AES.GCM.SealedBox(combined: encryptedData)
|
|
550
|
+
|
|
551
|
+
// Decrypt the ciphertext using AES GCM open
|
|
552
|
+
let decryptedData = try AES.GCM.open(sealedBox, using: symKey)
|
|
553
|
+
|
|
554
|
+
// Convert decrypted data to dictionary
|
|
555
|
+
let dictionary = try JSONSerialization.jsonObject(
|
|
556
|
+
with: decryptedData) as? [String: Any] ?? [:]
|
|
557
|
+
|
|
558
|
+
return dictionary
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// MARK: deriveSymmetricKeyFromPassphrase
|
|
562
|
+
|
|
563
|
+
class func deriveSymmetricKeyFromPassphrase(_ passphrase: String,
|
|
564
|
+
salt: Data)
|
|
565
|
+
-> Data? {
|
|
566
|
+
|
|
567
|
+
let passphraseData = Data(passphrase.utf8)
|
|
568
|
+
let keyLength = kCCKeySizeAES256
|
|
569
|
+
let iterations: UInt32 = 10000
|
|
570
|
+
var derivedKeyData = Data(count: keyLength)
|
|
571
|
+
let derivedCount = derivedKeyData.count
|
|
572
|
+
let derivationStatus = derivedKeyData.withUnsafeMutableBytes { derivedKeyUnsafeMutableRawBufferPointer in
|
|
573
|
+
passphraseData.withUnsafeBytes { passphraseUnsafeRawBufferPointer in
|
|
574
|
+
salt.withUnsafeBytes { saltUnsafeRawBufferPointer in
|
|
575
|
+
CCKeyDerivationPBKDF(
|
|
576
|
+
CCPBKDFAlgorithm(kCCPBKDF2),
|
|
577
|
+
passphraseUnsafeRawBufferPointer.baseAddress,
|
|
578
|
+
passphraseData.count,
|
|
579
|
+
saltUnsafeRawBufferPointer.baseAddress,
|
|
580
|
+
salt.count,
|
|
581
|
+
CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA256),
|
|
582
|
+
iterations,
|
|
583
|
+
derivedKeyUnsafeMutableRawBufferPointer.baseAddress,
|
|
584
|
+
derivedCount
|
|
585
|
+
)
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
return derivationStatus == kCCSuccess ? derivedKeyData : nil
|
|
590
|
+
}
|
|
469
591
|
}
|
|
470
592
|
// swiftlint:enable type_body_length
|
|
471
593
|
// swiftlint:enable file_length
|