From 036a47d33a9e34d7e8842fadaed2f797b81d180c Mon Sep 17 00:00:00 2001 From: Lesley Norton Date: Tue, 26 Nov 2024 17:19:32 -0800 Subject: [PATCH] FXVPN-190: Set proxy settings to domains, not subdomains (#83) This PR changes `Utils.getFormattedHostname` to `Utils.getDomainName`. Instead of returning a formatted hostname, the function now takes in a url and returns the domain name. The net net of this change is that we now set proxy settings at the domain level instead of the subdomain level. - FXVPN-190, FXVPN-183 --- src/background/requestHandler.js | 2 +- src/background/tabHandler.js | 2 +- src/background/tabReloader.js | 2 +- src/shared/utils.js | 47 +++++++++++++++++++--------- src/ui/browserAction/popupPage.js | 8 +++-- src/ui/pageAction/pageAction.js | 2 +- tests/jest/background/utils.test.mjs | 8 ++--- 7 files changed, 46 insertions(+), 25 deletions(-) diff --git a/src/background/requestHandler.js b/src/background/requestHandler.js index 25d42932..a36243fe 100644 --- a/src/background/requestHandler.js +++ b/src/background/requestHandler.js @@ -145,7 +145,7 @@ export class RequestHandler extends Component { for (let urlString of [documentUrl, url]) { if (urlString) { - const parsedHostname = Utils.getFormattedHostname(urlString); + const parsedHostname = Utils.getTopLevelDomain(urlString); const proxyInfo = self.proxyMap.get(parsedHostname); if (proxyInfo) { return proxyInfo; diff --git a/src/background/tabHandler.js b/src/background/tabHandler.js index 1c2e1571..019ce488 100644 --- a/src/background/tabHandler.js +++ b/src/background/tabHandler.js @@ -84,7 +84,7 @@ export class TabHandler extends Component { return browser.pageAction.hide(currentTab.id); } - this.currentHostname = await Utils.getFormattedHostname(currentTab.url); + this.currentHostname = await Utils.getTopLevelDomain(currentTab.url); this.currentContext = this.siteContexts.get(this.currentHostname); if (this.currentContext && this.currentContext.excluded) { diff --git a/src/background/tabReloader.js b/src/background/tabReloader.js index 4b6750cf..b2648009 100644 --- a/src/background/tabReloader.js +++ b/src/background/tabReloader.js @@ -85,7 +85,7 @@ export class TabReloader extends Component { if (hostname === "") { return false; } - const tabURL = Utils.getFormattedHostname(tab.url); + const tabURL = Utils.getTopLevelDomain(tab.url); return tabURL === hostname; }; } diff --git a/src/shared/utils.js b/src/shared/utils.js index 4b1a149e..9940b161 100644 --- a/src/shared/utils.js +++ b/src/shared/utils.js @@ -29,35 +29,51 @@ export const Utils = { /** * Formats and retrieves the hostname from a given URL. - * @param {string} url - The URL to format. - * @returns {string} - The formatted hostname. Is empty if not valid for extension context. + * @param {string} url - URL to format. + * @returns {string} - URL sans prefixes. */ - getFormattedHostname(url) { + stripPrefixesFromUrl(url) { // Handle sites being viewed in reader mode // TODO... other prefixes(?) const readerPrefix = "about:reader?url="; if (url.startsWith(readerPrefix)) { const encodedUrl = url.slice(readerPrefix.length); - url = decodeURIComponent(encodedUrl); + return decodeURIComponent(encodedUrl); } - const getHostname = (aUrl) => { - try { - const urlObj = new URL(aUrl); - return urlObj.hostname; - } catch (e) { - return null; + return url; + }, + + /** + * Formats and retrieves the domain from a given URL. + * @param {string} url - URL from which to retrieve the domain name. + * @returns {string} - The domain name, or the url if a valid (within the context of the extension) domain name is not derived. + */ + getTopLevelDomain(url) { + url = this.stripPrefixesFromUrl(url); + + try { + // Create a URL object from the input URL + let parsedUrl = new URL(url); + + // Split the hostname to remove any subdomains or prefixes + let domainParts = parsedUrl.hostname.split("."); + + // If the domain has more than two parts, remove subdomains (e.g., "reader.example.com" becomes "example.com") + if (domainParts.length > 2) { + return domainParts.slice(-2).join("."); } - }; - let hostname = getHostname(url); - // Use the entire URL if hostname is not valid (like about:debugging) - if (!hostname || hostname === "") { + // If it's already just a domain name, return it + return parsedUrl.hostname ? parsedUrl.hostname : url; + } catch (error) { + // Handle invalid URLs return url; } - return hostname; }, isValidForProxySetting: (url) => { + url = Utils.stripPrefixesFromUrl(url); + try { const urlObj = new URL(url); return urlObj.protocol === "https:" || urlObj.protocol === "http:"; @@ -65,6 +81,7 @@ export const Utils = { return false; } }, + nameFor: (countryCode = "", cityCode = "", serverList = []) => { return Utils.getCity(countryCode, cityCode, serverList)?.name; }, diff --git a/src/ui/browserAction/popupPage.js b/src/ui/browserAction/popupPage.js index ea6eaf34..c01d1978 100644 --- a/src/ui/browserAction/popupPage.js +++ b/src/ui/browserAction/popupPage.js @@ -87,7 +87,7 @@ export class BrowserActionPopup extends LitElement { this.hasSiteContext = false; return; } - const hostname = Utils.getFormattedHostname(tab.url); + const hostname = Utils.getTopLevelDomain(tab.url); this.pageURL = hostname; if (this._siteContexts.has(this.pageURL)) { this._siteContext = proxyHandler.siteContexts.value.get(this.pageURL); @@ -219,7 +219,7 @@ export class BrowserActionPopup extends LitElement { return html`

${parts.at(0)} - ${origin} + ${origin} ${parts.at(-1)}

`; @@ -450,6 +450,10 @@ export class BrowserActionPopup extends LitElement { padding-block: 8px 16px !important; } + .origin.bold { + word-break: break-word; + max-width: 260px; + } h3 { margin-block: calc(var(--padding-default) / 2) 0px; } diff --git a/src/ui/pageAction/pageAction.js b/src/ui/pageAction/pageAction.js index c7c0e5ed..b1fe9e09 100644 --- a/src/ui/pageAction/pageAction.js +++ b/src/ui/pageAction/pageAction.js @@ -31,7 +31,7 @@ export class PageActionPopup extends LitElement { if (!Utils.isValidForProxySetting(tab.url)) { return; } - const hostname = Utils.getFormattedHostname(tab.url); + const hostname = Utils.getTopLevelDomain(tab.url); this.pageURL = hostname; if (proxyHandler.siteContexts.value.has(this.pageURL)) { this._siteContext = proxyHandler.siteContexts.value.get(this.pageURL); diff --git a/tests/jest/background/utils.test.mjs b/tests/jest/background/utils.test.mjs index b3e070f3..c054d5cb 100644 --- a/tests/jest/background/utils.test.mjs +++ b/tests/jest/background/utils.test.mjs @@ -29,19 +29,19 @@ describe("Utils", () => { mockSet.mockClear(); }); - describe("getFormattedHostName", () => { + describe("getTopLevelDomain", () => { test("Returns a formatted hostname when given a url", () => { - const result = Utils.getFormattedHostname("www.mozilla.org"); + const result = Utils.getTopLevelDomain("www.mozilla.org"); expect(result).toBe("www.mozilla.org"); }); test("Removes reader prefixes from the url", () => { - const result = Utils.getFormattedHostname( + const result = Utils.getTopLevelDomain( "about:reader?url=https://firefox.com" ); expect(result).toBe("firefox.com"); }); test("Returns the string if the string is not a valid url", () => { - const result = Utils.getFormattedHostname("about:debugging"); + const result = Utils.getTopLevelDomain("about:debugging"); expect(result).toBe("about:debugging"); }); });