@capgo/cordova-updater 8.1.1

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.
Files changed (76) hide show
  1. package/LICENSE +373 -0
  2. package/README.md +82 -0
  3. package/dist/esm/definitions.d.ts +2684 -0
  4. package/dist/esm/definitions.js +109 -0
  5. package/dist/esm/definitions.js.map +1 -0
  6. package/dist/esm/exec.d.ts +4 -0
  7. package/dist/esm/exec.js +25 -0
  8. package/dist/esm/exec.js.map +1 -0
  9. package/dist/esm/history.d.ts +1 -0
  10. package/dist/esm/history.js +283 -0
  11. package/dist/esm/history.js.map +1 -0
  12. package/dist/esm/index.d.ts +57 -0
  13. package/dist/esm/index.js +68 -0
  14. package/dist/esm/index.js.map +1 -0
  15. package/dist/esm/plugin.d.ts +57 -0
  16. package/dist/esm/plugin.js +15 -0
  17. package/dist/esm/plugin.js.map +1 -0
  18. package/dist/plugin.cjs.js +217 -0
  19. package/dist/plugin.cjs.js.map +1 -0
  20. package/dist/plugin.js +222 -0
  21. package/dist/plugin.js.map +1 -0
  22. package/package.json +96 -0
  23. package/plugin.xml +207 -0
  24. package/src/android/CordovaUpdaterPlugin.java +5662 -0
  25. package/src/android/UpdaterPathHandler.java +99 -0
  26. package/src/android/app/capgo/cordova/updater/AndroidAppExitReporter.java +92 -0
  27. package/src/android/app/capgo/cordova/updater/AppLifecycleObserver.java +115 -0
  28. package/src/android/app/capgo/cordova/updater/BundleInfo.java +246 -0
  29. package/src/android/app/capgo/cordova/updater/BundleStatus.java +45 -0
  30. package/src/android/app/capgo/cordova/updater/Callback.java +13 -0
  31. package/src/android/app/capgo/cordova/updater/CapgoUpdater.java +3404 -0
  32. package/src/android/app/capgo/cordova/updater/CordovaUpdaterConfig.java +56 -0
  33. package/src/android/app/capgo/cordova/updater/CryptoCipher.java +462 -0
  34. package/src/android/app/capgo/cordova/updater/DataManager.java +44 -0
  35. package/src/android/app/capgo/cordova/updater/DelayCondition.java +56 -0
  36. package/src/android/app/capgo/cordova/updater/DelayUntilNext.java +14 -0
  37. package/src/android/app/capgo/cordova/updater/DelayUpdateUtils.java +307 -0
  38. package/src/android/app/capgo/cordova/updater/DeviceIdHelper.java +230 -0
  39. package/src/android/app/capgo/cordova/updater/DownloadService.java +1219 -0
  40. package/src/android/app/capgo/cordova/updater/DownloadWorkerManager.java +260 -0
  41. package/src/android/app/capgo/cordova/updater/InternalUtils.java +54 -0
  42. package/src/android/app/capgo/cordova/updater/Logger.java +345 -0
  43. package/src/android/app/capgo/cordova/updater/ShakeDetector.java +72 -0
  44. package/src/android/app/capgo/cordova/updater/ShakeMenu.java +39 -0
  45. package/src/android/app/capgo/cordova/updater/ThreeFingerPinchDetector.java +323 -0
  46. package/src/android/app/capgo/cordova/updater/compat/JSArray.java +9 -0
  47. package/src/android/app/capgo/cordova/updater/compat/JSObject.java +83 -0
  48. package/src/android/app/capgo/cordova/updater/compat/PluginCall.java +165 -0
  49. package/src/android/capgo-cordova-updater.gradle +19 -0
  50. package/src/android/capgo-updater.xml +3 -0
  51. package/src/android/test/app/capgo/cordova/updater/CapacitorUpdaterUnitTest.java.skip +3039 -0
  52. package/src/android/test/app/capgo/cordova/updater/DelayUpdateUtilsTest.java +177 -0
  53. package/src/android/test/app/capgo/cordova/updater/NativeContractTest.java +105 -0
  54. package/src/ios/AES.swift +216 -0
  55. package/src/ios/AppHealthTracker.swift +82 -0
  56. package/src/ios/BundleInfo.swift +185 -0
  57. package/src/ios/BundleStatus.swift +127 -0
  58. package/src/ios/CapgoRawRsa.swift +36 -0
  59. package/src/ios/CapgoUpdater.swift +3544 -0
  60. package/src/ios/CordovaCompat.swift +11 -0
  61. package/src/ios/CordovaPluginCall.swift +190 -0
  62. package/src/ios/CordovaUpdaterCommands.swift +270 -0
  63. package/src/ios/CordovaUpdaterPlugin.swift +4706 -0
  64. package/src/ios/CryptoCipher.swift +326 -0
  65. package/src/ios/DelayCondition.swift +74 -0
  66. package/src/ios/DelayUntilNext.swift +30 -0
  67. package/src/ios/DelayUpdateUtils.swift +257 -0
  68. package/src/ios/DeviceIdHelper.swift +120 -0
  69. package/src/ios/Info.plist +28 -0
  70. package/src/ios/InternalUtils.swift +471 -0
  71. package/src/ios/Logger.swift +283 -0
  72. package/src/ios/RSA.swift +96 -0
  73. package/src/ios/ShakeMenu.swift +52 -0
  74. package/src/ios/UpdaterSchemeHandler.swift +81 -0
  75. package/src/ios/UserDefaultsExtension.swift +46 -0
  76. package/src/ios/WebViewStatsReporter.swift +303 -0
@@ -0,0 +1,303 @@
1
+ import Foundation
2
+ import WebKit
3
+
4
+ final class WebViewStatsReporter {
5
+ static let script = """
6
+ (function(){
7
+ if(window.__capgoWebViewErrorReporterInstalled){return;}
8
+ window.__capgoWebViewErrorReporterInstalled=true;
9
+ var maxReports=20,sentReports=0,queue=[],seen={};
10
+ var sessionKey='CapacitorUpdater.webViewSession';
11
+ var sessionId=String(Date.now())+'-'+Math.random().toString(36).slice(2);
12
+ function s(value){
13
+ try{
14
+ if(value===undefined){return '';}
15
+ if(value===null){return 'null';}
16
+ if(typeof value==='string'){return value;}
17
+ if(value&&typeof value.message==='string'){return value.message;}
18
+ return String(value);
19
+ }catch(_){return '';}
20
+ }
21
+ function stack(value){
22
+ try{return value&&value.stack?String(value.stack):'';}catch(_){return '';}
23
+ }
24
+ function updater(){
25
+ var cap=window.Capacitor;
26
+ if(!cap||!cap.Plugins){return null;}
27
+ return cap.Plugins.CapacitorUpdater||null;
28
+ }
29
+ function flush(){
30
+ var plugin=updater();
31
+ if(!plugin||typeof plugin.reportWebViewError!=='function'){return false;}
32
+ while(queue.length){
33
+ var payload=queue.shift();
34
+ try{
35
+ var result=plugin.reportWebViewError(payload);
36
+ if(result&&typeof result.catch==='function'){result.catch(function(){});}
37
+ }catch(_){}
38
+ }
39
+ return true;
40
+ }
41
+ var retries=0;
42
+ function scheduleFlush(){
43
+ if(flush()){return;}
44
+ if(retries++<40){setTimeout(scheduleFlush,250);}
45
+ }
46
+ function send(payload){
47
+ try{
48
+ if(sentReports>=maxReports){return;}
49
+ payload.href=payload.href||location.href||'';
50
+ payload.user_agent=navigator.userAgent||'';
51
+ payload.session_id=sessionId;
52
+ var key=[payload.type,payload.message,payload.source,payload.line,payload.column,payload.tag_name].join('|');
53
+ if(seen[key]){return;}
54
+ seen[key]=true;
55
+ sentReports+=1;
56
+ queue.push(payload);
57
+ scheduleFlush();
58
+ }catch(_){}
59
+ }
60
+ function readSession(){
61
+ try{return JSON.parse(localStorage.getItem(sessionKey)||'null')||null;}catch(_){return null;}
62
+ }
63
+ function writeSession(active){
64
+ try{
65
+ localStorage.setItem(sessionKey,JSON.stringify({
66
+ id:sessionId,
67
+ active:active,
68
+ href:location.href||'',
69
+ started_at:window.__capgoWebViewSessionStartedAt,
70
+ updated_at:String(Date.now())
71
+ }));
72
+ }catch(_){}
73
+ }
74
+ window.__capgoWebViewSessionStartedAt=String(Date.now());
75
+ var previous=readSession();
76
+ if(previous&&previous.active){
77
+ send({
78
+ type:'webview_unclean_restart',
79
+ message:'WebView restarted without a clean page unload',
80
+ previous_session_id:s(previous.id),
81
+ previous_href:s(previous.href),
82
+ previous_started_at:s(previous.started_at),
83
+ previous_updated_at:s(previous.updated_at)
84
+ });
85
+ }
86
+ writeSession(true);
87
+ setInterval(function(){writeSession(true);},15000);
88
+ function pageDuration(){
89
+ var started=Number(window.__capgoWebViewSessionStartedAt||Date.now());
90
+ return String(Math.max(0,Date.now()-started));
91
+ }
92
+ function markClean(){writeSession(false);}
93
+ window.addEventListener('pagehide',markClean,true);
94
+ window.addEventListener('beforeunload',markClean,true);
95
+ window.addEventListener('error',function(event){
96
+ var target=event&&event.target;
97
+ if(target&&target!==window&&(target.src||target.href)){
98
+ send({
99
+ type:'resource_error',
100
+ message:'Resource failed to load',
101
+ source:s(target.src||target.href),
102
+ tag_name:s(target.tagName)
103
+ });
104
+ return;
105
+ }
106
+ send({
107
+ type:'javascript_error',
108
+ message:s((event&&event.message)||(event&&event.error)),
109
+ source:s(event&&event.filename),
110
+ line:s(event&&event.lineno),
111
+ column:s(event&&event.colno),
112
+ stack:stack(event&&event.error)
113
+ });
114
+ },true);
115
+ window.addEventListener('unhandledrejection',function(event){
116
+ var reason=event&&event.reason;
117
+ send({type:'unhandled_rejection',message:s(reason),stack:stack(reason)});
118
+ },true);
119
+ document.addEventListener('securitypolicyviolation',function(event){
120
+ send({
121
+ type:'security_policy_violation',
122
+ message:s(event&&event.violatedDirective),
123
+ source:s(event&&event.blockedURI)
124
+ });
125
+ },true);
126
+ document.addEventListener('DOMContentLoaded',function(){
127
+ send({
128
+ type:'webview_dom_content_loaded',
129
+ message:'WebView DOM content loaded',
130
+ duration_ms:pageDuration(),
131
+ page_started_at:String(window.__capgoWebViewSessionStartedAt)
132
+ });
133
+ },true);
134
+ window.addEventListener('load',function(){
135
+ send({
136
+ type:'webview_page_loaded',
137
+ message:'WebView page loaded',
138
+ duration_ms:pageDuration(),
139
+ page_started_at:String(window.__capgoWebViewSessionStartedAt)
140
+ });
141
+ },true);
142
+ document.addEventListener('deviceready',scheduleFlush,false);
143
+ setTimeout(scheduleFlush,0);
144
+ })();
145
+ """
146
+
147
+ private let implementation: CapgoUpdater
148
+ private var installed = false
149
+
150
+ init(implementation: CapgoUpdater) {
151
+ self.implementation = implementation
152
+ }
153
+
154
+ func install(on webView: WKWebView?) {
155
+ guard !installed else {
156
+ return
157
+ }
158
+ guard let webView else {
159
+ return
160
+ }
161
+
162
+ installed = true
163
+ let userScript = WKUserScript(source: Self.script, injectionTime: .atDocumentStart, forMainFrameOnly: true)
164
+ webView.configuration.userContentController.addUserScript(userScript)
165
+ webView.evaluateJavaScript(Self.script, completionHandler: nil)
166
+ }
167
+
168
+ func reportError(_ call: CAPPluginCall) {
169
+ let errorType = call.getString("type") ?? "javascript_error"
170
+ let current = implementation.getCurrentBundle()
171
+ implementation.sendStats(
172
+ action: Self.statsAction(for: errorType),
173
+ versionName: current.getVersionName(),
174
+ oldVersionName: "",
175
+ metadata: Self.buildMetadata([
176
+ "type": errorType,
177
+ "message": call.getString("message"),
178
+ "source": call.getString("source"),
179
+ "line": call.getString("line") ?? call.getString("lineno"),
180
+ "column": call.getString("column") ?? call.getString("colno"),
181
+ "stack": call.getString("stack"),
182
+ "tag_name": call.getString("tag_name"),
183
+ "href": call.getString("href"),
184
+ "user_agent": call.getString("user_agent"),
185
+ "session_id": call.getString("session_id"),
186
+ "duration_ms": call.getString("duration_ms"),
187
+ "page_started_at": call.getString("page_started_at"),
188
+ "previous_session_id": call.getString("previous_session_id"),
189
+ "previous_href": call.getString("previous_href"),
190
+ "previous_started_at": call.getString("previous_started_at"),
191
+ "previous_updated_at": call.getString("previous_updated_at")
192
+ ])
193
+ )
194
+ call.resolve()
195
+ }
196
+
197
+ static func statsAction(for type: String) -> String {
198
+ switch type {
199
+ case "unhandled_rejection":
200
+ return "webview_unhandled_rejection"
201
+ case "resource_error":
202
+ return "webview_resource_error"
203
+ case "security_policy_violation":
204
+ return "webview_security_policy_violation"
205
+ case "webview_unclean_restart":
206
+ return "webview_unclean_restart"
207
+ case "render_process_gone":
208
+ return "webview_render_process_gone"
209
+ case "web_content_process_terminated":
210
+ return "webview_content_process_terminated"
211
+ case "webview_dom_content_loaded":
212
+ return "webview_dom_content_loaded"
213
+ case "webview_page_loaded":
214
+ return "webview_page_loaded"
215
+ case "javascript_error":
216
+ return "webview_javascript_error"
217
+ default:
218
+ return "webview_javascript_error"
219
+ }
220
+ }
221
+
222
+ static func buildMetadata(_ values: [String: String?]) -> [String: String] {
223
+ var metadata: [String: String] = [:]
224
+ put(&metadata, key: "error_type", value: payloadValue(values, "type") ?? "javascript_error", maxLength: 64)
225
+ put(&metadata, key: "message", value: payloadValue(values, "message"), maxLength: 1_024)
226
+ put(&metadata, key: "source", value: sanitizeUrl(payloadValue(values, "source")), maxLength: 512)
227
+ put(&metadata, key: "line", value: payloadValue(values, "line"), maxLength: 32)
228
+ put(&metadata, key: "column", value: payloadValue(values, "column"), maxLength: 32)
229
+ put(&metadata, key: "stack", value: payloadValue(values, "stack"), maxLength: 2_048)
230
+ put(&metadata, key: "tag_name", value: payloadValue(values, "tag_name"), maxLength: 64)
231
+ put(&metadata, key: "href", value: sanitizeUrl(payloadValue(values, "href")), maxLength: 512)
232
+ put(&metadata, key: "user_agent", value: payloadValue(values, "user_agent"), maxLength: 256)
233
+ put(&metadata, key: "session_id", value: payloadValue(values, "session_id"), maxLength: 128)
234
+ put(&metadata, key: "duration_ms", value: payloadValue(values, "duration_ms"), maxLength: 32)
235
+ put(&metadata, key: "page_started_at", value: payloadValue(values, "page_started_at"), maxLength: 64)
236
+ put(&metadata, key: "previous_session_id", value: payloadValue(values, "previous_session_id"), maxLength: 128)
237
+ put(&metadata, key: "previous_href", value: sanitizeUrl(payloadValue(values, "previous_href")), maxLength: 512)
238
+ put(&metadata, key: "previous_started_at", value: payloadValue(values, "previous_started_at"), maxLength: 64)
239
+ put(&metadata, key: "previous_updated_at", value: payloadValue(values, "previous_updated_at"), maxLength: 64)
240
+ return metadata
241
+ }
242
+
243
+ private static func payloadValue(_ values: [String: String?], _ key: String) -> String? {
244
+ guard let value = values[key] else {
245
+ return nil
246
+ }
247
+ return value
248
+ }
249
+
250
+ static func sanitizeUrl(_ value: String?) -> String? {
251
+ guard let value = value, !value.isEmpty else {
252
+ return value
253
+ }
254
+
255
+ if var components = URLComponents(string: value), components.scheme != nil, components.host != nil {
256
+ components.user = nil
257
+ components.password = nil
258
+ components.query = nil
259
+ components.fragment = nil
260
+ components.path = sanitizeUrlPath(components.path)
261
+ return components.string ?? stripUrlQueryAndFragment(value)
262
+ }
263
+
264
+ return stripUrlQueryAndFragment(value)
265
+ }
266
+
267
+ private static func sanitizeUrlPath(_ path: String) -> String {
268
+ guard !path.isEmpty else {
269
+ return path
270
+ }
271
+
272
+ return path
273
+ .split(separator: "/", omittingEmptySubsequences: false)
274
+ .map { isSensitiveUrlPathSegment(String($0)) ? "redacted" : String($0) }
275
+ .joined(separator: "/")
276
+ }
277
+
278
+ private static func isSensitiveUrlPathSegment(_ segment: String) -> Bool {
279
+ segment.range(of: #"^[0-9]{6,}$"#, options: .regularExpression) != nil ||
280
+ segment.range(of: #"^[0-9a-fA-F]{16,}$"#, options: .regularExpression) != nil ||
281
+ segment.range(
282
+ of: #"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"#,
283
+ options: .regularExpression
284
+ ) != nil
285
+ }
286
+
287
+ private static func stripUrlQueryAndFragment(_ value: String) -> String {
288
+ let queryIndex = value.firstIndex(of: "?")
289
+ let fragmentIndex = value.firstIndex(of: "#")
290
+ let endIndexes = [queryIndex, fragmentIndex].compactMap { $0 }
291
+ guard let endIndex = endIndexes.min() else {
292
+ return value
293
+ }
294
+ return String(value[..<endIndex])
295
+ }
296
+
297
+ private static func put(_ metadata: inout [String: String], key: String, value: String?, maxLength: Int) {
298
+ guard let value = value, !value.isEmpty else {
299
+ return
300
+ }
301
+ metadata[key] = String(value.prefix(maxLength))
302
+ }
303
+ }