Skip to content

Commit

Permalink
Merge pull request #332 from tim-crisp/feature/proxy-protocol-support
Browse files Browse the repository at this point in the history
Feature/proxy protocol support
  • Loading branch information
younesaassila authored Feb 7, 2025
2 parents b59855a + f2aee15 commit c638fdf
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 20 deletions.
2 changes: 1 addition & 1 deletion src/background/handlers/onBeforeVideoWeaverRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export default function onBeforeVideoWeaverRequest(
textLower.includes("https://example.com") &&
textLower.includes("https://help.twitch.tv/");
const proxy =
details.proxyInfo && details.proxyInfo.type !== "direct"
details.proxyInfo && details.proxyInfo.type !== "DIRECT"
? getUrlFromProxyInfo(details.proxyInfo)
: null;

Expand Down
14 changes: 7 additions & 7 deletions src/background/handlers/onProxyRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export default async function onProxyRequest(
}

const host = getHostFromUrl(details.url);
if (!host) return { type: "direct" };
if (!host) return { type: "DIRECT" };

const documentHost = details.documentUrl
? getHostFromUrl(details.documentUrl)
Expand All @@ -43,7 +43,7 @@ export default async function onProxyRequest(
!passportHostRegex.test(documentHost) && // Passport requests have a `passport.twitch.tv` document URL.
!twitchTvHostRegex.test(documentHost)
) {
return { type: "direct" };
return { type: "DIRECT" };
}

const proxies = store.state.optimizedProxiesEnabled
Expand Down Expand Up @@ -92,12 +92,12 @@ export default async function onProxyRequest(
if (proxyUsherRequest && usherHostRegex.test(host)) {
if (details.url.includes("/vod/")) {
console.log(`✋ '${details.url}' is a VOD manifest.`);
return { type: "direct" };
return { type: "DIRECT" };
}
const channelName = findChannelFromUsherUrl(details.url);
if (isChannelWhitelisted(channelName)) {
console.log(`✋ Channel '${channelName}' is whitelisted.`);
return { type: "direct" };
return { type: "DIRECT" };
}
console.log(
`⌛ Proxying ${details.url} (${
Expand All @@ -119,7 +119,7 @@ export default async function onProxyRequest(
findChannelFromTwitchTvUrl(tabUrl);
if (isChannelWhitelisted(channelName)) {
console.log(`✋ Channel '${channelName}' is whitelisted.`);
return { type: "direct" };
return { type: "DIRECT" };
}
console.log(
`⌛ Proxying ${details.url} (${
Expand Down Expand Up @@ -149,12 +149,12 @@ export default async function onProxyRequest(
return proxyInfoArray;
}

return { type: "direct" };
return { type: "DIRECT" };
}

function getProxyInfoArrayFromUrls(urls: string[]): ProxyInfo[] {
return [
...urls.map(getProxyInfoFromUrl),
{ type: "direct" } as ProxyInfo, // Fallback to direct connection if all proxies fail.
{ type: "DIRECT" } as ProxyInfo, // Fallback to direct connection if all proxies fail.
];
}
2 changes: 1 addition & 1 deletion src/background/handlers/onResponseStarted.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ function getProxyFromDetails(
return getUrlFromProxyInfo(possibleProxies[0]);
} else {
const proxyInfo = details.proxyInfo; // Firefox only.
if (!proxyInfo || proxyInfo.type === "direct") return null;
if (!proxyInfo || proxyInfo.type === "DIRECT") return null;
return getUrlFromProxyInfo(proxyInfo);
}
}
42 changes: 37 additions & 5 deletions src/common/ts/proxyInfo.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,36 @@
import { Address6 } from "ip-address";
import type { ProxyInfo } from "../../types";

export function getProxyInfoFromUrl(
url: string
): ProxyInfo & { type: "http"; host: string; port: number } {
export const proxySchemes = {
direct: "DIRECT",
http: "PROXY",
https: "HTTPS",
socks: "SOCKS",
socks4: "SOCKS4",
socks5: "SOCKS5",
quic: "QUIC",
} as const;

type Protocol = keyof typeof proxySchemes;

const defaultPorts: Partial<{
[key in keyof typeof proxySchemes]: number;
}> = {
http: 80,
https: 443,
socks: 1080,
socks4: 1080,
socks5: 1080,
quic: 443,
};

export function getProxyInfoFromUrl(url: string) {
let protocol = "";
if (url.includes("://")) {
const [_protocol, urlWithoutProtocol] = url.split("://");
protocol = _protocol;
url = urlWithoutProtocol;
}
const lastIndexOfAt = url.lastIndexOf("@");
const hostname = url.substring(lastIndexOfAt + 1, url.length);
const lastIndexOfColon = getLastIndexOfColon(hostname);
Expand All @@ -12,7 +39,9 @@ export function getProxyInfoFromUrl(
let port: number | undefined = undefined;
if (lastIndexOfColon === -1) {
host = hostname;
port = 3128; // Default port
if (!protocol) {
port = 3128; // Default port
}
} else {
host = hostname.substring(0, lastIndexOfColon);
port = Number(hostname.substring(lastIndexOfColon + 1, hostname.length));
Expand All @@ -30,8 +59,11 @@ export function getProxyInfoFromUrl(
password = credentials.substring(indexOfColon + 1, credentials.length);
}

port = port ? port : defaultPorts[protocol as Protocol];

return {
type: "http",
type: proxySchemes[protocol as Protocol] ?? "PROXY",
protocol,
host,
port,
username,
Expand Down
2 changes: 1 addition & 1 deletion src/common/ts/proxySettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ function getProxyInfoStringFromUrls(urls: string[]): string {
return [
...urls.map(url => {
const proxyInfo = getProxyInfoFromUrl(url);
return `PROXY ${getUrlFromProxyInfo({
return `${proxyInfo.type} ${getUrlFromProxyInfo({
...proxyInfo,
// Don't include username/password in PAC script.
username: undefined,
Expand Down
12 changes: 8 additions & 4 deletions src/options/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,12 +336,16 @@ function isOptimizedProxyUrlAllowed(url: string): AllowedResult {
return [false, "TTV LOL PRO v1 proxies are not compatible"];
}

if (/^https?:\/\//i.test(url)) {
return [false, "Proxy URLs must not contain a protocol (e.g. 'http://')"];
const proxyInfo = getProxyInfoFromUrl(url);
if (proxyInfo.host.includes("/")) {
return [false, "Proxy URLs must not contain a path (e.g. '/path')"];
}

if (url.includes("/")) {
return [false, "Proxy URLs must not contain a path (e.g. '/path')"];
try {
const host = url.substring(url.lastIndexOf("@") + 1, url.length);
new URL(`http://${host}`); // Throws if the host is invalid.
} catch {
return [false, `'${url}' is not a valid proxy URL`];
}

try {
Expand Down
12 changes: 11 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,19 @@ export type KeyOfType<T, V> = keyof {
[P in keyof T as T[P] extends V ? P : never]: any;
};

// From https://chromium.googlesource.com/chromium/src/+/HEAD/net/docs/proxy.md#proxy-server-schemes
export type ProxyScheme =
| "DIRECT"
| "PROXY"
| "HTTPS"
| "SOCKS"
| "SOCKS4"
| "SOCKS5"
| "QUIC";

// From https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/proxy/ProxyInfo
export interface ProxyInfo {
type: "direct" | "http" | "https" | "socks" | "socks4";
type: ProxyScheme;
host?: string;
port?: number;
username?: string;
Expand Down

0 comments on commit c638fdf

Please sign in to comment.