@capgo/capacitor-inappbrowser 8.6.32 → 8.6.34
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/CapgoCapacitorInappbrowser.podspec +1 -0
- package/Package.swift +2 -1
- package/android/src/main/java/ee/forgr/capacitor_inappbrowser/WebViewDialog.java +2 -0
- package/ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift +14 -2
- package/ios/Sources/InAppBrowserPlugin/ProxyBridge.swift +210 -0
- package/ios/Sources/InAppBrowserPlugin/ProxySchemeHandler.swift +84 -10
- package/ios/Sources/InAppBrowserPlugin/Resources/.gitkeep +0 -0
- package/ios/Sources/InAppBrowserPlugin/Resources/proxy-bridge.js +586 -0
- package/ios/Sources/InAppBrowserPlugin/WKWebViewController.swift +67 -2
- package/package.json +3 -3
|
@@ -11,6 +11,7 @@ Pod::Spec.new do |s|
|
|
|
11
11
|
s.author = package['author']
|
|
12
12
|
s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
|
|
13
13
|
s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}'
|
|
14
|
+
s.resources = ['ios/Sources/InAppBrowserPlugin/Resources/proxy-bridge.js']
|
|
14
15
|
s.ios.deployment_target = '15.0'
|
|
15
16
|
s.dependency 'Capacitor'
|
|
16
17
|
s.swift_version = '5.1'
|
package/Package.swift
CHANGED
|
@@ -19,7 +19,8 @@ let package = Package(
|
|
|
19
19
|
.product(name: "Capacitor", package: "capacitor-swift-pm"),
|
|
20
20
|
.product(name: "Cordova", package: "capacitor-swift-pm")
|
|
21
21
|
],
|
|
22
|
-
path: "ios/Sources/InAppBrowserPlugin"
|
|
22
|
+
path: "ios/Sources/InAppBrowserPlugin",
|
|
23
|
+
resources: [.process("Resources")]),
|
|
23
24
|
.testTarget(
|
|
24
25
|
name: "InappbrowserPluginTests",
|
|
25
26
|
dependencies: ["InappbrowserPlugin"],
|
|
@@ -6053,6 +6053,7 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
6053
6053
|
|
|
6054
6054
|
// If both width and height are specified, use custom dimensions
|
|
6055
6055
|
if (width != null && height != null) {
|
|
6056
|
+
params.gravity = Gravity.TOP | Gravity.LEFT;
|
|
6056
6057
|
params.width = (int) getPixels(width);
|
|
6057
6058
|
params.height = (int) getPixels(height);
|
|
6058
6059
|
params.x = (x != null) ? (int) getPixels(x) : 0;
|
|
@@ -6060,6 +6061,7 @@ public class WebViewDialog extends Dialog implements ProxyResponseRouting.ProxyR
|
|
|
6060
6061
|
params.gravity = Gravity.TOP | Gravity.START;
|
|
6061
6062
|
} else if (height != null && width == null) {
|
|
6062
6063
|
// If only height is specified, use custom height with fullscreen width
|
|
6064
|
+
params.gravity = Gravity.TOP | Gravity.LEFT;
|
|
6063
6065
|
params.width = WindowManager.LayoutParams.MATCH_PARENT;
|
|
6064
6066
|
params.height = (int) getPixels(height);
|
|
6065
6067
|
params.x = 0;
|
|
@@ -98,7 +98,7 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
98
98
|
case aware = "AWARE"
|
|
99
99
|
case fakeVisible = "FAKE_VISIBLE"
|
|
100
100
|
}
|
|
101
|
-
private let pluginVersion: String = "8.6.
|
|
101
|
+
private let pluginVersion: String = "8.6.34"
|
|
102
102
|
public let identifier = "CapgoInAppBrowserPlugin"
|
|
103
103
|
public let jsName = "CapgoInAppBrowser"
|
|
104
104
|
public let pluginMethods: [CAPPluginMethod] = [
|
|
@@ -135,6 +135,7 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
135
135
|
var webViewController: WKWebViewController?
|
|
136
136
|
private var webViewControllers: [String: WKWebViewController] = [:]
|
|
137
137
|
private var proxySchemeHandlers: [String: ProxySchemeHandler] = [:]
|
|
138
|
+
private var proxyBridges: [String: ProxyBridge] = [:]
|
|
138
139
|
private var webViewStack: [String] = []
|
|
139
140
|
private var activeWebViewId: String?
|
|
140
141
|
private weak var presentationContainerView: UIView?
|
|
@@ -186,6 +187,7 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
186
187
|
}
|
|
187
188
|
proxySchemeHandlers[id]?.cancelAllPendingTasks()
|
|
188
189
|
proxySchemeHandlers[id] = nil
|
|
190
|
+
proxyBridges[id] = nil
|
|
189
191
|
webViewControllers[id] = nil
|
|
190
192
|
navigationControllers[id] = nil
|
|
191
193
|
webViewStack.removeAll { $0 == id }
|
|
@@ -893,16 +895,23 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
893
895
|
}
|
|
894
896
|
|
|
895
897
|
var proxyHandler: ProxySchemeHandler?
|
|
898
|
+
var proxyBridge: ProxyBridge?
|
|
899
|
+
var proxyBridgeAccessToken: String?
|
|
896
900
|
if legacyProxyRequests.isEnabled || !outboundProxyRules.isEmpty || !inboundProxyRules.isEmpty {
|
|
901
|
+
let bridgeAccessToken = UUID().uuidString
|
|
902
|
+
proxyBridgeAccessToken = bridgeAccessToken
|
|
903
|
+
proxyBridge = ProxyBridge(accessToken: bridgeAccessToken)
|
|
897
904
|
proxyHandler = ProxySchemeHandler(
|
|
898
905
|
plugin: self,
|
|
899
906
|
webviewId: webViewId,
|
|
900
907
|
legacyProxyRequests: legacyProxyRequests.isEnabled,
|
|
901
908
|
legacyProxyRequestURLRegex: legacyProxyRequests.urlRegex,
|
|
902
909
|
outboundRules: outboundProxyRules,
|
|
903
|
-
inboundRules: inboundProxyRules
|
|
910
|
+
inboundRules: inboundProxyRules,
|
|
911
|
+
proxyBridge: proxyBridge
|
|
904
912
|
)
|
|
905
913
|
self.proxySchemeHandlers[webViewId] = proxyHandler
|
|
914
|
+
self.proxyBridges[webViewId] = proxyBridge
|
|
906
915
|
}
|
|
907
916
|
|
|
908
917
|
self.webViewController = WKWebViewController.init(
|
|
@@ -921,6 +930,9 @@ public class CapgoInAppBrowserPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
921
930
|
captureConsoleLogs: captureConsoleLogs,
|
|
922
931
|
proxyRequests: legacyProxyRequests.isEnabled,
|
|
923
932
|
proxySchemeHandler: proxyHandler,
|
|
933
|
+
proxyBridge: proxyBridge,
|
|
934
|
+
proxyBridgeAccessToken: proxyBridgeAccessToken,
|
|
935
|
+
legacyProxyRequestURLRegexPattern: legacyProxyRequests.urlRegex?.pattern,
|
|
924
936
|
documentStartUserScripts: self.documentStartUserScripts(
|
|
925
937
|
authorizedAppLinks: authorizedAppLinks,
|
|
926
938
|
openBlankTargetInWebView: openBlankTargetInWebView
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
struct ProxyBridgeStoredRequest {
|
|
4
|
+
let method: String
|
|
5
|
+
let headersJson: String
|
|
6
|
+
let base64Body: String
|
|
7
|
+
let credentialsMode: String
|
|
8
|
+
let storedAt: Date
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
public final class ProxyBridge {
|
|
12
|
+
static let storedRequestTTL: TimeInterval = 120
|
|
13
|
+
|
|
14
|
+
private let accessToken: String
|
|
15
|
+
private var storedRequests: [String: ProxyBridgeStoredRequest] = [:]
|
|
16
|
+
private var storedRequestOrder: [String] = []
|
|
17
|
+
private let lock = NSLock()
|
|
18
|
+
private let clock: () -> Date
|
|
19
|
+
|
|
20
|
+
init(accessToken: String, clock: @escaping () -> Date = Date.init) {
|
|
21
|
+
self.accessToken = accessToken
|
|
22
|
+
self.clock = clock
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
func storeRequest(
|
|
26
|
+
token: String,
|
|
27
|
+
requestId: String,
|
|
28
|
+
method: String,
|
|
29
|
+
headersJson: String,
|
|
30
|
+
base64Body: String,
|
|
31
|
+
credentialsMode: String
|
|
32
|
+
) {
|
|
33
|
+
guard token == accessToken, !requestId.isEmpty else {
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let now = clock()
|
|
38
|
+
lock.lock()
|
|
39
|
+
cleanupExpiredRequests(now: now)
|
|
40
|
+
storedRequests[requestId] = ProxyBridgeStoredRequest(
|
|
41
|
+
method: method,
|
|
42
|
+
headersJson: headersJson,
|
|
43
|
+
base64Body: base64Body,
|
|
44
|
+
credentialsMode: credentialsMode,
|
|
45
|
+
storedAt: now
|
|
46
|
+
)
|
|
47
|
+
storedRequestOrder.append(requestId)
|
|
48
|
+
lock.unlock()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
func getAndRemove(requestId: String) -> ProxyBridgeStoredRequest? {
|
|
52
|
+
lock.lock()
|
|
53
|
+
defer { lock.unlock() }
|
|
54
|
+
guard let storedRequest = storedRequests.removeValue(forKey: requestId) else {
|
|
55
|
+
return nil
|
|
56
|
+
}
|
|
57
|
+
storedRequestOrder.removeAll { $0 == requestId }
|
|
58
|
+
return storedRequest
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private func cleanupExpiredRequests(now: Date) {
|
|
62
|
+
while let oldestRequestId = storedRequestOrder.first {
|
|
63
|
+
guard let oldestRequest = storedRequests[oldestRequestId] else {
|
|
64
|
+
storedRequestOrder.removeFirst()
|
|
65
|
+
continue
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if now.timeIntervalSince(oldestRequest.storedAt) < Self.storedRequestTTL {
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
storedRequests.removeValue(forKey: oldestRequestId)
|
|
73
|
+
storedRequestOrder.removeFirst()
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
enum ProxyBridgeSupport {
|
|
79
|
+
struct BridgeMarkerRequest {
|
|
80
|
+
let originalURL: String
|
|
81
|
+
let requestId: String
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
static func isBridgeMarkerRequestURL(_ requestURL: String) -> Bool {
|
|
85
|
+
guard let components = URLComponents(string: requestURL),
|
|
86
|
+
components.path == "/_capgo_proxy_",
|
|
87
|
+
let query = components.query,
|
|
88
|
+
!query.isEmpty else {
|
|
89
|
+
return false
|
|
90
|
+
}
|
|
91
|
+
return true
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
static func parseBridgeMarkerRequest(_ requestURL: String) -> BridgeMarkerRequest? {
|
|
95
|
+
guard isBridgeMarkerRequestURL(requestURL),
|
|
96
|
+
let components = URLComponents(string: requestURL) else {
|
|
97
|
+
return nil
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
let queryItems = components.queryItems ?? []
|
|
101
|
+
guard let originalURL = queryItems.first(where: { $0.name == "u" })?.value,
|
|
102
|
+
let requestId = queryItems.first(where: { $0.name == "rid" })?.value,
|
|
103
|
+
!originalURL.isEmpty,
|
|
104
|
+
!requestId.isEmpty else {
|
|
105
|
+
return nil
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return BridgeMarkerRequest(originalURL: originalURL, requestId: requestId)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
static func decodeStoredHeaders(_ headersJson: String) -> [String: String] {
|
|
112
|
+
guard let data = headersJson.data(using: .utf8),
|
|
113
|
+
let headers = try? JSONSerialization.jsonObject(with: data) as? [String: String] else {
|
|
114
|
+
return [:]
|
|
115
|
+
}
|
|
116
|
+
return headers
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
static func shouldInjectBridge(hasProxySchemeHandler: Bool) -> Bool {
|
|
120
|
+
hasProxySchemeHandler
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
static func usesLegacyJsProxyMode(
|
|
124
|
+
legacyProxyRequests: Bool,
|
|
125
|
+
legacyProxyRequestURLRegex: NSRegularExpression?,
|
|
126
|
+
hasOutboundRules: Bool,
|
|
127
|
+
hasInboundRules: Bool
|
|
128
|
+
) -> Bool {
|
|
129
|
+
(legacyProxyRequests || legacyProxyRequestURLRegex != nil) &&
|
|
130
|
+
hasOutboundRules == false &&
|
|
131
|
+
hasInboundRules == false
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
static func shouldDelegateLegacyJsProxyRequest(
|
|
135
|
+
legacyProxyRequests: Bool,
|
|
136
|
+
legacyProxyRequestURLRegex: NSRegularExpression?,
|
|
137
|
+
hasOutboundRules: Bool,
|
|
138
|
+
hasInboundRules: Bool,
|
|
139
|
+
requestURL: String
|
|
140
|
+
) -> Bool {
|
|
141
|
+
guard usesLegacyJsProxyMode(
|
|
142
|
+
legacyProxyRequests: legacyProxyRequests,
|
|
143
|
+
legacyProxyRequestURLRegex: legacyProxyRequestURLRegex,
|
|
144
|
+
hasOutboundRules: hasOutboundRules,
|
|
145
|
+
hasInboundRules: hasInboundRules
|
|
146
|
+
) else {
|
|
147
|
+
return false
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
guard let legacyProxyRequestURLRegex else {
|
|
151
|
+
return legacyProxyRequests
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
let range = NSRange(location: 0, length: requestURL.utf16.count)
|
|
155
|
+
return legacyProxyRequestURLRegex.firstMatch(in: requestURL, options: [], range: range) != nil
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
static func escapeJavaScriptLiteral(_ value: String) -> String {
|
|
159
|
+
value
|
|
160
|
+
.replacingOccurrences(of: "\\", with: "\\\\")
|
|
161
|
+
.replacingOccurrences(of: "'", with: "\\'")
|
|
162
|
+
.replacingOccurrences(of: "\r", with: "\\r")
|
|
163
|
+
.replacingOccurrences(of: "\n", with: "\\n")
|
|
164
|
+
.replacingOccurrences(of: "\u{2028}", with: "\\u2028")
|
|
165
|
+
.replacingOccurrences(of: "\u{2029}", with: "\\u2029")
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
static func bootstrapScriptSource() -> String {
|
|
169
|
+
"""
|
|
170
|
+
(function() {
|
|
171
|
+
if (window.__capgoProxy && window.__capgoProxy.__capgoNativeBridgeInstalled) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
window.__capgoProxy = {
|
|
175
|
+
__capgoNativeBridgeInstalled: true,
|
|
176
|
+
storeRequest: function(token, requestId, method, headersJson, base64Body, credentialsMode) {
|
|
177
|
+
if (!window.webkit || !window.webkit.messageHandlers || !window.webkit.messageHandlers.capgoProxyBridge) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
window.webkit.messageHandlers.capgoProxyBridge.postMessage({
|
|
181
|
+
token: token,
|
|
182
|
+
requestId: requestId,
|
|
183
|
+
method: method,
|
|
184
|
+
headersJson: headersJson,
|
|
185
|
+
base64Body: base64Body,
|
|
186
|
+
credentialsMode: credentialsMode
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
})();
|
|
191
|
+
"""
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
static func loadBundledBridgeScript(accessToken: String, proxyRegexSource: String) -> String? {
|
|
195
|
+
#if SWIFT_PACKAGE
|
|
196
|
+
let bundle = Bundle.module
|
|
197
|
+
#else
|
|
198
|
+
let bundle = Bundle(for: ProxyBridge.self)
|
|
199
|
+
#endif
|
|
200
|
+
|
|
201
|
+
guard let scriptURL = bundle.url(forResource: "proxy-bridge", withExtension: "js"),
|
|
202
|
+
let rawScript = try? String(contentsOf: scriptURL) else {
|
|
203
|
+
return nil
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return rawScript
|
|
207
|
+
.replacingOccurrences(of: "___CAPGO_PROXY_TOKEN___", with: escapeJavaScriptLiteral(accessToken))
|
|
208
|
+
.replacingOccurrences(of: "___CAPGO_PROXY_REGEX___", with: escapeJavaScriptLiteral(proxyRegexSource))
|
|
209
|
+
}
|
|
210
|
+
}
|
|
@@ -460,16 +460,17 @@ public class ProxySchemeHandler: NSObject, WKURLSchemeHandler, URLSessionTaskDel
|
|
|
460
460
|
private let legacyProxyRequestURLRegex: NSRegularExpression?
|
|
461
461
|
private let outboundRules: [NativeProxyRule]
|
|
462
462
|
private let inboundRules: [NativeProxyRule]
|
|
463
|
+
private weak var proxyBridge: ProxyBridge?
|
|
463
464
|
|
|
464
465
|
private lazy var session = URLSession(configuration: .default, delegate: self, delegateQueue: nil)
|
|
465
|
-
|
|
466
466
|
init(
|
|
467
467
|
plugin: CapgoInAppBrowserPlugin,
|
|
468
468
|
webviewId: String,
|
|
469
469
|
legacyProxyRequests: Bool,
|
|
470
470
|
legacyProxyRequestURLRegex: NSRegularExpression?,
|
|
471
471
|
outboundRules: [NativeProxyRule],
|
|
472
|
-
inboundRules: [NativeProxyRule]
|
|
472
|
+
inboundRules: [NativeProxyRule],
|
|
473
|
+
proxyBridge: ProxyBridge? = nil
|
|
473
474
|
) {
|
|
474
475
|
self.plugin = plugin
|
|
475
476
|
self.webviewId = webviewId
|
|
@@ -477,6 +478,7 @@ public class ProxySchemeHandler: NSObject, WKURLSchemeHandler, URLSessionTaskDel
|
|
|
477
478
|
self.legacyProxyRequestURLRegex = legacyProxyRequestURLRegex
|
|
478
479
|
self.outboundRules = outboundRules
|
|
479
480
|
self.inboundRules = inboundRules
|
|
481
|
+
self.proxyBridge = proxyBridge
|
|
480
482
|
super.init()
|
|
481
483
|
}
|
|
482
484
|
|
|
@@ -488,7 +490,8 @@ public class ProxySchemeHandler: NSObject, WKURLSchemeHandler, URLSessionTaskDel
|
|
|
488
490
|
legacyProxyRequests: legacyProxyRequests,
|
|
489
491
|
legacyProxyRequestURLRegex: legacyProxyRequestURLRegex,
|
|
490
492
|
outboundRules: outboundRules,
|
|
491
|
-
inboundRules: inboundRules
|
|
493
|
+
inboundRules: inboundRules,
|
|
494
|
+
proxyBridge: proxyBridge
|
|
492
495
|
)
|
|
493
496
|
}
|
|
494
497
|
|
|
@@ -505,13 +508,10 @@ public class ProxySchemeHandler: NSObject, WKURLSchemeHandler, URLSessionTaskDel
|
|
|
505
508
|
}
|
|
506
509
|
|
|
507
510
|
let requestId = UUID().uuidString
|
|
508
|
-
let requestContext =
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
base64Body: extractBody(from: urlSchemeTask.request),
|
|
513
|
-
isMainFrame: ProxySchemeRequestSupport.isMainFrameRequest(urlSchemeTask.request)
|
|
514
|
-
)
|
|
511
|
+
guard let requestContext = makeInitialRequestContext(from: urlSchemeTask, requestURL: url) else {
|
|
512
|
+
finishCanceledSchemeTask(urlSchemeTask)
|
|
513
|
+
return
|
|
514
|
+
}
|
|
515
515
|
let pendingTask = PendingProxyTask(requestId: requestId, schemeTask: urlSchemeTask, requestContext: requestContext, phase: "outbound")
|
|
516
516
|
|
|
517
517
|
taskLock.lock()
|
|
@@ -1169,6 +1169,80 @@ public class ProxySchemeHandler: NSObject, WKURLSchemeHandler, URLSessionTaskDel
|
|
|
1169
1169
|
}
|
|
1170
1170
|
}
|
|
1171
1171
|
|
|
1172
|
+
|
|
1173
|
+
private func makeInitialRequestContext(from urlSchemeTask: WKURLSchemeTask, requestURL: URL) -> NativeRequestContext? {
|
|
1174
|
+
let requestURLString = requestURL.absoluteString
|
|
1175
|
+
|
|
1176
|
+
if let bridgeRequest = ProxyBridgeSupport.parseBridgeMarkerRequest(requestURLString) {
|
|
1177
|
+
if ProxyBridgeSupport.usesLegacyJsProxyMode(
|
|
1178
|
+
legacyProxyRequests: legacyProxyRequests,
|
|
1179
|
+
legacyProxyRequestURLRegex: legacyProxyRequestURLRegex,
|
|
1180
|
+
hasOutboundRules: !outboundRules.isEmpty,
|
|
1181
|
+
hasInboundRules: !inboundRules.isEmpty
|
|
1182
|
+
),
|
|
1183
|
+
!ProxyBridgeSupport.shouldDelegateLegacyJsProxyRequest(
|
|
1184
|
+
legacyProxyRequests: legacyProxyRequests,
|
|
1185
|
+
legacyProxyRequestURLRegex: legacyProxyRequestURLRegex,
|
|
1186
|
+
hasOutboundRules: !outboundRules.isEmpty,
|
|
1187
|
+
hasInboundRules: !inboundRules.isEmpty,
|
|
1188
|
+
requestURL: bridgeRequest.originalURL
|
|
1189
|
+
) {
|
|
1190
|
+
_ = proxyBridge?.getAndRemove(requestId: bridgeRequest.requestId)
|
|
1191
|
+
return nil
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
guard let stored = proxyBridge?.getAndRemove(requestId: bridgeRequest.requestId) else {
|
|
1195
|
+
return nil
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
var headers = ProxyBridgeSupport.decodeStoredHeaders(stored.headersJson)
|
|
1199
|
+
let markerHeaders = urlSchemeTask.request.allHTTPHeaderFields ?? [:]
|
|
1200
|
+
for (key, value) in markerHeaders where headers[key] == nil {
|
|
1201
|
+
headers[key] = value
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
let base64Body = stored.base64Body.isEmpty ? nil : stored.base64Body
|
|
1205
|
+
return NativeRequestContext(
|
|
1206
|
+
url: bridgeRequest.originalURL,
|
|
1207
|
+
method: ProxySchemeRequestSupport.normalizedRequestMethod(stored.method),
|
|
1208
|
+
headers: headers,
|
|
1209
|
+
base64Body: base64Body,
|
|
1210
|
+
isMainFrame: ProxySchemeRequestSupport.isMainFrameRequest(urlSchemeTask.request)
|
|
1211
|
+
)
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
return NativeRequestContext(
|
|
1215
|
+
url: requestURLString,
|
|
1216
|
+
method: ProxySchemeRequestSupport.normalizedRequestMethod(urlSchemeTask.request.httpMethod),
|
|
1217
|
+
headers: urlSchemeTask.request.allHTTPHeaderFields ?? [:],
|
|
1218
|
+
base64Body: extractBody(from: urlSchemeTask.request),
|
|
1219
|
+
isMainFrame: ProxySchemeRequestSupport.isMainFrameRequest(urlSchemeTask.request)
|
|
1220
|
+
)
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
private func finishCanceledSchemeTask(_ schemeTask: WKURLSchemeTask) {
|
|
1224
|
+
guard let url = schemeTask.request.url,
|
|
1225
|
+
let httpResponse = HTTPURLResponse(
|
|
1226
|
+
url: url,
|
|
1227
|
+
statusCode: 204,
|
|
1228
|
+
httpVersion: "HTTP/1.1",
|
|
1229
|
+
headerFields: [:]
|
|
1230
|
+
)
|
|
1231
|
+
else {
|
|
1232
|
+
schemeTask.didFailWithError(
|
|
1233
|
+
NSError(
|
|
1234
|
+
domain: "ProxySchemeHandler",
|
|
1235
|
+
code: -4,
|
|
1236
|
+
userInfo: [NSLocalizedDescriptionKey: "Failed to create canceled response"]
|
|
1237
|
+
)
|
|
1238
|
+
)
|
|
1239
|
+
return
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
schemeTask.didReceive(httpResponse)
|
|
1243
|
+
schemeTask.didReceive(Data())
|
|
1244
|
+
schemeTask.didFinish()
|
|
1245
|
+
}
|
|
1172
1246
|
private func extractBody(from request: URLRequest) -> String? {
|
|
1173
1247
|
if let body = request.httpBody {
|
|
1174
1248
|
return body.base64EncodedString()
|
|
File without changes
|
|
@@ -0,0 +1,586 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
(() => {
|
|
3
|
+
var __async = (__this, __arguments, generator) => {
|
|
4
|
+
return new Promise((resolve, reject) => {
|
|
5
|
+
var fulfilled = (value) => {
|
|
6
|
+
try {
|
|
7
|
+
step(generator.next(value));
|
|
8
|
+
} catch (e) {
|
|
9
|
+
reject(e);
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
var rejected = (value) => {
|
|
13
|
+
try {
|
|
14
|
+
step(generator.throw(value));
|
|
15
|
+
} catch (e) {
|
|
16
|
+
reject(e);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
20
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// src/proxy-bridge-support.ts
|
|
25
|
+
function findCapturedHeaderKey(headers, headerName) {
|
|
26
|
+
const normalizedHeaderName = headerName.toLowerCase();
|
|
27
|
+
for (const key of Object.keys(headers)) {
|
|
28
|
+
if (key.toLowerCase() === normalizedHeaderName) {
|
|
29
|
+
return key;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
function isNativeProxyErrorResponse(response) {
|
|
35
|
+
return response.status === 599 && response.headers.get("x-capgo-proxy-error") !== null;
|
|
36
|
+
}
|
|
37
|
+
function nativeProxyErrorMessage(response) {
|
|
38
|
+
const nativeErrorHeader = response.headers.get("x-capgo-proxy-error");
|
|
39
|
+
if (!nativeErrorHeader) {
|
|
40
|
+
return "Network request failed";
|
|
41
|
+
}
|
|
42
|
+
const nativeMessage = nativeErrorHeader.trim();
|
|
43
|
+
return nativeMessage || "Network request failed";
|
|
44
|
+
}
|
|
45
|
+
function replaceCapturedHeader(headers, name, value) {
|
|
46
|
+
const existingKey = findCapturedHeaderKey(headers, name);
|
|
47
|
+
if (existingKey && existingKey !== name) {
|
|
48
|
+
delete headers[existingKey];
|
|
49
|
+
}
|
|
50
|
+
headers[name] = value;
|
|
51
|
+
}
|
|
52
|
+
function appendCapturedHeader(headers, name, value) {
|
|
53
|
+
const existingKey = findCapturedHeaderKey(headers, name);
|
|
54
|
+
if (!existingKey) {
|
|
55
|
+
headers[name] = value;
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
headers[existingKey] = headers[existingKey] ? `${headers[existingKey]}, ${value}` : value;
|
|
59
|
+
}
|
|
60
|
+
function inferContentTypeFromBody(body) {
|
|
61
|
+
if (typeof body === "string") {
|
|
62
|
+
return "text/plain;charset=UTF-8";
|
|
63
|
+
}
|
|
64
|
+
if (body instanceof URLSearchParams) {
|
|
65
|
+
return "application/x-www-form-urlencoded;charset=UTF-8";
|
|
66
|
+
}
|
|
67
|
+
if (typeof Blob !== "undefined" && body instanceof Blob) {
|
|
68
|
+
return body.type || null;
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
function ensureInferredContentType(headers, body) {
|
|
73
|
+
if (findCapturedHeaderKey(headers, "content-type")) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const inferredContentType = inferContentTypeFromBody(body);
|
|
77
|
+
if (inferredContentType) {
|
|
78
|
+
headers["content-type"] = inferredContentType;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function resolveProxyBridgeUrl(rawUrl, baseUrl) {
|
|
82
|
+
try {
|
|
83
|
+
return new URL(rawUrl, baseUrl).href;
|
|
84
|
+
} catch (_error) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function shouldProxyBridgeUrl(rawUrl, baseUrl, urlRegex) {
|
|
89
|
+
const resolvedUrl = resolveProxyBridgeUrl(rawUrl, baseUrl);
|
|
90
|
+
if (!resolvedUrl) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
const protocol = new URL(resolvedUrl).protocol.toLowerCase();
|
|
94
|
+
if (protocol !== "http:" && protocol !== "https:") {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
return !urlRegex || urlRegex.test(resolvedUrl);
|
|
98
|
+
}
|
|
99
|
+
function getSubmitEventSubmitter(event, submitEventCtor) {
|
|
100
|
+
var _a, _b;
|
|
101
|
+
const resolvedSubmitEventCtor = submitEventCtor != null ? submitEventCtor : typeof SubmitEvent !== "undefined" ? SubmitEvent : void 0;
|
|
102
|
+
if (resolvedSubmitEventCtor && event instanceof resolvedSubmitEventCtor) {
|
|
103
|
+
return (_a = event.submitter) != null ? _a : null;
|
|
104
|
+
}
|
|
105
|
+
if ("submitter" in event) {
|
|
106
|
+
return (_b = event.submitter) != null ? _b : null;
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
function shouldProxySubmitEvent(defaultPrevented, canProxyTarget) {
|
|
111
|
+
return !defaultPrevented && canProxyTarget;
|
|
112
|
+
}
|
|
113
|
+
function shouldProxySubmitRequest(defaultPrevented, canProxyTarget, rawUrl, baseUrl, urlRegex) {
|
|
114
|
+
return shouldProxySubmitEvent(defaultPrevented, canProxyTarget) && shouldProxyBridgeUrl(rawUrl, baseUrl, urlRegex);
|
|
115
|
+
}
|
|
116
|
+
function consumeProxySubmitReplayBypass(form) {
|
|
117
|
+
if (!form.__capgoSkipNextProxySubmit) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
delete form.__capgoSkipNextProxySubmit;
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
function replaySubmitAfterProxyFailure(form, originalSubmit, submitter) {
|
|
124
|
+
if (typeof form.requestSubmit === "function") {
|
|
125
|
+
form.__capgoSkipNextProxySubmit = true;
|
|
126
|
+
try {
|
|
127
|
+
if (submitter !== null && submitter !== void 0) {
|
|
128
|
+
form.requestSubmit(submitter);
|
|
129
|
+
} else {
|
|
130
|
+
form.requestSubmit();
|
|
131
|
+
}
|
|
132
|
+
return;
|
|
133
|
+
} catch (_error) {
|
|
134
|
+
delete form.__capgoSkipNextProxySubmit;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
originalSubmit.call(form);
|
|
138
|
+
}
|
|
139
|
+
function captureXhrReplayState(xhr) {
|
|
140
|
+
var _a, _b, _c, _d;
|
|
141
|
+
return {
|
|
142
|
+
responseType: (_a = xhr.responseType) != null ? _a : "",
|
|
143
|
+
timeout: (_b = xhr.timeout) != null ? _b : 0,
|
|
144
|
+
withCredentials: (_c = xhr.withCredentials) != null ? _c : false,
|
|
145
|
+
overrideMimeType: (_d = xhr.__proxyOverrideMimeType) != null ? _d : null
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function restoreXhrReplayState(xhr, state) {
|
|
149
|
+
xhr.responseType = state.responseType;
|
|
150
|
+
xhr.timeout = state.timeout;
|
|
151
|
+
xhr.withCredentials = state.withCredentials;
|
|
152
|
+
xhr.__proxyOverrideMimeType = state.overrideMimeType;
|
|
153
|
+
if (state.overrideMimeType && typeof xhr.overrideMimeType === "function") {
|
|
154
|
+
xhr.overrideMimeType(state.overrideMimeType);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// src/proxy-bridge.ts
|
|
159
|
+
(function() {
|
|
160
|
+
const proxyBridge = window.__capgoProxy;
|
|
161
|
+
if (!proxyBridge) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const accessToken = "___CAPGO_PROXY_TOKEN___";
|
|
165
|
+
const proxyRegexSource = "___CAPGO_PROXY_REGEX___";
|
|
166
|
+
let requestCounter = 0;
|
|
167
|
+
let proxyRequestPattern = null;
|
|
168
|
+
if (proxyRegexSource) {
|
|
169
|
+
try {
|
|
170
|
+
proxyRequestPattern = new RegExp(proxyRegexSource);
|
|
171
|
+
} catch (_error) {
|
|
172
|
+
proxyRequestPattern = null;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function generateRequestId() {
|
|
176
|
+
return "pr_" + Date.now() + "_" + requestCounter++;
|
|
177
|
+
}
|
|
178
|
+
function arrayBufferToBase64(buffer) {
|
|
179
|
+
const bytes = new Uint8Array(buffer);
|
|
180
|
+
let binary = "";
|
|
181
|
+
for (let i = 0; i < bytes.byteLength; i++) {
|
|
182
|
+
binary += String.fromCharCode(bytes[i]);
|
|
183
|
+
}
|
|
184
|
+
return btoa(binary);
|
|
185
|
+
}
|
|
186
|
+
function stringToBase64(value) {
|
|
187
|
+
return btoa(unescape(encodeURIComponent(value)));
|
|
188
|
+
}
|
|
189
|
+
function hasHeader(headers, headerName) {
|
|
190
|
+
const normalizedHeaderName = headerName.toLowerCase();
|
|
191
|
+
return Object.keys(headers).some((key) => key.toLowerCase() === normalizedHeaderName);
|
|
192
|
+
}
|
|
193
|
+
function normalizeMethod(method) {
|
|
194
|
+
return (method || "GET").toUpperCase();
|
|
195
|
+
}
|
|
196
|
+
function normalizeCredentialsMode(mode) {
|
|
197
|
+
if (mode === "omit" || mode === "include") {
|
|
198
|
+
return mode;
|
|
199
|
+
}
|
|
200
|
+
return "same-origin";
|
|
201
|
+
}
|
|
202
|
+
function getDocumentBaseUrl() {
|
|
203
|
+
if (typeof document !== "undefined" && typeof document.baseURI === "string" && document.baseURI) {
|
|
204
|
+
return document.baseURI;
|
|
205
|
+
}
|
|
206
|
+
return window.location.href;
|
|
207
|
+
}
|
|
208
|
+
function resolveUrl(url) {
|
|
209
|
+
if (url && !url.match(/^[a-zA-Z][a-zA-Z0-9+\-.]*:\/\//)) {
|
|
210
|
+
try {
|
|
211
|
+
return new URL(url, getDocumentBaseUrl()).href;
|
|
212
|
+
} catch (_error) {
|
|
213
|
+
return url;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return url;
|
|
217
|
+
}
|
|
218
|
+
function methodSupportsRequestBody(method) {
|
|
219
|
+
const normalizedMethod = normalizeMethod(method);
|
|
220
|
+
return normalizedMethod !== "GET" && normalizedMethod !== "HEAD";
|
|
221
|
+
}
|
|
222
|
+
function bodyToBase64(body) {
|
|
223
|
+
return __async(this, null, function* () {
|
|
224
|
+
if (body === null || body === void 0) {
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
if (typeof body === "string") {
|
|
228
|
+
return stringToBase64(body);
|
|
229
|
+
}
|
|
230
|
+
if (body instanceof ArrayBuffer) {
|
|
231
|
+
return arrayBufferToBase64(body);
|
|
232
|
+
}
|
|
233
|
+
if (ArrayBuffer.isView(body)) {
|
|
234
|
+
return arrayBufferToBase64(body.buffer.slice(body.byteOffset, body.byteOffset + body.byteLength));
|
|
235
|
+
}
|
|
236
|
+
if (body instanceof Blob) {
|
|
237
|
+
const buffer = yield body.arrayBuffer();
|
|
238
|
+
return arrayBufferToBase64(buffer);
|
|
239
|
+
}
|
|
240
|
+
if (body instanceof FormData) {
|
|
241
|
+
const buffer = yield new Response(body).arrayBuffer();
|
|
242
|
+
return arrayBufferToBase64(buffer);
|
|
243
|
+
}
|
|
244
|
+
if (body instanceof URLSearchParams) {
|
|
245
|
+
return stringToBase64(body.toString());
|
|
246
|
+
}
|
|
247
|
+
return null;
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
function storeInterceptedRequest(url, method, headers, body, credentialsMode) {
|
|
251
|
+
return __async(this, null, function* () {
|
|
252
|
+
const requestId = generateRequestId();
|
|
253
|
+
const normalizedMethod = normalizeMethod(method);
|
|
254
|
+
let normalizedBody = body;
|
|
255
|
+
if (normalizedBody instanceof FormData) {
|
|
256
|
+
const encoded = new Response(normalizedBody);
|
|
257
|
+
const contentType = encoded.headers.get("content-type");
|
|
258
|
+
if (contentType) {
|
|
259
|
+
replaceCapturedHeader(headers, "content-type", contentType);
|
|
260
|
+
}
|
|
261
|
+
normalizedBody = yield encoded.arrayBuffer();
|
|
262
|
+
}
|
|
263
|
+
if (!methodSupportsRequestBody(normalizedMethod)) {
|
|
264
|
+
normalizedBody = null;
|
|
265
|
+
}
|
|
266
|
+
ensureInferredContentType(headers, normalizedBody);
|
|
267
|
+
const base64Body = yield bodyToBase64(normalizedBody);
|
|
268
|
+
if (normalizedBody !== null && normalizedBody !== void 0 && base64Body === null && methodSupportsRequestBody(normalizedMethod)) {
|
|
269
|
+
throw new Error(`[proxy-bridge] Unsupported request body for ${normalizedMethod} proxy replay`);
|
|
270
|
+
}
|
|
271
|
+
proxyBridge.storeRequest(
|
|
272
|
+
accessToken,
|
|
273
|
+
requestId,
|
|
274
|
+
normalizedMethod,
|
|
275
|
+
JSON.stringify(headers),
|
|
276
|
+
base64Body || "",
|
|
277
|
+
normalizeCredentialsMode(credentialsMode)
|
|
278
|
+
);
|
|
279
|
+
return "/_capgo_proxy_?u=" + encodeURIComponent(url) + "&rid=" + requestId;
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
function getSubmitterAttribute(submitter, attributeName) {
|
|
283
|
+
if (!(submitter instanceof HTMLElement)) {
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
return submitter.getAttribute(attributeName);
|
|
287
|
+
}
|
|
288
|
+
function createFormData(form, submitter) {
|
|
289
|
+
if (submitter instanceof HTMLElement) {
|
|
290
|
+
try {
|
|
291
|
+
return new FormData(form, submitter);
|
|
292
|
+
} catch (_error) {
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return new FormData(form);
|
|
296
|
+
}
|
|
297
|
+
function appendFormDataToUrl(url, formData) {
|
|
298
|
+
const resolvedUrl = new URL(url, getDocumentBaseUrl());
|
|
299
|
+
const searchParams = new URLSearchParams(resolvedUrl.search);
|
|
300
|
+
formData.forEach((value, key) => {
|
|
301
|
+
searchParams.append(key, typeof value === "string" ? value : value.name);
|
|
302
|
+
});
|
|
303
|
+
resolvedUrl.search = searchParams.toString();
|
|
304
|
+
return resolvedUrl.toString();
|
|
305
|
+
}
|
|
306
|
+
function formDataToUrlSearchParams(formData) {
|
|
307
|
+
const searchParams = new URLSearchParams();
|
|
308
|
+
formData.forEach((value, key) => {
|
|
309
|
+
searchParams.append(key, typeof value === "string" ? value : value.name);
|
|
310
|
+
});
|
|
311
|
+
return searchParams;
|
|
312
|
+
}
|
|
313
|
+
function formDataToPlainText(formData) {
|
|
314
|
+
const lines = [];
|
|
315
|
+
formData.forEach((value, key) => {
|
|
316
|
+
lines.push(key + "=" + (typeof value === "string" ? value : value.name));
|
|
317
|
+
});
|
|
318
|
+
return lines.join("\r\n");
|
|
319
|
+
}
|
|
320
|
+
function resolveFormMethod(form, submitter) {
|
|
321
|
+
return normalizeMethod(getSubmitterAttribute(submitter, "formmethod") || form.getAttribute("method"));
|
|
322
|
+
}
|
|
323
|
+
function resolveFormAction(form, submitter) {
|
|
324
|
+
return resolveUrl(
|
|
325
|
+
getSubmitterAttribute(submitter, "formaction") || form.getAttribute("action") || getDocumentBaseUrl()
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
function resolveFormTarget(form, submitter) {
|
|
329
|
+
return (getSubmitterAttribute(submitter, "formtarget") || form.getAttribute("target") || "").trim();
|
|
330
|
+
}
|
|
331
|
+
function resolveFormEnctype(form, submitter) {
|
|
332
|
+
return (getSubmitterAttribute(submitter, "formenctype") || form.getAttribute("enctype") || "application/x-www-form-urlencoded").toLowerCase();
|
|
333
|
+
}
|
|
334
|
+
function canProxyFormTarget(target) {
|
|
335
|
+
const normalizedTarget = target.toLowerCase();
|
|
336
|
+
return normalizedTarget === "" || normalizedTarget === "_self" || normalizedTarget === "_top" || normalizedTarget === "_parent";
|
|
337
|
+
}
|
|
338
|
+
function navigateFormProxy(proxyUrl, target) {
|
|
339
|
+
const normalizedTarget = target.toLowerCase();
|
|
340
|
+
if (!normalizedTarget || normalizedTarget === "_self") {
|
|
341
|
+
window.location.assign(proxyUrl);
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
if (normalizedTarget === "_top" && window.top) {
|
|
345
|
+
window.top.location.assign(proxyUrl);
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
if (normalizedTarget === "_parent" && window.parent) {
|
|
349
|
+
window.parent.location.assign(proxyUrl);
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
window.location.assign(proxyUrl);
|
|
353
|
+
}
|
|
354
|
+
function proxyFormSubmission(form, submitter) {
|
|
355
|
+
return __async(this, null, function* () {
|
|
356
|
+
const target = resolveFormTarget(form, submitter);
|
|
357
|
+
if (!canProxyFormTarget(target)) {
|
|
358
|
+
return false;
|
|
359
|
+
}
|
|
360
|
+
const method = resolveFormMethod(form, submitter);
|
|
361
|
+
const actionUrl = resolveFormAction(form, submitter);
|
|
362
|
+
const formData = createFormData(form, submitter);
|
|
363
|
+
const headers = {};
|
|
364
|
+
let requestUrl = actionUrl;
|
|
365
|
+
let body = null;
|
|
366
|
+
if (method === "GET" || method === "HEAD") {
|
|
367
|
+
requestUrl = appendFormDataToUrl(actionUrl, formData);
|
|
368
|
+
} else {
|
|
369
|
+
const enctype = resolveFormEnctype(form, submitter);
|
|
370
|
+
if (enctype === "text/plain") {
|
|
371
|
+
headers["content-type"] = "text/plain;charset=UTF-8";
|
|
372
|
+
body = formDataToPlainText(formData);
|
|
373
|
+
} else if (enctype === "multipart/form-data") {
|
|
374
|
+
body = formData;
|
|
375
|
+
} else {
|
|
376
|
+
headers["content-type"] = "application/x-www-form-urlencoded;charset=UTF-8";
|
|
377
|
+
body = formDataToUrlSearchParams(formData);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
if (!shouldProxyBridgeUrl(requestUrl, getDocumentBaseUrl(), proxyRequestPattern)) {
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
const proxyUrl = yield storeInterceptedRequest(requestUrl, method, headers, body, "include");
|
|
384
|
+
navigateFormProxy(proxyUrl, target);
|
|
385
|
+
return true;
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
const originalFetch = window.fetch;
|
|
389
|
+
window.fetch = function(input, init) {
|
|
390
|
+
return __async(this, null, function* () {
|
|
391
|
+
var _a;
|
|
392
|
+
let url;
|
|
393
|
+
let method = "GET";
|
|
394
|
+
const headers = {};
|
|
395
|
+
let inheritedHeaders = false;
|
|
396
|
+
let body = null;
|
|
397
|
+
let credentialsMode = "same-origin";
|
|
398
|
+
let requestCloneError = null;
|
|
399
|
+
if (input instanceof Request) {
|
|
400
|
+
url = input.url;
|
|
401
|
+
method = input.method;
|
|
402
|
+
credentialsMode = normalizeCredentialsMode(input.credentials);
|
|
403
|
+
inheritedHeaders = true;
|
|
404
|
+
input.headers.forEach((value, key) => {
|
|
405
|
+
headers[key] = value;
|
|
406
|
+
});
|
|
407
|
+
try {
|
|
408
|
+
const cloned = input.clone();
|
|
409
|
+
const buffer = yield cloned.arrayBuffer();
|
|
410
|
+
if (buffer.byteLength > 0) {
|
|
411
|
+
body = buffer;
|
|
412
|
+
}
|
|
413
|
+
} catch (error) {
|
|
414
|
+
requestCloneError = error;
|
|
415
|
+
}
|
|
416
|
+
} else {
|
|
417
|
+
url = input instanceof URL ? input.toString() : input;
|
|
418
|
+
}
|
|
419
|
+
url = resolveUrl(url);
|
|
420
|
+
if (init) {
|
|
421
|
+
if (init.method) {
|
|
422
|
+
method = init.method;
|
|
423
|
+
}
|
|
424
|
+
if (init.headers) {
|
|
425
|
+
if (inheritedHeaders) {
|
|
426
|
+
Object.keys(headers).forEach((key) => {
|
|
427
|
+
delete headers[key];
|
|
428
|
+
});
|
|
429
|
+
inheritedHeaders = false;
|
|
430
|
+
}
|
|
431
|
+
const normalized = new Headers(init.headers);
|
|
432
|
+
normalized.forEach((value, key) => {
|
|
433
|
+
headers[key] = value;
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
if (init.body !== void 0) {
|
|
437
|
+
body = init.body;
|
|
438
|
+
}
|
|
439
|
+
if (init.credentials) {
|
|
440
|
+
credentialsMode = normalizeCredentialsMode(init.credentials);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
if (requestCloneError != null) {
|
|
444
|
+
return originalFetch.call(window, input, init);
|
|
445
|
+
}
|
|
446
|
+
if (!shouldProxyBridgeUrl(url, getDocumentBaseUrl(), proxyRequestPattern)) {
|
|
447
|
+
return originalFetch.call(window, input, init);
|
|
448
|
+
}
|
|
449
|
+
const signal = (_a = init == null ? void 0 : init.signal) != null ? _a : input instanceof Request ? input.signal : void 0;
|
|
450
|
+
let proxyUrl;
|
|
451
|
+
try {
|
|
452
|
+
proxyUrl = yield storeInterceptedRequest(url, method, headers, body, credentialsMode);
|
|
453
|
+
} catch (_error) {
|
|
454
|
+
return originalFetch.call(window, input, init);
|
|
455
|
+
}
|
|
456
|
+
const proxyResponse = yield originalFetch.call(globalThis, proxyUrl, {
|
|
457
|
+
method: "GET",
|
|
458
|
+
signal
|
|
459
|
+
});
|
|
460
|
+
if (isNativeProxyErrorResponse(proxyResponse)) {
|
|
461
|
+
throw new TypeError(nativeProxyErrorMessage(proxyResponse));
|
|
462
|
+
}
|
|
463
|
+
return proxyResponse;
|
|
464
|
+
});
|
|
465
|
+
};
|
|
466
|
+
const originalXhrOpen = XMLHttpRequest.prototype.open;
|
|
467
|
+
const originalXhrSend = XMLHttpRequest.prototype.send;
|
|
468
|
+
const originalXhrAbort = XMLHttpRequest.prototype.abort;
|
|
469
|
+
const originalXhrSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
|
|
470
|
+
const originalXhrOverrideMimeType = XMLHttpRequest.prototype.overrideMimeType;
|
|
471
|
+
XMLHttpRequest.prototype.open = function(method, url, ...rest) {
|
|
472
|
+
this.__proxyMethod = method;
|
|
473
|
+
this.__proxyUrl = resolveUrl(url instanceof URL ? url.toString() : url);
|
|
474
|
+
this.__proxyHeaders = {};
|
|
475
|
+
this.__proxyAsync = rest[0] !== false;
|
|
476
|
+
this.__proxyCredentials = this.withCredentials ? "include" : "same-origin";
|
|
477
|
+
this.__proxyUsername = typeof rest[1] === "string" ? rest[1] : null;
|
|
478
|
+
this.__proxyPassword = typeof rest[2] === "string" ? rest[2] : "";
|
|
479
|
+
this.__proxyAborted = false;
|
|
480
|
+
this.__proxyOverrideMimeType = null;
|
|
481
|
+
return originalXhrOpen.apply(this, [method, url, ...rest]);
|
|
482
|
+
};
|
|
483
|
+
XMLHttpRequest.prototype.setRequestHeader = function(name, value) {
|
|
484
|
+
if (this.__proxyHeaders) {
|
|
485
|
+
appendCapturedHeader(this.__proxyHeaders, name, value);
|
|
486
|
+
}
|
|
487
|
+
return originalXhrSetRequestHeader.call(this, name, value);
|
|
488
|
+
};
|
|
489
|
+
XMLHttpRequest.prototype.abort = function() {
|
|
490
|
+
this.__proxyAborted = true;
|
|
491
|
+
return originalXhrAbort.call(this);
|
|
492
|
+
};
|
|
493
|
+
if (typeof originalXhrOverrideMimeType === "function") {
|
|
494
|
+
XMLHttpRequest.prototype.overrideMimeType = function(mimeType) {
|
|
495
|
+
this.__proxyOverrideMimeType = mimeType;
|
|
496
|
+
return originalXhrOverrideMimeType.call(this, mimeType);
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
XMLHttpRequest.prototype.send = function(body) {
|
|
500
|
+
const xhr = this;
|
|
501
|
+
const method = xhr.__proxyMethod || "GET";
|
|
502
|
+
const url = xhr.__proxyUrl || "";
|
|
503
|
+
const headers = xhr.__proxyHeaders || {};
|
|
504
|
+
const isAsync = xhr.__proxyAsync !== false;
|
|
505
|
+
const credentialsMode = xhr.withCredentials ? "include" : "same-origin";
|
|
506
|
+
const username = xhr.__proxyUsername;
|
|
507
|
+
const password = xhr.__proxyPassword;
|
|
508
|
+
if (typeof username === "string" && username.length > 0 && !hasHeader(headers, "Authorization")) {
|
|
509
|
+
headers["Authorization"] = "Basic " + stringToBase64(username + ":" + (typeof password === "string" ? password : ""));
|
|
510
|
+
}
|
|
511
|
+
function completeSend(proxyUrl) {
|
|
512
|
+
if (xhr.__proxyAborted) {
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
const replayState = captureXhrReplayState(xhr);
|
|
516
|
+
originalXhrOpen.call(xhr, "GET", proxyUrl, true);
|
|
517
|
+
restoreXhrReplayState(xhr, replayState);
|
|
518
|
+
originalXhrSend.call(xhr, null);
|
|
519
|
+
}
|
|
520
|
+
if (!shouldProxyBridgeUrl(url, getDocumentBaseUrl(), proxyRequestPattern)) {
|
|
521
|
+
originalXhrSend.call(xhr, body != null ? body : null);
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
if (!isAsync) {
|
|
525
|
+
console.warn("[proxy-bridge] Synchronous XMLHttpRequest cannot be proxied; falling back to the original request");
|
|
526
|
+
originalXhrSend.call(xhr, body != null ? body : null);
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
storeInterceptedRequest(url, method, headers, body, credentialsMode).then((proxyUrl) => {
|
|
530
|
+
completeSend(proxyUrl);
|
|
531
|
+
}).catch((_error) => {
|
|
532
|
+
if (xhr.__proxyAborted) {
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
console.error("[proxy-bridge] Failed to encode XMLHttpRequest body");
|
|
536
|
+
originalXhrSend.call(xhr, body != null ? body : null);
|
|
537
|
+
});
|
|
538
|
+
};
|
|
539
|
+
const originalFormSubmit = HTMLFormElement.prototype.submit;
|
|
540
|
+
document.addEventListener("submit", (event) => {
|
|
541
|
+
const form = event.target instanceof HTMLFormElement ? event.target : null;
|
|
542
|
+
if (!form) {
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
if (consumeProxySubmitReplayBypass(form)) {
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
const submitter = getSubmitEventSubmitter(event);
|
|
549
|
+
const target = resolveFormTarget(form, submitter);
|
|
550
|
+
const method = resolveFormMethod(form, submitter);
|
|
551
|
+
let requestUrl = resolveFormAction(form, submitter);
|
|
552
|
+
if (method === "GET" || method === "HEAD") {
|
|
553
|
+
requestUrl = appendFormDataToUrl(requestUrl, createFormData(form, submitter));
|
|
554
|
+
}
|
|
555
|
+
if (!shouldProxySubmitRequest(
|
|
556
|
+
event.defaultPrevented,
|
|
557
|
+
canProxyFormTarget(target),
|
|
558
|
+
requestUrl,
|
|
559
|
+
getDocumentBaseUrl(),
|
|
560
|
+
proxyRequestPattern
|
|
561
|
+
)) {
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
event.preventDefault();
|
|
565
|
+
proxyFormSubmission(form, submitter).then((handled) => {
|
|
566
|
+
if (!handled) {
|
|
567
|
+
replaySubmitAfterProxyFailure(form, originalFormSubmit, submitter);
|
|
568
|
+
}
|
|
569
|
+
}).catch((error) => {
|
|
570
|
+
console.error("[proxy-bridge] Failed to proxy form submission", error);
|
|
571
|
+
replaySubmitAfterProxyFailure(form, originalFormSubmit, submitter);
|
|
572
|
+
});
|
|
573
|
+
});
|
|
574
|
+
HTMLFormElement.prototype.submit = function() {
|
|
575
|
+
const form = this;
|
|
576
|
+
proxyFormSubmission(form).then((handled) => {
|
|
577
|
+
if (!handled) {
|
|
578
|
+
originalFormSubmit.call(form);
|
|
579
|
+
}
|
|
580
|
+
}).catch((_error) => {
|
|
581
|
+
console.error("[proxy-bridge] Failed to proxy programmatic form submission");
|
|
582
|
+
originalFormSubmit.call(form);
|
|
583
|
+
});
|
|
584
|
+
};
|
|
585
|
+
})();
|
|
586
|
+
})();
|
|
@@ -354,7 +354,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
354
354
|
self.initWebview(isInspectable: isInspectable)
|
|
355
355
|
}
|
|
356
356
|
|
|
357
|
-
public init(url: URL, headers: [String: String], isInspectable: Bool, credentials: WKWebViewCredentials? = nil, preventDeeplink: Bool, blankNavigationTab: Bool, enabledSafeBottomMargin: Bool, enabledSafeTopMargin: Bool = true, blockedHosts: [String], authorizedAppLinks: [String], allowWebViewJsVisibilityControl: Bool = false, allowScreenshotsFromWebPage: Bool = false, captureConsoleLogs: Bool = false, proxyRequests: Bool = false, proxySchemeHandler: ProxySchemeHandler? = nil, documentStartUserScripts: [String] = [], openBlankTargetInWebView: Bool = false) {
|
|
357
|
+
public init(url: URL, headers: [String: String], isInspectable: Bool, credentials: WKWebViewCredentials? = nil, preventDeeplink: Bool, blankNavigationTab: Bool, enabledSafeBottomMargin: Bool, enabledSafeTopMargin: Bool = true, blockedHosts: [String], authorizedAppLinks: [String], allowWebViewJsVisibilityControl: Bool = false, allowScreenshotsFromWebPage: Bool = false, captureConsoleLogs: Bool = false, proxyRequests: Bool = false, proxySchemeHandler: ProxySchemeHandler? = nil, proxyBridge: ProxyBridge? = nil, proxyBridgeAccessToken: String? = nil, legacyProxyRequestURLRegexPattern: String? = nil, documentStartUserScripts: [String] = [], openBlankTargetInWebView: Bool = false) {
|
|
358
358
|
super.init(nibName: nil, bundle: nil)
|
|
359
359
|
self.blankNavigationTab = blankNavigationTab
|
|
360
360
|
self.enabledSafeBottomMargin = enabledSafeBottomMargin
|
|
@@ -366,6 +366,9 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
366
366
|
self.captureConsoleLogs = captureConsoleLogs
|
|
367
367
|
self.proxyRequests = proxyRequests
|
|
368
368
|
self.proxySchemeHandler = proxySchemeHandler
|
|
369
|
+
self.proxyBridge = proxyBridge
|
|
370
|
+
self.proxyBridgeAccessToken = proxyBridgeAccessToken
|
|
371
|
+
self.legacyProxyRequestURLRegexPattern = legacyProxyRequestURLRegexPattern
|
|
369
372
|
self.openBlankTargetInWebView = openBlankTargetInWebView
|
|
370
373
|
self.setHeaders(headers: headers)
|
|
371
374
|
self.setPreventDeeplink(preventDeeplink: preventDeeplink)
|
|
@@ -422,6 +425,9 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
422
425
|
var disableOverscroll: Bool = false
|
|
423
426
|
var proxyRequests: Bool = false
|
|
424
427
|
var proxySchemeHandler: ProxySchemeHandler?
|
|
428
|
+
var proxyBridge: ProxyBridge?
|
|
429
|
+
var proxyBridgeAccessToken: String?
|
|
430
|
+
var legacyProxyRequestURLRegexPattern: String?
|
|
425
431
|
var initialWebConfiguration: WKWebViewConfiguration?
|
|
426
432
|
var waitsForPopupNavigation = false
|
|
427
433
|
var hiddenPopupWindow = false
|
|
@@ -1298,6 +1304,25 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
1298
1304
|
}
|
|
1299
1305
|
print("[InAppBrowser - preShowScriptError]: Error!!!!")
|
|
1300
1306
|
semaphore.signal()
|
|
1307
|
+
} else if message.name == "capgoProxyBridge" {
|
|
1308
|
+
guard let messageBody = message.body as? [String: Any],
|
|
1309
|
+
let token = messageBody["token"] as? String,
|
|
1310
|
+
let requestId = messageBody["requestId"] as? String,
|
|
1311
|
+
let method = messageBody["method"] as? String,
|
|
1312
|
+
let headersJson = messageBody["headersJson"] as? String else {
|
|
1313
|
+
return
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
let base64Body = messageBody["base64Body"] as? String ?? ""
|
|
1317
|
+
let credentialsMode = messageBody["credentialsMode"] as? String ?? "same-origin"
|
|
1318
|
+
proxyBridge?.storeRequest(
|
|
1319
|
+
token: token,
|
|
1320
|
+
requestId: requestId,
|
|
1321
|
+
method: method,
|
|
1322
|
+
headersJson: headersJson,
|
|
1323
|
+
base64Body: base64Body,
|
|
1324
|
+
credentialsMode: credentialsMode
|
|
1325
|
+
)
|
|
1301
1326
|
} else if message.name == "close" {
|
|
1302
1327
|
closeView()
|
|
1303
1328
|
} else if message.name == "hide" {
|
|
@@ -1432,6 +1457,35 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
1432
1457
|
userContentController.addUserScript(script)
|
|
1433
1458
|
}
|
|
1434
1459
|
|
|
1460
|
+
private func addProxyBridgeUserScripts(to userContentController: WKUserContentController) {
|
|
1461
|
+
guard let accessToken = proxyBridgeAccessToken else {
|
|
1462
|
+
return
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
let bootstrapScript = WKUserScript(
|
|
1466
|
+
source: ProxyBridgeSupport.bootstrapScriptSource(),
|
|
1467
|
+
injectionTime: .atDocumentStart,
|
|
1468
|
+
forMainFrameOnly: false
|
|
1469
|
+
)
|
|
1470
|
+
userContentController.addUserScript(bootstrapScript)
|
|
1471
|
+
|
|
1472
|
+
let proxyRegexSource = legacyProxyRequestURLRegexPattern ?? ""
|
|
1473
|
+
guard let bridgeScriptSource = ProxyBridgeSupport.loadBundledBridgeScript(
|
|
1474
|
+
accessToken: accessToken,
|
|
1475
|
+
proxyRegexSource: proxyRegexSource
|
|
1476
|
+
) else {
|
|
1477
|
+
print("[InAppBrowser][Proxy] WARNING: Failed to load proxy-bridge.js for iOS injection")
|
|
1478
|
+
return
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
let bridgeScript = WKUserScript(
|
|
1482
|
+
source: bridgeScriptSource,
|
|
1483
|
+
injectionTime: .atDocumentStart,
|
|
1484
|
+
forMainFrameOnly: false
|
|
1485
|
+
)
|
|
1486
|
+
userContentController.addUserScript(bridgeScript)
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1435
1489
|
func injectJavaScriptInterface() {
|
|
1436
1490
|
let script = mobileAppScriptSource()
|
|
1437
1491
|
DispatchQueue.main.async {
|
|
@@ -1470,6 +1524,7 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
1470
1524
|
userContentController.removeScriptMessageHandler(forName: "takeScreenshot")
|
|
1471
1525
|
userContentController.removeScriptMessageHandler(forName: "consoleMessageHandler")
|
|
1472
1526
|
userContentController.removeScriptMessageHandler(forName: "magicPrint")
|
|
1527
|
+
userContentController.removeScriptMessageHandler(forName: "capgoProxyBridge")
|
|
1473
1528
|
|
|
1474
1529
|
if proxyRequests || proxySchemeHandler != nil, let handler = proxySchemeHandler {
|
|
1475
1530
|
WKWebView.enableCustomSchemeHandling(for: ["https", "http"])
|
|
@@ -1481,6 +1536,10 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
1481
1536
|
}
|
|
1482
1537
|
}
|
|
1483
1538
|
|
|
1539
|
+
if ProxyBridgeSupport.shouldInjectBridge(hasProxySchemeHandler: proxySchemeHandler != nil) {
|
|
1540
|
+
addProxyBridgeUserScripts(to: userContentController)
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1484
1543
|
let weakHandler = WeakScriptMessageHandler(self)
|
|
1485
1544
|
userContentController.add(weakHandler, name: "messageHandler")
|
|
1486
1545
|
userContentController.add(weakHandler, name: "preShowScriptError")
|
|
@@ -1516,6 +1575,9 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
1516
1575
|
)
|
|
1517
1576
|
)
|
|
1518
1577
|
}
|
|
1578
|
+
if ProxyBridgeSupport.shouldInjectBridge(hasProxySchemeHandler: proxySchemeHandler != nil) {
|
|
1579
|
+
userContentController.add(weakHandler, name: "capgoProxyBridge")
|
|
1580
|
+
}
|
|
1519
1581
|
userContentController.add(weakHandler, name: "magicPrint")
|
|
1520
1582
|
|
|
1521
1583
|
// Inject JavaScript to override window.print
|
|
@@ -1704,7 +1766,9 @@ open class WKWebViewController: UIViewController, WKScriptMessageHandler {
|
|
|
1704
1766
|
self.disableOverscroll = parent.disableOverscroll
|
|
1705
1767
|
self.proxyRequests = parent.proxyRequests
|
|
1706
1768
|
self.proxySchemeHandler = proxySchemeHandler
|
|
1707
|
-
self.
|
|
1769
|
+
self.proxyBridge = parent.proxyBridge
|
|
1770
|
+
self.proxyBridgeAccessToken = parent.proxyBridgeAccessToken
|
|
1771
|
+
self.legacyProxyRequestURLRegexPattern = parent.legacyProxyRequestURLRegexPattern
|
|
1708
1772
|
self.waitsForPopupNavigation = true
|
|
1709
1773
|
self.hiddenPopupWindow = parent.hiddenPopupWindow
|
|
1710
1774
|
self.opensHidden = parent.hiddenPopupWindow
|
|
@@ -1984,6 +2048,7 @@ public extension WKWebViewController {
|
|
|
1984
2048
|
webView.configuration.userContentController.removeScriptMessageHandler(forName: "preShowScriptSuccess")
|
|
1985
2049
|
webView.configuration.userContentController.removeScriptMessageHandler(forName: "preShowScriptError")
|
|
1986
2050
|
webView.configuration.userContentController.removeScriptMessageHandler(forName: "magicPrint")
|
|
2051
|
+
webView.configuration.userContentController.removeScriptMessageHandler(forName: "capgoProxyBridge")
|
|
1987
2052
|
|
|
1988
2053
|
webView.removeFromSuperview()
|
|
1989
2054
|
// Also clean progress bar view if present
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capgo/capacitor-inappbrowser",
|
|
3
|
-
"version": "8.6.
|
|
3
|
+
"version": "8.6.34",
|
|
4
4
|
"description": "Capacitor plugin in app browser",
|
|
5
5
|
"main": "dist/plugin.cjs.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
],
|
|
33
33
|
"scripts": {
|
|
34
34
|
"verify": "bun run verify:ios && bun run verify:android && bun run verify:web",
|
|
35
|
-
"verify:ios": "xcodebuild -scheme CapgoCapacitorInappbrowser -destination generic/platform=iOS",
|
|
35
|
+
"verify:ios": "bun run build:proxy-bridge && xcodebuild -scheme CapgoCapacitorInappbrowser -destination generic/platform=iOS",
|
|
36
36
|
"verify:android": "cd android && ./gradlew clean build test && cd ..",
|
|
37
37
|
"verify:web": "bun run build && bun run test:web",
|
|
38
38
|
"test:web": "bun test src/proxy-bridge-support.test.ts",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"prettier": "prettier-pretty-check \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
|
|
44
44
|
"swiftlint": "node-swiftlint",
|
|
45
45
|
"docgen": "docgen --api InAppBrowserPlugin --output-readme README.md --output-json dist/docs.json",
|
|
46
|
-
"build:proxy-bridge": "esbuild src/proxy-bridge.ts --bundle --outfile=android/src/main/assets/proxy-bridge.js --format=iife --target=es2015",
|
|
46
|
+
"build:proxy-bridge": "esbuild src/proxy-bridge.ts --bundle --outfile=android/src/main/assets/proxy-bridge.js --format=iife --target=es2015 && mkdir -p ios/Sources/InAppBrowserPlugin/Resources && cp android/src/main/assets/proxy-bridge.js ios/Sources/InAppBrowserPlugin/Resources/proxy-bridge.js",
|
|
47
47
|
"build": "bun run clean && bun run docgen && tsc && rollup -c rollup.config.mjs && bun run build:proxy-bridge",
|
|
48
48
|
"clean": "rimraf ./dist",
|
|
49
49
|
"watch": "tsc --watch",
|