@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.
- package/LICENSE +373 -0
- package/README.md +82 -0
- package/dist/esm/definitions.d.ts +2684 -0
- package/dist/esm/definitions.js +109 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/exec.d.ts +4 -0
- package/dist/esm/exec.js +25 -0
- package/dist/esm/exec.js.map +1 -0
- package/dist/esm/history.d.ts +1 -0
- package/dist/esm/history.js +283 -0
- package/dist/esm/history.js.map +1 -0
- package/dist/esm/index.d.ts +57 -0
- package/dist/esm/index.js +68 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/plugin.d.ts +57 -0
- package/dist/esm/plugin.js +15 -0
- package/dist/esm/plugin.js.map +1 -0
- package/dist/plugin.cjs.js +217 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +222 -0
- package/dist/plugin.js.map +1 -0
- package/package.json +96 -0
- package/plugin.xml +207 -0
- package/src/android/CordovaUpdaterPlugin.java +5662 -0
- package/src/android/UpdaterPathHandler.java +99 -0
- package/src/android/app/capgo/cordova/updater/AndroidAppExitReporter.java +92 -0
- package/src/android/app/capgo/cordova/updater/AppLifecycleObserver.java +115 -0
- package/src/android/app/capgo/cordova/updater/BundleInfo.java +246 -0
- package/src/android/app/capgo/cordova/updater/BundleStatus.java +45 -0
- package/src/android/app/capgo/cordova/updater/Callback.java +13 -0
- package/src/android/app/capgo/cordova/updater/CapgoUpdater.java +3404 -0
- package/src/android/app/capgo/cordova/updater/CordovaUpdaterConfig.java +56 -0
- package/src/android/app/capgo/cordova/updater/CryptoCipher.java +462 -0
- package/src/android/app/capgo/cordova/updater/DataManager.java +44 -0
- package/src/android/app/capgo/cordova/updater/DelayCondition.java +56 -0
- package/src/android/app/capgo/cordova/updater/DelayUntilNext.java +14 -0
- package/src/android/app/capgo/cordova/updater/DelayUpdateUtils.java +307 -0
- package/src/android/app/capgo/cordova/updater/DeviceIdHelper.java +230 -0
- package/src/android/app/capgo/cordova/updater/DownloadService.java +1219 -0
- package/src/android/app/capgo/cordova/updater/DownloadWorkerManager.java +260 -0
- package/src/android/app/capgo/cordova/updater/InternalUtils.java +54 -0
- package/src/android/app/capgo/cordova/updater/Logger.java +345 -0
- package/src/android/app/capgo/cordova/updater/ShakeDetector.java +72 -0
- package/src/android/app/capgo/cordova/updater/ShakeMenu.java +39 -0
- package/src/android/app/capgo/cordova/updater/ThreeFingerPinchDetector.java +323 -0
- package/src/android/app/capgo/cordova/updater/compat/JSArray.java +9 -0
- package/src/android/app/capgo/cordova/updater/compat/JSObject.java +83 -0
- package/src/android/app/capgo/cordova/updater/compat/PluginCall.java +165 -0
- package/src/android/capgo-cordova-updater.gradle +19 -0
- package/src/android/capgo-updater.xml +3 -0
- package/src/android/test/app/capgo/cordova/updater/CapacitorUpdaterUnitTest.java.skip +3039 -0
- package/src/android/test/app/capgo/cordova/updater/DelayUpdateUtilsTest.java +177 -0
- package/src/android/test/app/capgo/cordova/updater/NativeContractTest.java +105 -0
- package/src/ios/AES.swift +216 -0
- package/src/ios/AppHealthTracker.swift +82 -0
- package/src/ios/BundleInfo.swift +185 -0
- package/src/ios/BundleStatus.swift +127 -0
- package/src/ios/CapgoRawRsa.swift +36 -0
- package/src/ios/CapgoUpdater.swift +3544 -0
- package/src/ios/CordovaCompat.swift +11 -0
- package/src/ios/CordovaPluginCall.swift +190 -0
- package/src/ios/CordovaUpdaterCommands.swift +270 -0
- package/src/ios/CordovaUpdaterPlugin.swift +4706 -0
- package/src/ios/CryptoCipher.swift +326 -0
- package/src/ios/DelayCondition.swift +74 -0
- package/src/ios/DelayUntilNext.swift +30 -0
- package/src/ios/DelayUpdateUtils.swift +257 -0
- package/src/ios/DeviceIdHelper.swift +120 -0
- package/src/ios/Info.plist +28 -0
- package/src/ios/InternalUtils.swift +471 -0
- package/src/ios/Logger.swift +283 -0
- package/src/ios/RSA.swift +96 -0
- package/src/ios/ShakeMenu.swift +52 -0
- package/src/ios/UpdaterSchemeHandler.swift +81 -0
- package/src/ios/UserDefaultsExtension.swift +46 -0
- 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
|
+
}
|