@capgo/capacitor-updater 4.17.37 → 4.17.39
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/LICENCE +367 -159
- package/README.md +13 -13
- package/android/src/main/java/ee/forgr/capacitor_updater/BundleInfo.java +6 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/BundleStatus.java +6 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdater.java +6 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdaterPlugin.java +7 -1
- package/android/src/main/java/ee/forgr/capacitor_updater/CryptoCipher.java +6 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/DelayCondition.java +6 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/DelayUntilNext.java +6 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/DownloadService.java +6 -0
- package/dist/docs.json +18 -18
- package/dist/esm/definitions.d.ts +13 -13
- package/dist/esm/definitions.js +5 -0
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/index.js +5 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/web.d.ts +4 -4
- package/dist/esm/web.js +11 -0
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +16 -0
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +16 -0
- package/dist/plugin.js.map +1 -1
- package/ios/Plugin/BundleInfo.swift +16 -10
- package/ios/Plugin/BundleStatus.swift +7 -1
- package/ios/Plugin/CapacitorUpdater.swift +94 -90
- package/ios/Plugin/CapacitorUpdaterPlugin.swift +93 -83
- package/ios/Plugin/CryptoCipher.swift +5 -26
- package/ios/Plugin/DelayCondition.swift +6 -0
- package/ios/Plugin/DelayUntilNext.swift +6 -0
- package/ios/Plugin/UserDefaultsExtension.swift +6 -0
- package/package.json +1 -1
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
|
+
*/
|
|
6
|
+
|
|
1
7
|
import Foundation
|
|
2
8
|
import Capacitor
|
|
3
9
|
import Version
|
|
@@ -9,11 +15,11 @@ import Version
|
|
|
9
15
|
@objc(CapacitorUpdaterPlugin)
|
|
10
16
|
public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
11
17
|
private var implementation = CapacitorUpdater()
|
|
12
|
-
private let
|
|
18
|
+
private let PLUGIN_VERSION: String = "4.17.39"
|
|
13
19
|
static let updateUrlDefault = "https://api.capgo.app/updates"
|
|
14
20
|
static let statsUrlDefault = "https://api.capgo.app/stats"
|
|
15
21
|
static let channelUrlDefault = "https://api.capgo.app/channel_self"
|
|
16
|
-
let
|
|
22
|
+
let DELAY_CONDITION_PREFERENCES = ""
|
|
17
23
|
private var updateUrl = ""
|
|
18
24
|
private var statsUrl = ""
|
|
19
25
|
private var defaultPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEA4pW9olT0FBXXivRCzd3xcImlWZrqkwcF2xTkX/FwXmj9eh9H\nkBLrsQmfsC+PJisRXIOGq6a0z3bsGq6jBpp3/Jr9jiaW5VuPGaKeMaZZBRvi/N5f\nIMG3hZXSOcy0IYg+E1Q7RkYO1xq5GLHseqG+PXvJsNe4R8R/Bmd/ngq0xh/cvcrH\nHpXwO0Aj9tfprlb+rHaVV79EkVRWYPidOLnK1n0EFHFJ1d/MyDIp10TEGm2xHpf/\nBrlb1an8wXEuzoC0DgYaczgTjovwR+ewSGhSHJliQdM0Qa3o1iN87DldWtydImMs\nPjJ3DUwpsjAMRe5X8Et4+udFW2ciYnQo9H0CkwIDAQABAoIBAQCtjlMV/4qBxAU4\nu0ZcWA9yywwraX0aJ3v1xrfzQYV322Wk4Ea5dbSxA5UcqCE29DA1M824t1Wxv/6z\npWbcTP9xLuresnJMtmgTE7umfiubvTONy2sENT20hgDkIwcq1CfwOEm61zjQzPhQ\nkSB5AmEsyR/BZEsUNc+ygR6AWOUFB7tj4yMc32LOTWSbE/znnF2BkmlmnQykomG1\n2oVqM3lUFP7+m8ux1O7scO6IMts+Z/eFXjWfxpbebUSvSIR83GXPQZ34S/c0ehOg\nyHdmCSOel1r3VvInMe+30j54Jr+Ml/7Ee6axiwyE2e/bd85MsK9sVdp0OtelXaqA\nOZZqWvN5AoGBAP2Hn3lSq+a8GsDH726mHJw60xM0LPbVJTYbXsmQkg1tl3NKJTMM\nQqz41+5uys+phEgLHI9gVJ0r+HaGHXnJ4zewlFjsudstb/0nfctUvTqnhEhfNo9I\ny4kufVKPRF3sMEeo7CDVJs4GNBLycEyIBy6Mbv0VcO7VaZqggRwu4no9AoGBAOTK\n6NWYs1BWlkua2wmxexGOzehNGedInp0wGr2l4FDayWjkZLqvB+nNXUQ63NdHlSs4\nWB2Z1kQXZxVaI2tPYexGUKXEo2uFob63uflbuE029ovDXIIPFTPtGNdNXwhHT5a+\nPhmy3sMc+s2BSNM5qaNmfxQxhdd6gRU6oikE+c0PAoGAMn3cKNFqIt27hkFLUgIL\nGKIuf1iYy9/PNWNmEUaVj88PpopRtkTu0nwMpROzmH/uNFriKTvKHjMvnItBO4wV\nkHW+VadvrFL0Rrqituf9d7z8/1zXBNo+juePVe3qc7oiM2NVA4Tv4YAixtM5wkQl\nCgQ15nlqsGYYTg9BJ1e/CxECgYEAjEYPzO2reuUrjr0p8F59ev1YJ0YmTJRMk0ks\nC/yIdGo/tGzbiU3JB0LfHPcN8Xu07GPGOpfYM7U5gXDbaG6qNgfCaHAQVdr/mQPi\nJQ1kCQtay8QCkscWk9iZM1//lP7LwDtxraXqSCwbZSYP9VlUNZeg8EuQqNU2EUL6\nqzWexmcCgYEA0prUGNBacraTYEknB1CsbP36UPWsqFWOvevlz+uEC5JPxPuW5ZHh\nSQN7xl6+PHyjPBM7ttwPKyhgLOVTb3K7ex/PXnudojMUK5fh7vYfChVTSlx2p6r0\nDi58PdD+node08cJH+ie0Yphp7m+D4+R9XD0v0nEvnu4BtAW6DrJasw=\n-----END RSA PRIVATE KEY-----\n"
|
|
@@ -29,11 +35,11 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
29
35
|
private var taskRunning = false
|
|
30
36
|
|
|
31
37
|
override public func load() {
|
|
32
|
-
print("\(self.implementation.
|
|
38
|
+
print("\(self.implementation.TAG) init for device \(self.implementation.deviceID)")
|
|
33
39
|
do {
|
|
34
40
|
currentVersionNative = try Version(Bundle.main.versionName ?? "0.0.0")
|
|
35
41
|
} catch {
|
|
36
|
-
print("\(self.implementation.
|
|
42
|
+
print("\(self.implementation.TAG) Cannot get version native \(currentVersionNative)")
|
|
37
43
|
}
|
|
38
44
|
autoDeleteFailed = getConfig().getBoolean("autoDeleteFailed", true)
|
|
39
45
|
autoDeletePrevious = getConfig().getBoolean("autoDeletePrevious", true)
|
|
@@ -44,7 +50,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
44
50
|
|
|
45
51
|
implementation.privateKey = getConfig().getString("privateKey", self.defaultPrivateKey)!
|
|
46
52
|
implementation.notifyDownload = notifyDownload
|
|
47
|
-
implementation.
|
|
53
|
+
implementation.PLUGIN_VERSION = self.PLUGIN_VERSION
|
|
48
54
|
let config = (self.bridge?.viewController as? CAPBridgeViewController)?.instanceDescriptor().legacyConfig
|
|
49
55
|
if config?["appId"] != nil {
|
|
50
56
|
implementation.appId = config?["appId"] as! String
|
|
@@ -62,24 +68,24 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
62
68
|
}
|
|
63
69
|
|
|
64
70
|
private func cleanupObsoleteVersions() {
|
|
65
|
-
var
|
|
71
|
+
var LatestVersionNative: Version = "0.0.0"
|
|
66
72
|
do {
|
|
67
|
-
|
|
73
|
+
LatestVersionNative = try Version(UserDefaults.standard.string(forKey: "LatestVersionNative") ?? "0.0.0")
|
|
68
74
|
} catch {
|
|
69
|
-
print("\(self.implementation.
|
|
75
|
+
print("\(self.implementation.TAG) Cannot get version native \(currentVersionNative)")
|
|
70
76
|
}
|
|
71
|
-
if
|
|
77
|
+
if LatestVersionNative != "0.0.0" && currentVersionNative.major > LatestVersionNative.major {
|
|
72
78
|
_ = self._reset(toLastSuccessful: false)
|
|
73
79
|
let res = implementation.list()
|
|
74
80
|
res.forEach { version in
|
|
75
|
-
print("\(self.implementation.
|
|
81
|
+
print("\(self.implementation.TAG) Deleting obsolete bundle: \(version)")
|
|
76
82
|
let res = implementation.delete(id: version.getId())
|
|
77
83
|
if !res {
|
|
78
|
-
print("\(self.implementation.
|
|
84
|
+
print("\(self.implementation.TAG) Delete failed, id \(version.getId()) doesn't exist")
|
|
79
85
|
}
|
|
80
86
|
}
|
|
81
87
|
}
|
|
82
|
-
UserDefaults.standard.set( self.currentVersionNative.description, forKey: "
|
|
88
|
+
UserDefaults.standard.set( self.currentVersionNative.description, forKey: "LatestVersionNative")
|
|
83
89
|
UserDefaults.standard.synchronize()
|
|
84
90
|
}
|
|
85
91
|
|
|
@@ -99,40 +105,40 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
99
105
|
}
|
|
100
106
|
|
|
101
107
|
@objc func getPluginVersion(_ call: CAPPluginCall) {
|
|
102
|
-
call.resolve(["version": self.
|
|
108
|
+
call.resolve(["version": self.PLUGIN_VERSION])
|
|
103
109
|
}
|
|
104
110
|
|
|
105
111
|
@objc func download(_ call: CAPPluginCall) {
|
|
106
112
|
guard let urlString = call.getString("url") else {
|
|
107
|
-
print("\(self.implementation.
|
|
113
|
+
print("\(self.implementation.TAG) Download called without url")
|
|
108
114
|
call.reject("Download called without url")
|
|
109
115
|
return
|
|
110
116
|
}
|
|
111
117
|
guard let version = call.getString("version") else {
|
|
112
|
-
print("\(self.implementation.
|
|
118
|
+
print("\(self.implementation.TAG) Download called without version")
|
|
113
119
|
call.reject("Download called without version")
|
|
114
120
|
return
|
|
115
121
|
}
|
|
116
122
|
let sessionKey = call.getString("sessionKey", "")
|
|
117
123
|
let checksum = call.getString("checksum", "")
|
|
118
124
|
let url = URL(string: urlString)
|
|
119
|
-
print("\(self.implementation.
|
|
125
|
+
print("\(self.implementation.TAG) Downloading \(url!)")
|
|
120
126
|
DispatchQueue.global(qos: .background).async {
|
|
121
127
|
do {
|
|
122
128
|
let next = try self.implementation.download(url: url!, version: version, sessionKey: sessionKey)
|
|
123
129
|
if checksum != "" && next.getChecksum() != checksum {
|
|
124
|
-
print("\(self.implementation.
|
|
130
|
+
print("\(self.implementation.TAG) Error checksum", next.getChecksum(), checksum)
|
|
125
131
|
self.implementation.sendStats(action: "checksum_fail", versionName: next.getVersionName())
|
|
126
132
|
let resDel = self.implementation.delete(id: next.getId())
|
|
127
133
|
if !resDel {
|
|
128
|
-
print("\(self.implementation.
|
|
134
|
+
print("\(self.implementation.TAG) Delete failed, id \(next.getId()) doesn't exist")
|
|
129
135
|
}
|
|
130
136
|
return
|
|
131
137
|
}
|
|
132
138
|
self.notifyListeners("updateAvailable", data: ["bundle": next.toJSON()])
|
|
133
139
|
call.resolve(next.toJSON())
|
|
134
140
|
} catch {
|
|
135
|
-
print("\(self.implementation.
|
|
141
|
+
print("\(self.implementation.TAG) Failed to download from: \(url!) \(error.localizedDescription)")
|
|
136
142
|
self.notifyListeners("downloadFailed", data: ["version": version])
|
|
137
143
|
let current: BundleInfo = self.implementation.getCurrentBundle()
|
|
138
144
|
self.implementation.sendStats(action: "download_fail", versionName: current.getVersionName())
|
|
@@ -145,7 +151,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
145
151
|
guard let bridge = self.bridge else { return false }
|
|
146
152
|
let id = self.implementation.getCurrentBundleId()
|
|
147
153
|
let destHot = self.implementation.getPathHot(id: id)
|
|
148
|
-
print("\(self.implementation.
|
|
154
|
+
print("\(self.implementation.TAG) Reloading \(id)")
|
|
149
155
|
if let vc = bridge.viewController as? CAPBridgeViewController {
|
|
150
156
|
vc.setServerBasePath(path: destHot.path)
|
|
151
157
|
self.checkAppReady()
|
|
@@ -159,20 +165,20 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
159
165
|
if self._reload() {
|
|
160
166
|
call.resolve()
|
|
161
167
|
} else {
|
|
162
|
-
print("\(self.implementation.
|
|
168
|
+
print("\(self.implementation.TAG) Reload failed")
|
|
163
169
|
call.reject("Reload failed")
|
|
164
170
|
}
|
|
165
171
|
}
|
|
166
172
|
|
|
167
173
|
@objc func next(_ call: CAPPluginCall) {
|
|
168
174
|
guard let id = call.getString("id") else {
|
|
169
|
-
print("\(self.implementation.
|
|
175
|
+
print("\(self.implementation.TAG) Next called without id")
|
|
170
176
|
call.reject("Next called without id")
|
|
171
177
|
return
|
|
172
178
|
}
|
|
173
|
-
print("\(self.implementation.
|
|
179
|
+
print("\(self.implementation.TAG) Setting next active id \(id)")
|
|
174
180
|
if !self.implementation.setNextBundle(next: id) {
|
|
175
|
-
print("\(self.implementation.
|
|
181
|
+
print("\(self.implementation.TAG) Set next version failed. id \(id) does not exist.")
|
|
176
182
|
call.reject("Set next version failed. id \(id) does not exist.")
|
|
177
183
|
} else {
|
|
178
184
|
call.resolve(self.implementation.getBundleInfo(id: id).toJSON())
|
|
@@ -181,14 +187,14 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
181
187
|
|
|
182
188
|
@objc func set(_ call: CAPPluginCall) {
|
|
183
189
|
guard let id = call.getString("id") else {
|
|
184
|
-
print("\(self.implementation.
|
|
190
|
+
print("\(self.implementation.TAG) Set called without id")
|
|
185
191
|
call.reject("Set called without id")
|
|
186
192
|
return
|
|
187
193
|
}
|
|
188
194
|
let res = implementation.set(id: id)
|
|
189
|
-
print("\(self.implementation.
|
|
195
|
+
print("\(self.implementation.TAG) Set active bundle: \(id)")
|
|
190
196
|
if !res {
|
|
191
|
-
print("\(self.implementation.
|
|
197
|
+
print("\(self.implementation.TAG) Bundle successfully set to: \(id) ")
|
|
192
198
|
call.reject("Update failed, id \(id) doesn't exist")
|
|
193
199
|
} else {
|
|
194
200
|
self.reload(call)
|
|
@@ -197,7 +203,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
197
203
|
|
|
198
204
|
@objc func delete(_ call: CAPPluginCall) {
|
|
199
205
|
guard let id = call.getString("id") else {
|
|
200
|
-
print("\(self.implementation.
|
|
206
|
+
print("\(self.implementation.TAG) Delete called without version")
|
|
201
207
|
call.reject("Delete called without id")
|
|
202
208
|
return
|
|
203
209
|
}
|
|
@@ -205,7 +211,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
205
211
|
if res {
|
|
206
212
|
call.resolve()
|
|
207
213
|
} else {
|
|
208
|
-
print("\(self.implementation.
|
|
214
|
+
print("\(self.implementation.TAG) Delete failed, id \(id) doesn't exist")
|
|
209
215
|
call.reject("Delete failed, id \(id) doesn't exist")
|
|
210
216
|
}
|
|
211
217
|
}
|
|
@@ -234,7 +240,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
234
240
|
|
|
235
241
|
@objc func setChannel(_ call: CAPPluginCall) {
|
|
236
242
|
guard let channel = call.getString("channel") else {
|
|
237
|
-
print("\(self.implementation.
|
|
243
|
+
print("\(self.implementation.TAG) setChannel called without channel")
|
|
238
244
|
call.reject("setChannel called without channel")
|
|
239
245
|
return
|
|
240
246
|
}
|
|
@@ -260,7 +266,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
260
266
|
}
|
|
261
267
|
@objc func setCustomId(_ call: CAPPluginCall) {
|
|
262
268
|
guard let customId = call.getString("customId") else {
|
|
263
|
-
print("\(self.implementation.
|
|
269
|
+
print("\(self.implementation.TAG) setCustomId called without customId")
|
|
264
270
|
call.reject("setCustomId called without customId")
|
|
265
271
|
return
|
|
266
272
|
}
|
|
@@ -276,11 +282,11 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
276
282
|
// If developer wants to reset to the last successful bundle, and that bundle is not
|
|
277
283
|
// the built-in bundle, set it as the bundle to use and reload.
|
|
278
284
|
if toLastSuccessful && !fallback.isBuiltin() {
|
|
279
|
-
print("\(self.implementation.
|
|
285
|
+
print("\(self.implementation.TAG) Resetting to: \(fallback.toString())")
|
|
280
286
|
return self.implementation.set(bundle: fallback) && self._reload()
|
|
281
287
|
}
|
|
282
288
|
|
|
283
|
-
print("\(self.implementation.
|
|
289
|
+
print("\(self.implementation.TAG) Resetting to builtin version")
|
|
284
290
|
|
|
285
291
|
// Otherwise, reset back to the built-in bundle and reload.
|
|
286
292
|
self.implementation.reset()
|
|
@@ -295,8 +301,8 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
295
301
|
if self._reset(toLastSuccessful: toLastSuccessful) {
|
|
296
302
|
call.resolve()
|
|
297
303
|
} else {
|
|
298
|
-
print("\(self.implementation.
|
|
299
|
-
call.reject("\(self.implementation.
|
|
304
|
+
print("\(self.implementation.TAG) Reset failed")
|
|
305
|
+
call.reject("\(self.implementation.TAG) Reset failed")
|
|
300
306
|
}
|
|
301
307
|
}
|
|
302
308
|
|
|
@@ -311,13 +317,13 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
311
317
|
@objc func notifyAppReady(_ call: CAPPluginCall) {
|
|
312
318
|
let version = self.implementation.getCurrentBundle()
|
|
313
319
|
self.implementation.setSuccess(bundle: version, autoDeletePrevious: self.autoDeletePrevious)
|
|
314
|
-
print("\(self.implementation.
|
|
320
|
+
print("\(self.implementation.TAG) Current bundle loaded successfully. ['notifyAppReady()' was called] \(version.toString())")
|
|
315
321
|
call.resolve()
|
|
316
322
|
}
|
|
317
323
|
|
|
318
324
|
@objc func setMultiDelay(_ call: CAPPluginCall) {
|
|
319
325
|
guard let delayConditionList = call.getValue("delayConditions") else {
|
|
320
|
-
print("\(self.implementation.
|
|
326
|
+
print("\(self.implementation.TAG) setMultiDelay called without delayCondition")
|
|
321
327
|
call.reject("setMultiDelay called without delayCondition")
|
|
322
328
|
return
|
|
323
329
|
}
|
|
@@ -343,19 +349,19 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
343
349
|
|
|
344
350
|
private func _setMultiDelay(delayConditions: String?) -> Bool {
|
|
345
351
|
if delayConditions != nil && "" != delayConditions {
|
|
346
|
-
UserDefaults.standard.set(delayConditions, forKey:
|
|
352
|
+
UserDefaults.standard.set(delayConditions, forKey: DELAY_CONDITION_PREFERENCES)
|
|
347
353
|
UserDefaults.standard.synchronize()
|
|
348
|
-
print("\(self.implementation.
|
|
354
|
+
print("\(self.implementation.TAG) Delay update saved.")
|
|
349
355
|
return true
|
|
350
356
|
} else {
|
|
351
|
-
print("\(self.implementation.
|
|
357
|
+
print("\(self.implementation.TAG) Failed to delay update, [Error calling '_setMultiDelay()']")
|
|
352
358
|
return false
|
|
353
359
|
}
|
|
354
360
|
}
|
|
355
361
|
|
|
356
362
|
private func _cancelDelay(source: String) {
|
|
357
|
-
print("\(self.implementation.
|
|
358
|
-
UserDefaults.standard.removeObject(forKey:
|
|
363
|
+
print("\(self.implementation.TAG) delay Canceled from \(source)")
|
|
364
|
+
UserDefaults.standard.removeObject(forKey: DELAY_CONDITION_PREFERENCES)
|
|
359
365
|
UserDefaults.standard.synchronize()
|
|
360
366
|
}
|
|
361
367
|
|
|
@@ -364,8 +370,8 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
364
370
|
call.resolve()
|
|
365
371
|
}
|
|
366
372
|
|
|
367
|
-
private func
|
|
368
|
-
let delayUpdatePreferences = UserDefaults.standard.string(forKey:
|
|
373
|
+
private func _checkCancelDelay(killed: Bool) {
|
|
374
|
+
let delayUpdatePreferences = UserDefaults.standard.string(forKey: DELAY_CONDITION_PREFERENCES) ?? "[]"
|
|
369
375
|
let delayConditionList: [DelayCondition] = fromJsonArr(json: delayUpdatePreferences).map { obj -> DelayCondition in
|
|
370
376
|
let kind: String = obj.value(forKey: "kind") as! String
|
|
371
377
|
let value: String? = obj.value(forKey: "value") as? String
|
|
@@ -380,25 +386,28 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
380
386
|
if !killed {
|
|
381
387
|
self._cancelDelay(source: "background check")
|
|
382
388
|
}
|
|
389
|
+
break
|
|
383
390
|
case "kill":
|
|
384
391
|
if killed {
|
|
385
392
|
self._cancelDelay(source: "kill check")
|
|
386
393
|
// instant install for kill action
|
|
387
394
|
self.installNext()
|
|
388
395
|
}
|
|
396
|
+
break
|
|
389
397
|
case "date":
|
|
390
398
|
if value != nil && value != "" {
|
|
391
399
|
let dateFormatter = ISO8601DateFormatter()
|
|
392
|
-
guard let
|
|
400
|
+
guard let ExpireDate = dateFormatter.date(from: value!) else {
|
|
393
401
|
self._cancelDelay(source: "date parsing issue")
|
|
394
402
|
return
|
|
395
403
|
}
|
|
396
|
-
if
|
|
404
|
+
if ExpireDate < Date() {
|
|
397
405
|
self._cancelDelay(source: "date expired")
|
|
398
406
|
}
|
|
399
407
|
} else {
|
|
400
408
|
self._cancelDelay(source: "delayVal absent")
|
|
401
409
|
}
|
|
410
|
+
break
|
|
402
411
|
case "nativeVersion":
|
|
403
412
|
if value != nil && value != "" {
|
|
404
413
|
do {
|
|
@@ -412,10 +421,11 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
412
421
|
} else {
|
|
413
422
|
self._cancelDelay(source: "delayVal absent")
|
|
414
423
|
}
|
|
424
|
+
break
|
|
415
425
|
case .none:
|
|
416
|
-
print("\(self.implementation.
|
|
426
|
+
print("\(self.implementation.TAG) _checkCancelDelay switch case none error")
|
|
417
427
|
case .some:
|
|
418
|
-
print("\(self.implementation.
|
|
428
|
+
print("\(self.implementation.TAG) _checkCancelDelay switch case some error")
|
|
419
429
|
}
|
|
420
430
|
}
|
|
421
431
|
}
|
|
@@ -435,9 +445,9 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
435
445
|
func checkAppReady() {
|
|
436
446
|
self.appReadyCheck?.cancel()
|
|
437
447
|
self.appReadyCheck = DispatchWorkItem(block: {
|
|
438
|
-
self.
|
|
448
|
+
self.DeferredNotifyAppReadyCheck()
|
|
439
449
|
})
|
|
440
|
-
print("\(self.implementation.
|
|
450
|
+
print("\(self.implementation.TAG) Wait for \(self.appReadyTimeout) ms, then check for notifyAppReady")
|
|
441
451
|
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(self.appReadyTimeout), execute: self.appReadyCheck!)
|
|
442
452
|
}
|
|
443
453
|
|
|
@@ -445,15 +455,15 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
445
455
|
// Automatically roll back to fallback version if notifyAppReady has not been called yet
|
|
446
456
|
let current: BundleInfo = self.implementation.getCurrentBundle()
|
|
447
457
|
if current.isBuiltin() {
|
|
448
|
-
print("\(self.implementation.
|
|
458
|
+
print("\(self.implementation.TAG) Built-in bundle is active. Nothing to do.")
|
|
449
459
|
return
|
|
450
460
|
}
|
|
451
461
|
|
|
452
|
-
print("\(self.implementation.
|
|
462
|
+
print("\(self.implementation.TAG) Current bundle is: \(current.toString())")
|
|
453
463
|
|
|
454
464
|
if BundleStatus.SUCCESS.localizedString != current.getStatus() {
|
|
455
|
-
print("\(self.implementation.
|
|
456
|
-
print("\(self.implementation.
|
|
465
|
+
print("\(self.implementation.TAG) notifyAppReady was not called, roll back current bundle: \(current.toString())")
|
|
466
|
+
print("\(self.implementation.TAG) Did you forget to call 'notifyAppReady()' in your Capacitor App code?")
|
|
457
467
|
self.notifyListeners("updateFailed", data: [
|
|
458
468
|
"bundle": current.toJSON()
|
|
459
469
|
])
|
|
@@ -461,20 +471,20 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
461
471
|
self.implementation.setError(bundle: current)
|
|
462
472
|
_ = self._reset(toLastSuccessful: true)
|
|
463
473
|
if self.autoDeleteFailed && !current.isBuiltin() {
|
|
464
|
-
print("\(self.implementation.
|
|
474
|
+
print("\(self.implementation.TAG) Deleting failing bundle: \(current.toString())")
|
|
465
475
|
let res = self.implementation.delete(id: current.getId(), removeInfo: false)
|
|
466
476
|
if !res {
|
|
467
|
-
print("\(self.implementation.
|
|
477
|
+
print("\(self.implementation.TAG) Delete version deleted: \(current.toString())")
|
|
468
478
|
} else {
|
|
469
|
-
print("\(self.implementation.
|
|
479
|
+
print("\(self.implementation.TAG) Failed to delete failed bundle: \(current.toString())")
|
|
470
480
|
}
|
|
471
481
|
}
|
|
472
482
|
} else {
|
|
473
|
-
print("\(self.implementation.
|
|
483
|
+
print("\(self.implementation.TAG) notifyAppReady was called. This is fine: \(current.toString())")
|
|
474
484
|
}
|
|
475
485
|
}
|
|
476
486
|
|
|
477
|
-
func
|
|
487
|
+
func DeferredNotifyAppReadyCheck() {
|
|
478
488
|
self.checkRevert()
|
|
479
489
|
self.appReadyCheck = nil
|
|
480
490
|
}
|
|
@@ -490,13 +500,13 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
490
500
|
// End the task if time expires.
|
|
491
501
|
self.endBackGroundTask()
|
|
492
502
|
}
|
|
493
|
-
print("\(self.implementation.
|
|
503
|
+
print("\(self.implementation.TAG) Check for update via \(self.updateUrl)")
|
|
494
504
|
let url = URL(string: self.updateUrl)!
|
|
495
505
|
let res = self.implementation.getLatest(url: url)
|
|
496
506
|
let current = self.implementation.getCurrentBundle()
|
|
497
507
|
|
|
498
508
|
if (res.message) != nil {
|
|
499
|
-
print("\(self.implementation.
|
|
509
|
+
print("\(self.implementation.TAG) message \(res.message ?? "")")
|
|
500
510
|
if res.major == true {
|
|
501
511
|
self.notifyListeners("majorAvailable", data: ["version": res.version])
|
|
502
512
|
}
|
|
@@ -506,7 +516,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
506
516
|
}
|
|
507
517
|
let sessionKey = res.sessionKey ?? ""
|
|
508
518
|
guard let downloadUrl = URL(string: res.url) else {
|
|
509
|
-
print("\(self.implementation.
|
|
519
|
+
print("\(self.implementation.TAG) Error no url or wrong format")
|
|
510
520
|
self.notifyListeners("noNeedUpdate", data: ["bundle": current.toJSON()])
|
|
511
521
|
self.endBackGroundTask()
|
|
512
522
|
return
|
|
@@ -516,38 +526,38 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
516
526
|
let latest = self.implementation.getBundleInfoByVersionName(version: latestVersionName)
|
|
517
527
|
if latest != nil {
|
|
518
528
|
if latest!.isErrorStatus() {
|
|
519
|
-
print("\(self.implementation.
|
|
529
|
+
print("\(self.implementation.TAG) Latest version already exists, and is in error state. Aborting update.")
|
|
520
530
|
self.notifyListeners("noNeedUpdate", data: ["bundle": current.toJSON()])
|
|
521
531
|
self.endBackGroundTask()
|
|
522
532
|
return
|
|
523
533
|
}
|
|
524
534
|
if latest!.isDownloaded() {
|
|
525
|
-
print("\(self.implementation.
|
|
535
|
+
print("\(self.implementation.TAG) Latest version already exists and download is NOT required. Update will occur next time app moves to background.")
|
|
526
536
|
self.notifyListeners("updateAvailable", data: ["bundle": current.toJSON()])
|
|
527
537
|
_ = self.implementation.setNextBundle(next: latest!.getId())
|
|
528
538
|
self.endBackGroundTask()
|
|
529
539
|
return
|
|
530
540
|
}
|
|
531
541
|
if latest!.isDeleted() {
|
|
532
|
-
print("\(self.implementation.
|
|
542
|
+
print("\(self.implementation.TAG) Latest bundle already exists and will be deleted, download will overwrite it.")
|
|
533
543
|
let res = self.implementation.delete(id: latest!.getId(), removeInfo: true)
|
|
534
544
|
if !res {
|
|
535
|
-
print("\(self.implementation.
|
|
545
|
+
print("\(self.implementation.TAG) Delete version deleted: \(latest!.toString())")
|
|
536
546
|
} else {
|
|
537
|
-
print("\(self.implementation.
|
|
547
|
+
print("\(self.implementation.TAG) Failed to delete failed bundle: \(latest!.toString())")
|
|
538
548
|
}
|
|
539
549
|
}
|
|
540
550
|
}
|
|
541
551
|
|
|
542
552
|
do {
|
|
543
|
-
print("\(self.implementation.
|
|
553
|
+
print("\(self.implementation.TAG) New bundle: \(latestVersionName) found. Current is: \(current.getVersionName()). Update will occur next time app moves to background.")
|
|
544
554
|
let next = try self.implementation.download(url: downloadUrl, version: latestVersionName, sessionKey: sessionKey)
|
|
545
555
|
if res.checksum != "" && next.getChecksum() != res.checksum {
|
|
546
|
-
print("\(self.implementation.
|
|
556
|
+
print("\(self.implementation.TAG) Error checksum", next.getChecksum(), res.checksum)
|
|
547
557
|
self.implementation.sendStats(action: "checksum_fail", versionName: next.getVersionName())
|
|
548
558
|
let resDel = self.implementation.delete(id: next.getId())
|
|
549
559
|
if !resDel {
|
|
550
|
-
print("\(self.implementation.
|
|
560
|
+
print("\(self.implementation.TAG) Delete failed, id \(next.getId()) doesn't exist")
|
|
551
561
|
}
|
|
552
562
|
self.endBackGroundTask()
|
|
553
563
|
return
|
|
@@ -555,14 +565,14 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
555
565
|
self.notifyListeners("updateAvailable", data: ["bundle": next.toJSON()])
|
|
556
566
|
_ = self.implementation.setNextBundle(next: next.getId())
|
|
557
567
|
} catch {
|
|
558
|
-
print("\(self.implementation.
|
|
568
|
+
print("\(self.implementation.TAG) Error downloading file", error.localizedDescription)
|
|
559
569
|
let current: BundleInfo = self.implementation.getCurrentBundle()
|
|
560
570
|
self.implementation.sendStats(action: "download_fail", versionName: current.getVersionName())
|
|
561
571
|
self.notifyListeners("downloadFailed", data: ["version": latestVersionName])
|
|
562
572
|
self.notifyListeners("noNeedUpdate", data: ["bundle": current.toJSON()])
|
|
563
573
|
}
|
|
564
574
|
} else {
|
|
565
|
-
print("\(self.implementation.
|
|
575
|
+
print("\(self.implementation.TAG) No need to update, \(current.getId()) is the latest bundle.")
|
|
566
576
|
self.notifyListeners("noNeedUpdate", data: ["bundle": current.toJSON()])
|
|
567
577
|
}
|
|
568
578
|
self.endBackGroundTask()
|
|
@@ -570,30 +580,30 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
570
580
|
}
|
|
571
581
|
|
|
572
582
|
@objc func appKilled() {
|
|
573
|
-
self.
|
|
583
|
+
self._checkCancelDelay(killed: true)
|
|
574
584
|
}
|
|
575
585
|
|
|
576
586
|
private func installNext() {
|
|
577
|
-
let delayUpdatePreferences = UserDefaults.standard.string(forKey:
|
|
587
|
+
let delayUpdatePreferences = UserDefaults.standard.string(forKey: DELAY_CONDITION_PREFERENCES) ?? "[]"
|
|
578
588
|
let delayConditionList: [DelayCondition]? = fromJsonArr(json: delayUpdatePreferences).map { obj -> DelayCondition in
|
|
579
589
|
let kind: String = obj.value(forKey: "kind") as! String
|
|
580
590
|
let value: String? = obj.value(forKey: "value") as? String
|
|
581
591
|
return DelayCondition(kind: kind, value: value)
|
|
582
592
|
}
|
|
583
593
|
if delayConditionList != nil && delayConditionList?.capacity != 0 {
|
|
584
|
-
print("\(self.implementation.
|
|
594
|
+
print("\(self.implementation.TAG) Update delayed to next backgrounding")
|
|
585
595
|
return
|
|
586
596
|
}
|
|
587
597
|
let current: BundleInfo = self.implementation.getCurrentBundle()
|
|
588
598
|
let next: BundleInfo? = self.implementation.getNextBundle()
|
|
589
599
|
|
|
590
600
|
if next != nil && !next!.isErrorStatus() && next!.getVersionName() != current.getVersionName() {
|
|
591
|
-
print("\(self.implementation.
|
|
601
|
+
print("\(self.implementation.TAG) Next bundle is: \(next!.toString())")
|
|
592
602
|
if self.implementation.set(bundle: next!) && self._reload() {
|
|
593
|
-
print("\(self.implementation.
|
|
603
|
+
print("\(self.implementation.TAG) Updated to bundle: \(next!.toString())")
|
|
594
604
|
_ = self.implementation.setNextBundle(next: Optional<String>.none)
|
|
595
605
|
} else {
|
|
596
|
-
print("\(self.implementation.
|
|
606
|
+
print("\(self.implementation.TAG) Update to bundle: \(next!.toString()) Failed!")
|
|
597
607
|
}
|
|
598
608
|
}
|
|
599
609
|
}
|
|
@@ -617,7 +627,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
617
627
|
@objc func appMovedToForeground() {
|
|
618
628
|
if backgroundWork != nil && taskRunning {
|
|
619
629
|
backgroundWork!.cancel()
|
|
620
|
-
print("\(self.implementation.
|
|
630
|
+
print("\(self.implementation.TAG) Background Timer Task canceled, Activity resumed before timer completes")
|
|
621
631
|
}
|
|
622
632
|
if self._isAutoUpdateEnabled() {
|
|
623
633
|
self.backgroundDownload()
|
|
@@ -626,8 +636,8 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
626
636
|
}
|
|
627
637
|
|
|
628
638
|
@objc func appMovedToBackground() {
|
|
629
|
-
print("\(self.implementation.
|
|
630
|
-
let delayUpdatePreferences = UserDefaults.standard.string(forKey:
|
|
639
|
+
print("\(self.implementation.TAG) Check for pending update")
|
|
640
|
+
let delayUpdatePreferences = UserDefaults.standard.string(forKey: DELAY_CONDITION_PREFERENCES) ?? "[]"
|
|
631
641
|
|
|
632
642
|
let delayConditionList: [DelayCondition] = fromJsonArr(json: delayUpdatePreferences).map { obj -> DelayCondition in
|
|
633
643
|
let kind: String = obj.value(forKey: "kind") as! String
|
|
@@ -648,12 +658,12 @@ public class CapacitorUpdaterPlugin: CAPPlugin {
|
|
|
648
658
|
self.backgroundWork = DispatchWorkItem(block: {
|
|
649
659
|
// IOS never executes this task in background
|
|
650
660
|
self.taskRunning = false
|
|
651
|
-
self.
|
|
661
|
+
self._checkCancelDelay(killed: false)
|
|
652
662
|
self.installNext()
|
|
653
663
|
})
|
|
654
664
|
DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + interval, execute: self.backgroundWork!)
|
|
655
665
|
} else {
|
|
656
|
-
self.
|
|
666
|
+
self._checkCancelDelay(killed: false)
|
|
657
667
|
self.installNext()
|
|
658
668
|
}
|
|
659
669
|
|
|
@@ -1,29 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
//
|
|
7
|
-
// While this file was written from scratch, it was inspired by reading
|
|
8
|
-
// through https://github.com/henrinormak/Heimdall which is under MIT.
|
|
9
|
-
// Some function implementations were copied from Heimdall as well.
|
|
10
|
-
//
|
|
11
|
-
// SimpleSwiftCrypto does not store credentials in the Keychain by design.
|
|
12
|
-
// I'm willing to accept a PR that adds this though.
|
|
13
|
-
//
|
|
14
|
-
// The primary motive for making this was to make App Maker Cloud secure.
|
|
15
|
-
// App Maker Professional, an IDE for iPad/iOS, communicates with the
|
|
16
|
-
// App Maker Cloud server. This enables multiplayer features (much like
|
|
17
|
-
// "VS Live Share"). To keep all clients' source code secure, all data
|
|
18
|
-
// is not only transferred over WebSockets https/wss, but is also
|
|
19
|
-
// also first encrypted by using a shared AES key generated by a client
|
|
20
|
-
// which is propagated to the others via RSA. This way, the server never
|
|
21
|
-
// has the shared AES key while all clients will have a copy of it. The
|
|
22
|
-
// server can then safely work with private repositories of users without
|
|
23
|
-
// ever being able to see their code. This solution did not need to use
|
|
24
|
-
// Keychain because no persistence was needed as new keys are generated for
|
|
25
|
-
// each "Live Session".
|
|
26
|
-
//
|
|
1
|
+
/*
|
|
2
|
+
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
|
+
*/
|
|
27
6
|
|
|
28
7
|
import Foundation
|
|
29
8
|
import CommonCrypto
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
5
|
+
*/
|
|
6
|
+
|
|
1
7
|
import Foundation
|
|
2
8
|
|
|
3
9
|
protocol ObjectSavable {
|