Skip to content

Commit eceafc8

Browse files
LukasOgunfeitimiLukas
andauthored
Intercept webview requests (#23)
* intercept requests * better logic * keep the data parsed * remove log import * change payload structure * change payload structure * add log import * check clone func --------- Co-authored-by: Lukas <[email protected]>
1 parent 4fa8acd commit eceafc8

File tree

7 files changed

+324
-129
lines changed

7 files changed

+324
-129
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
browser.runtime.onMessage.addListener(function (message, sender, _) {
2+
if (message.type === "intercepted_request") {
3+
try {
4+
browser.runtime.sendNativeMessage("gecko", {
5+
event: "intercepted_request",
6+
data: message.data,
7+
});
8+
} catch (err) {
9+
// Silently handle errors to prevent crashes
10+
}
11+
}
12+
});
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
const script = document.createElement("script");
2+
script.textContent = `
3+
(function() {
4+
const log = (request_type, data) => {
5+
try {
6+
window.postMessage({
7+
type: "intercepted_request",
8+
payload: {
9+
request_type,
10+
data
11+
}
12+
}, "*");
13+
} catch (e) {}
14+
};
15+
const originalFetch = window.fetch;
16+
window.fetch = async function(input, init) {
17+
try {
18+
const method = (init && init.method) || (typeof input === "string" ? "GET" : input.method || "GET");
19+
const url = typeof input === "string" ? input : input.url;
20+
let requestHeaders = init?.headers || {};
21+
if (requestHeaders instanceof Headers) {
22+
requestHeaders = Object.fromEntries(requestHeaders.entries());
23+
}
24+
log("fetch_request", {
25+
url,
26+
method,
27+
headers: requestHeaders,
28+
body: init?.body,
29+
});
30+
const response = await originalFetch.apply(this, arguments);
31+
if (!response || !response.clone) {
32+
return response;
33+
}
34+
const clonedResponse = response.clone();
35+
let responseHeaders = clonedResponse.headers || {};
36+
if (responseHeaders instanceof Headers) {
37+
responseHeaders = Object.fromEntries(responseHeaders.entries());
38+
}
39+
log("fetch_response", {
40+
url,
41+
method,
42+
headers: responseHeaders,
43+
body: await clonedResponse.text(),
44+
status: clonedResponse.status,
45+
});
46+
return response;
47+
} catch (err) {
48+
log("fetch_error", err.toString());
49+
}
50+
};
51+
const OriginalXHR = window.XMLHttpRequest;
52+
53+
function PatchedXHR() {
54+
const xhr = new OriginalXHR();
55+
let _method = "";
56+
let _url = "";
57+
let headers = {};
58+
xhr.open = new Proxy(xhr.open, {
59+
apply(t, thisArg, args) {
60+
_method = args[0];
61+
_url = args[1];
62+
return Reflect.apply(t, thisArg, args);
63+
},
64+
});
65+
const setRequestHeader = xhr.setRequestHeader;
66+
xhr.setRequestHeader = function(name, value) {
67+
headers[name] = value;
68+
return setRequestHeader.apply(xhr, arguments);
69+
};
70+
xhr.send = new Proxy(xhr.send, {
71+
apply(t, thisArg, args) {
72+
log("xhr_request", {
73+
method: _method,
74+
url: _url,
75+
headers,
76+
body: args[0],
77+
});
78+
xhr.addEventListener("loadend", function() {
79+
log("xhr_response", {
80+
method: _method,
81+
url: _url,
82+
headers,
83+
body: xhr.responseText || xhr.response,
84+
status: xhr.status,
85+
});
86+
});
87+
return Reflect.apply(t, thisArg, args);
88+
},
89+
});
90+
return xhr;
91+
}
92+
window.XMLHttpRequest = PatchedXHR;
93+
})();
94+
`;
95+
(document.head || document.documentElement).appendChild(script);
96+
97+
window.addEventListener("message", (event) => {
98+
if (event.source !== window) return;
99+
if (event.data?.type === "intercepted_request") {
100+
try {
101+
browser.runtime.sendMessage({
102+
type: "intercepted_request",
103+
data: event.data.payload,
104+
});
105+
} catch (err) {}
106+
}
107+
});
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"manifest_version": 2,
3+
"name": "Opacity Extension for Intercepting Requests",
4+
"version": "1.0",
5+
"description": "Opacity extension for GeckoView for intercepting requests",
6+
"applications": {
7+
"gecko": {
8+
9+
"strict_min_version": "68.0"
10+
}
11+
},
12+
"background": {
13+
"scripts": [
14+
"background.js"
15+
]
16+
},
17+
"content_scripts": [
18+
{
19+
"matches": ["<all_urls>"],
20+
"js": ["content.js"],
21+
"run_at": "document_start",
22+
"all_frames": true
23+
}
24+
],
25+
"permissions": [
26+
"webRequest",
27+
"activeTab",
28+
"tabs",
29+
"webRequestBlocking",
30+
"cookies",
31+
"*://*/*",
32+
"<all_urls>",
33+
"nativeMessaging",
34+
"nativeMessagingFromContent",
35+
"geckoViewAddons",
36+
"webNavigation",
37+
"scripting"
38+
]
39+
}

OpacityCore/src/main/cpp/OpacityCore.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,16 +136,17 @@ extern "C" void android_set_request_header(const char *key, const char *value) {
136136
env->CallVoidMethod(java_object, method, jkey, jvalue);
137137
}
138138

139-
extern "C" void android_present_webview() {
139+
extern "C" void android_present_webview(bool shouldIntercept) {
140140
JNIEnv *env = GetJniEnv();
141141
// Get the Kotlin class
142142
jclass jOpacityCore = env->GetObjectClass(java_object);
143143

144144
// Get the method ID for the method you want to call
145-
jmethodID method = env->GetMethodID(jOpacityCore, "presentBrowser", "()V");
145+
jmethodID method = env->GetMethodID(jOpacityCore, "presentBrowser", "(Z)V");
146146

147147
// Call the method with the necessary parameters
148-
env->CallVoidMethod(java_object, method);
148+
jboolean jshouldIntercept = shouldIntercept ? JNI_TRUE : JNI_FALSE;
149+
env->CallVoidMethod(java_object, method, jshouldIntercept);
149150
}
150151

151152
extern "C" const char *get_ip_address() {

OpacityCore/src/main/jni/include/sdk.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ extern void android_prepare_request(const char *url);
247247

248248
extern void android_set_request_header(const char *key, const char *value);
249249

250-
extern void android_present_webview(void);
250+
extern void android_present_webview(bool intercept_requests);
251251

252252
extern void android_close_webview(void);
253253

0 commit comments

Comments
 (0)