diff --git a/add-on/src/lib/redirect-handler/blockOrObserve.ts b/add-on/src/lib/redirect-handler/blockOrObserve.ts index c87320183..dd450a2ac 100644 --- a/add-on/src/lib/redirect-handler/blockOrObserve.ts +++ b/add-on/src/lib/redirect-handler/blockOrObserve.ts @@ -26,6 +26,7 @@ interface regexFilterMap { interface redirectHandlerInput { originUrl: string redirectUrl: string + getPort: (state: CompanionState) => string } type messageToSelfType = typeof GLOBAL_STATE_CHANGE | typeof GLOBAL_STATE_OPTION_CHANGE | typeof DELETE_RULE_REQUEST @@ -34,6 +35,8 @@ interface messageToSelf { value?: string | Record } +const defaultNSRegexStr = `(${[...DEFAULT_NAMESPACES].join('|')})` + // We need to check if the browser supports the declarativeNetRequest API. // TODO: replace with check for `Blocking` in `chrome.webRequest.OnBeforeRequestOptions` // which is currently a bug https://bugs.chromium.org/p/chromium/issues/detail?id=1427952 @@ -80,11 +83,18 @@ const savedRegexFilters: Map = new Map() const DEFAULT_LOCAL_RULES: redirectHandlerInput[] = [ { originUrl: 'http://127.0.0.1', - redirectUrl: 'http://localhost' + redirectUrl: 'http://localhost', + getPort: ({ gwURLString }): string => new URL(gwURLString).port }, { originUrl: 'http://[::1]', - redirectUrl: 'http://localhost' + redirectUrl: 'http://localhost', + getPort: ({ gwURLString }): string => new URL(gwURLString).port + }, + { + originUrl: 'http://localhost', + redirectUrl: 'http://127.0.0.1', + getPort: ({ apiURL }): string => new URL(apiURL).port } ] @@ -163,7 +173,7 @@ function constructRegexFilter ({ originUrl, redirectUrl }: redirectHandlerInput) if (DEFAULT_NAMESPACES.has(subdomainPart as string)) { // We found a namespace, this is going to match group 2, i.e. namespace. // e.g https://bafybeib3bzis4mejzsnzsb65od3rnv5ffit7vsllratddjkgfgq4wiamqu.ipfs.dweb.link - regexFilter = `${commonStaticUrlStart}(.*?)\\.(${[...DEFAULT_NAMESPACES].join('|')})${commonStaticUrlEnd}` + regexFilter = `${commonStaticUrlStart}(.*?)\\.${defaultNSRegexStr}${commonStaticUrlEnd}` regexSubstitution = redirectUrl .replace(subdomain.reverse().join('.'), '\\1') // replace subdomain or CID. @@ -203,7 +213,6 @@ function constructRegexFilter ({ originUrl, redirectUrl }: redirectHandlerInput) // A redirect like // https://ipfs.io/ipfs/QmZMxU -> http://localhost:8080/ipfs/QmZMxU const [originFirst, originLast] = originUrl.split(`/${originNS}/`) - const defaultNSRegexStr = `(${[...DEFAULT_NAMESPACES].join('|')})` regexFilter = `^${escapeURLRegex(originFirst)}\\/${defaultNSRegexStr}\\/${RULE_REGEX_ENDING}` .replace(/https?/ig, 'https?') regexSubstitution = redirectUrl @@ -338,11 +347,11 @@ async function reconcileRulesAndRemoveOld (state: CompanionState): Promise } } - const { port } = new URL(state.gwURLString) // make sure that the default rules are added. - for (const { originUrl, redirectUrl } of DEFAULT_LOCAL_RULES) { - const regexFilter = `^${escapeURLRegex(`${originUrl}:${port}`)}${RULE_REGEX_ENDING}` - const regexSubstitution = `${redirectUrl}:${port}/\\1` + for (const { originUrl, redirectUrl, getPort } of DEFAULT_LOCAL_RULES) { + const port = getPort(state) + const regexFilter = `^${escapeURLRegex(`${originUrl}:${port}`)}\\/${defaultNSRegexStr}\\/${RULE_REGEX_ENDING}` + const regexSubstitution = `${redirectUrl}:${port}/\\1/\\2` if (!savedRegexFilters.has(regexFilter)) { // We need to add the new rule. diff --git a/test/functional/lib/redirect-handler/blockOrObserve.test.ts b/test/functional/lib/redirect-handler/blockOrObserve.test.ts index 6a4863468..455fc5bc2 100644 --- a/test/functional/lib/redirect-handler/blockOrObserve.test.ts +++ b/test/functional/lib/redirect-handler/blockOrObserve.test.ts @@ -49,12 +49,14 @@ function ensureTabRedirected (url): void { * @param regexSubstitution */ function ensureDeclrativeNetRequetRuleIsAdded ({ + addRuleIndex = 0, addRuleLength = 1, callIndex = 0, expectedCondition, regexSubstitution, removedRulesIds = [], }: { + addRuleIndex?: number addRuleLength?: number callIndex?: number expectedCondition: string @@ -69,7 +71,7 @@ function ensureDeclrativeNetRequetRuleIsAdded ({ expect(removeRuleIds).to.deep.equal(removedRulesIds) if (addRuleLength > 0) { expect(addRules).to.have.lengthOf(addRuleLength) - const [{ id, priority, action, condition }] = addRules + const { id, priority, action, condition } = addRules[addRuleIndex] expect(id).to.be.a('number') expect(priority).to.equal(1) expect(action).to.deep.equal({ type: 'redirect', redirect: { regexSubstitution } }) @@ -137,6 +139,37 @@ describe('lib/redirect-handler/blockOrObserve', () => { expect (browserMock.tabs.query.called).to.be.false }) + it('Should add default rules for localhost', async () => { + await addRuleToDynamicRuleSet({ + originUrl: 'https://ipfs.io/ipns/en.wikipedia-on-ipfs.org', + redirectUrl: 'http://localhost:8080/ipns/en.wikipedia-on-ipfs.org' + }) + + ensureDeclrativeNetRequetRuleIsAdded({ + addRuleIndex: 0, + addRuleLength: 3, + callIndex: 1, + expectedCondition: `^http\\:\\/\\/127\\.0\\.0\\.1\\:8080\\/(ipfs|ipns)\\/${RULE_REGEX_ENDING}`, + regexSubstitution: 'http://localhost:8080/\\1/\\2' + }) + + ensureDeclrativeNetRequetRuleIsAdded({ + addRuleIndex: 1, + addRuleLength: 3, + callIndex: 1, + expectedCondition: `^http\\:\\/\\/\\[\\:\\:1\\]\\:8080\\/(ipfs|ipns)\\/${RULE_REGEX_ENDING}`, + regexSubstitution: 'http://localhost:8080/\\1/\\2' + }) + + ensureDeclrativeNetRequetRuleIsAdded({ + addRuleIndex: 2, + addRuleLength: 3, + callIndex: 1, + expectedCondition: `^http\\:\\/\\/localhost\\:5001\\/(ipfs|ipns)\\/${RULE_REGEX_ENDING}`, + regexSubstitution: 'http://127.0.0.1:5001/\\1/\\2' + }) + }) + it('Should allow pages to be recovered', async () => { // when redirecting to recovery page await addRuleToDynamicRuleSet({