diff --git a/src/background/handlers/onBeforeVideoWeaverRequest.ts b/src/background/handlers/onBeforeVideoWeaverRequest.ts index 9eba3c7..deec2f2 100644 --- a/src/background/handlers/onBeforeVideoWeaverRequest.ts +++ b/src/background/handlers/onBeforeVideoWeaverRequest.ts @@ -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; diff --git a/src/background/handlers/onResponseStarted.ts b/src/background/handlers/onResponseStarted.ts index a02b436..e188386 100644 --- a/src/background/handlers/onResponseStarted.ts +++ b/src/background/handlers/onResponseStarted.ts @@ -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); } } diff --git a/src/common/ts/proxyInfo.ts b/src/common/ts/proxyInfo.ts index a053a22..9b06313 100644 --- a/src/common/ts/proxyInfo.ts +++ b/src/common/ts/proxyInfo.ts @@ -1,18 +1,34 @@ import { Address6 } from "ip-address"; -import type { ProxyInfo } from "../../types"; +import type { ProxyInfo, ProxyScheme } from "../../types"; -export function getProxyInfoFromUrl( - url: string -): ProxyInfo & { type: "http"; host: string; port: number } { +export const proxySchemes: { [key: string]: ProxyScheme } = { + direct: "DIRECT", + http: "PROXY", + https: "HTTPS", + socks: "SOCKS", + socks4: "SOCKS4", + socks5: "SOCKS5", + quic: "QUIC", +}; + +export function getProxyInfoFromUrl(url: string) { + let protocol = ""; + if (url.includes("://")) { + let [proto, urlWithoutProtocol] = url.split("://"); + protocol = proto; + url = urlWithoutProtocol; + } const lastIndexOfAt = url.lastIndexOf("@"); - const hostname = url.substring(lastIndexOfAt + 1, url.length); + let hostname = url.substring(lastIndexOfAt + 1, url.length); const lastIndexOfColon = getLastIndexOfColon(hostname); - + hostname; let host: string | undefined = undefined; 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)); @@ -31,7 +47,8 @@ export function getProxyInfoFromUrl( } return { - type: "http", + type: proxySchemes[protocol] ?? "PROXY", + protocol, host, port, username, diff --git a/src/common/ts/proxySettings.ts b/src/common/ts/proxySettings.ts index 2269791..d493f5f 100644 --- a/src/common/ts/proxySettings.ts +++ b/src/common/ts/proxySettings.ts @@ -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, diff --git a/src/options/options.ts b/src/options/options.ts index 078e0b4..640a648 100644 --- a/src/options/options.ts +++ b/src/options/options.ts @@ -16,10 +16,9 @@ import sendAdLog from "../common/ts/sendAdLog"; import store from "../store"; import getDefaultState from "../store/getDefaultState"; import type { State } from "../store/types"; -import { KeyOfType, ProxyRequestType } from "../types"; +import { AllowedResult, KeyOfType, ProxyRequestType } from "../types"; //#region Types -type AllowedResult = [boolean, string?]; type InsertMode = "append" | "prepend" | "both"; type StoreStringArrayKey = KeyOfType; type ListOptions = { @@ -323,12 +322,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 { diff --git a/src/types.ts b/src/types.ts index ca7d7a4..ce657e3 100644 --- a/src/types.ts +++ b/src/types.ts @@ -3,9 +3,21 @@ export type KeyOfType = keyof { [P in keyof T as T[P] extends V ? P : never]: any; }; +export type AllowedResult = [boolean, string?]; + +// 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;