*Add navigation monitoring system to hijack search results and attempt to resolve via web3

This commit is contained in:
Derrick Hammer 2022-08-14 13:15:32 -04:00
parent 1443b2d79a
commit f3ee68679b
Signed by: pcfreak30
GPG Key ID: C997C339BE476FF2
3 changed files with 129 additions and 2 deletions

View File

@ -8,7 +8,7 @@
"48": "icon.png",
"96": "icon@2x.png"
},
"permissions": ["proxy", "webRequest", "webRequestBlocking", "<all_urls>"],
"permissions": ["proxy", "webRequest", "webRequestBlocking", "webNavigation", "<all_urls>"],
"background": {
"scripts": ["background.js"]
},

View File

@ -1,4 +1,4 @@
import { WebRequest, Proxy } from "webextension-polyfill";
import { WebRequest, Proxy, Tabs, WebNavigation } from "webextension-polyfill";
import OnHeadersReceivedDetailsType = WebRequest.OnHeadersReceivedDetailsType;
import OnBeforeRequestDetailsType = WebRequest.OnBeforeRequestDetailsType;
import OnBeforeSendHeadersDetailsType = WebRequest.OnBeforeSendHeadersDetailsType;
@ -9,6 +9,7 @@ import OnRequestDetailsType = Proxy.OnRequestDetailsType;
import HttpHeaders = WebRequest.HttpHeaders;
import StreamFilter = WebRequest.StreamFilter;
import HttpHeadersItemType = WebRequest.HttpHeadersItemType;
import OnBeforeNavigateDetailsType = WebNavigation.OnBeforeNavigateDetailsType;
export {
OnHeadersReceivedDetailsType,
@ -21,4 +22,6 @@ export {
HttpHeaders,
StreamFilter,
HttpHeadersItemType,
Tabs,
OnBeforeNavigateDetailsType,
};

View File

@ -3,6 +3,7 @@ import browser from "@lumeweb/webextension-polyfill";
import BaseProvider from "./contentProviders/baseProvider.js";
import {
BlockingResponse,
OnBeforeNavigateDetailsType,
OnBeforeRequestDetailsType,
OnBeforeSendHeadersDetailsType,
OnCompletedDetailsType,
@ -10,11 +11,16 @@ import {
OnHeadersReceivedDetailsType,
OnRequestDetailsType,
} from "./types";
import { getTld, isDomain, isIp, normalizeDomain } from "./util.js";
import tldEnum from "@lumeweb/tld-enum";
import { resolve } from "@lumeweb/kernel-dns-client";
import { blake2b, bufToHex } from "libskynet";
export default class WebEngine {
private contentProviders: BaseProvider[] = [];
private requests: Map<string, BaseProvider> = new Map();
private requestData: Map<string, {}> = new Map();
private navigations: Map<string, Promise<any>> = new Map();
constructor() {
browser.webRequest.onHeadersReceived.addListener(
@ -49,6 +55,9 @@ export default class WebEngine {
urls: ["<all_urls>"],
}
);
browser.webNavigation.onBeforeNavigate.addListener(
this.handleNavigationRequest.bind(this)
);
}
private async headerHandler(
@ -80,6 +89,20 @@ export default class WebEngine {
private async requestHandler(
details: OnBeforeRequestDetailsType
): Promise<BlockingResponse> {
const navId = this.getNavigationId(details);
let navRedirect: boolean | string = false;
if (this.navigations.has(navId)) {
try {
await this.navigations.get(navId);
} catch (e: any) {
navRedirect = e;
}
}
if (navRedirect && navRedirect !== details.url) {
return { redirectUrl: navRedirect as string };
}
return this.processHandler(details, "handleRequest");
}
@ -162,4 +185,105 @@ export default class WebEngine {
return def;
}
private async handleNavigationRequest(details: OnBeforeNavigateDetailsType) {
if (!details.url) {
return;
}
if (!isDomain(details.url) || isIp(details.url)) {
return;
}
const originalUrl = new URL(details.url);
const hostname = normalizeDomain(originalUrl.hostname);
if (["chrome:"].includes(originalUrl.protocol)) {
return;
}
if ("google.com" === hostname) {
if (
!(
originalUrl.searchParams.has("client") &&
originalUrl.searchParams.get("client")?.includes("firefox")
)
) {
return;
}
}
let resolveRequest: any, rejectRequest: any;
let promise = new Promise((resolve, reject) => {
resolveRequest = resolve;
rejectRequest = reject;
});
this.navigations.set(this.getNavigationId(details), promise);
let queriedUrl = originalUrl.searchParams.get("q") as string;
let queriedHost = queriedUrl;
try {
let queriedUrlUbj = new URL(queriedUrl);
queriedHost = queriedUrlUbj.hostname;
} catch {}
if (tldEnum.list.includes(getTld(queriedHost))) {
resolveRequest();
return false;
}
if (isIp(queriedHost)) {
resolveRequest();
return;
}
if (/[\s_]/.test(queriedHost)) {
resolveRequest();
return;
}
let dns;
try {
dns = await resolve(queriedHost, {});
} catch (e) {
resolveRequest();
return;
}
if (!dns) {
resolveRequest();
return;
}
if (!queriedUrl.includes("://")) {
queriedUrl = `http://${queriedUrl}`;
}
rejectRequest(queriedUrl);
}
private getNavigationId(details: any) {
return `${details.tabId}_${bufToHex(
blake2b(new TextEncoder().encode(details.url))
)}`;
}
public static cancelRequest(tabId: number) {
const handler = (details: OnBeforeRequestDetailsType): BlockingResponse => {
if (details.tabId !== tabId) {
return {};
}
browser.webRequest.onBeforeRequest.removeListener(handler);
return { cancel: true };
};
browser.webRequest.onBeforeRequest.addListener(
handler,
{ urls: ["<all_urls>"] },
["blocking"]
);
}
}