From 96da928aae2d8654b49b70c515f81840b62246f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=84=B1=ED=9B=88=20/=20Koder?= Date: Mon, 3 Feb 2025 04:12:41 +0900 Subject: [PATCH 1/7] feat: add custom hosts option --- src/options.html | 15 +++++++++++++++ src/options.ts | 20 ++++++++++++++++++++ src/utils/config.ts | 2 ++ 3 files changed, 37 insertions(+) diff --git a/src/options.html b/src/options.html index 626d4e83..3bee176d 100644 --- a/src/options.html +++ b/src/options.html @@ -57,6 +57,21 @@

Custom tools

+ + +
+ + + + + +

Specify custom hostnames to send the parsed data to, separated by commas.

+

Each hostname must not contain https:// or http://

+ +
+
diff --git a/src/options.ts b/src/options.ts index 46fd4dda..76d021f7 100644 --- a/src/options.ts +++ b/src/options.ts @@ -1,6 +1,7 @@ import { config } from './utils/config'; import { noop } from './utils/noop'; +const customHostsInput = document.querySelector('#custom-hosts'); const customPortsInput = document.querySelector('#custom-ports'); const customRulesContainer = document.querySelector('#custom-rules-container'); const requestTimeoutInput = document.querySelector('#request-timeout'); @@ -97,6 +98,25 @@ function addCustomRulesRow(regex?: string, parserName?: string): void { customRulesContainer.appendChild(row); } +customHostsInput.addEventListener('input', function (): void { + const hosts = this.value + .split(',') + .map(x => x.trim()) + .filter(x => x.length > 0); + + const uniqueHosts = [...new Set(hosts)]; + + const errorElem = document.querySelector('#custom-hosts-error'); + + if (uniqueHosts.some(x => x.includes('https://') || x.includes('http://'))) { + errorElem.classList.remove('hidden'); + } else { + errorElem.classList.add('hidden'); + + config.set('customHosts', uniqueHosts).then(noop).catch(noop); + } +}); + customPortsInput.addEventListener('input', function (): void { const ports = this.value .split(',') diff --git a/src/utils/config.ts b/src/utils/config.ts index f16f6869..ebfecefd 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -1,6 +1,7 @@ import { browser } from './browser'; interface ConfigItems { + customHosts: string[]; customPorts: number[]; customRules: [string, string][]; requestTimeout: number; @@ -9,6 +10,7 @@ interface ConfigItems { class Config { private readonly defaults: Partial = { + customHosts: [], customPorts: [], customRules: [], requestTimeout: 500, From aed9858cbaca28cf2ff49bd9cd22f5a9f25933bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=84=B1=ED=9B=88=20/=20Koder?= Date: Mon, 3 Feb 2025 04:13:47 +0900 Subject: [PATCH 2/7] fix: error displays on false situation --- src/options.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/options.ts b/src/options.ts index 76d021f7..5ad95df1 100644 --- a/src/options.ts +++ b/src/options.ts @@ -129,9 +129,9 @@ customPortsInput.addEventListener('input', function (): void { const errorElem = document.querySelector('#custom-ports-error'); if (uniquePorts.some(isNaN) || uniquePorts.some(x => x < 0)) { - errorElem.classList.add('hidden'); - } else { errorElem.classList.remove('hidden'); + } else { + errorElem.classList.add('hidden'); config.set('customPorts', uniquePorts).then(noop).catch(noop); } From adcdec08ee253832daa991764a7b6dfe3d31c191 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=84=B1=ED=9B=88=20/=20Koder?= Date: Mon, 3 Feb 2025 04:52:58 +0900 Subject: [PATCH 3/7] feat: custom hosts --- src/hosts/CustomHost.ts | 7 +++++-- src/hosts/Host.ts | 1 + src/hosts/hosts.ts | 14 +++++++++++++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/hosts/CustomHost.ts b/src/hosts/CustomHost.ts index a1b3ab38..fb2e45d6 100644 --- a/src/hosts/CustomHost.ts +++ b/src/hosts/CustomHost.ts @@ -1,12 +1,15 @@ import { Host } from './Host'; export class CustomHost extends Host { - public constructor(private port: number) { + public constructor( + private hostname: string, + private port: number, + ) { super(); } public async send(data: string): Promise { - await this.doSend(`http://localhost:${this.port}/`, { + await this.doSend(`http://${this.hostname}:${this.port}/`, { body: data, headers: { 'Content-Type': 'application/json', diff --git a/src/hosts/Host.ts b/src/hosts/Host.ts index 537b9efa..9e77e0f2 100644 --- a/src/hosts/Host.ts +++ b/src/hosts/Host.ts @@ -13,6 +13,7 @@ export abstract class Host { await fetch(url, { method: 'POST', signal: abortController.signal, + mode: 'no-cors', ...options, }); } catch (err) { diff --git a/src/hosts/hosts.ts b/src/hosts/hosts.ts index d2d77632..7cfc2340 100644 --- a/src/hosts/hosts.ts +++ b/src/hosts/hosts.ts @@ -4,6 +4,7 @@ import { CustomHost } from './CustomHost'; import { Host } from './Host'; const defaultHosts: Host[] = [new CHelperHost()]; +const defaultHostnames = ['localhost']; const defaultPorts = [ 1327, // cpbooster 4244, // Hightail @@ -15,7 +16,18 @@ const defaultPorts = [ ]; export async function getHosts(): Promise { + const customHostnames = await config.get('customHosts'); + const uniqueHostnames = [...new Set(defaultHostnames.concat(customHostnames))]; + const customPorts = await config.get('customPorts'); const uniquePorts = [...new Set(defaultPorts.concat(customPorts))]; - return defaultHosts.concat(uniquePorts.map(port => new CustomHost(port))); + + const hosts: CustomHost[] = []; + uniqueHostnames.map(hostname => { + uniquePorts.map(port => { + hosts.push(new CustomHost(hostname, port)); + }); + }); + + return defaultHosts.concat(hosts); } From 3cae316bd7a2bbb21d3e06d5255e981f3ad83d7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=84=B1=ED=9B=88=20/=20Koder?= Date: Mon, 3 Feb 2025 05:14:40 +0900 Subject: [PATCH 4/7] fix: fill custom value when page loaded --- src/options.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/options.ts b/src/options.ts index 5ad95df1..8b046808 100644 --- a/src/options.ts +++ b/src/options.ts @@ -7,6 +7,21 @@ const customRulesContainer = document.querySelector('#custom-rul const requestTimeoutInput = document.querySelector('#request-timeout'); const debugModeInput = document.querySelector('#debug-mode'); +async function fillCustomValues(): Promise { + const customHosts = await config.get('customHosts'); + const customPorts = await config.get('customPorts'); + const customRules = await config.get('customRules'); + + customHostsInput.value = customHosts.join(','); + customPortsInput.value = customPorts.join(','); + customRulesContainer.innerHTML = ''; + for (const rule of customRules) { + addCustomRulesRow(rule[0], rule[1]); + } + addCustomRulesRow(); +} +window.addEventListener('load', fillCustomValues); + function updateCustomRules(): void { const rows = customRulesContainer.querySelectorAll('.custom-rules-row'); const rules: [string, string][] = []; From 8fefcc2407b3f3b0fc2cbb918ac427d1ca7ac0c0 Mon Sep 17 00:00:00 2001 From: Jasper van Merle Date: Tue, 11 Feb 2025 20:03:08 +0100 Subject: [PATCH 5/7] Fix style issues --- src/options.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/options.html b/src/options.html index 3bee176d..ab7f2765 100644 --- a/src/options.html +++ b/src/options.html @@ -58,18 +58,18 @@

Custom tools

- +
- + - + - +

Specify custom hostnames to send the parsed data to, separated by commas.

Each hostname must not contain https:// or http://

- +
From 6abb465657b1ccb008f2e270688fef3d8c608b7a Mon Sep 17 00:00:00 2001 From: Jasper van Merle Date: Tue, 11 Feb 2025 20:48:12 +0100 Subject: [PATCH 6/7] Add host vs. hostname consistency --- src/hosts/CustomHost.ts | 4 ++-- src/hosts/hosts.ts | 15 +++++++-------- src/options.html | 8 +++++--- src/options.ts | 33 ++++++++++++++++++--------------- 4 files changed, 32 insertions(+), 28 deletions(-) diff --git a/src/hosts/CustomHost.ts b/src/hosts/CustomHost.ts index fb2e45d6..d02421fb 100644 --- a/src/hosts/CustomHost.ts +++ b/src/hosts/CustomHost.ts @@ -2,14 +2,14 @@ import { Host } from './Host'; export class CustomHost extends Host { public constructor( - private hostname: string, + private host: string, private port: number, ) { super(); } public async send(data: string): Promise { - await this.doSend(`http://${this.hostname}:${this.port}/`, { + await this.doSend(`http://${this.host}:${this.port}/`, { body: data, headers: { 'Content-Type': 'application/json', diff --git a/src/hosts/hosts.ts b/src/hosts/hosts.ts index 7cfc2340..834dc4dd 100644 --- a/src/hosts/hosts.ts +++ b/src/hosts/hosts.ts @@ -3,8 +3,7 @@ import { CHelperHost } from './CHelperHost'; import { CustomHost } from './CustomHost'; import { Host } from './Host'; -const defaultHosts: Host[] = [new CHelperHost()]; -const defaultHostnames = ['localhost']; +const defaultHosts = ['localhost']; const defaultPorts = [ 1327, // cpbooster 4244, // Hightail @@ -16,18 +15,18 @@ const defaultPorts = [ ]; export async function getHosts(): Promise { - const customHostnames = await config.get('customHosts'); - const uniqueHostnames = [...new Set(defaultHostnames.concat(customHostnames))]; + const customHosts = await config.get('customHosts'); + const uniqueHosts = [...new Set(defaultHosts.concat(customHosts))]; const customPorts = await config.get('customPorts'); const uniquePorts = [...new Set(defaultPorts.concat(customPorts))]; - const hosts: CustomHost[] = []; - uniqueHostnames.map(hostname => { + const hosts: Host[] = [new CHelperHost()]; + uniqueHosts.map(host => { uniquePorts.map(port => { - hosts.push(new CustomHost(hostname, port)); + hosts.push(new CustomHost(host, port)); }); }); - return defaultHosts.concat(hosts); + return hosts; } diff --git a/src/options.html b/src/options.html index ab7f2765..9e6f6e22 100644 --- a/src/options.html +++ b/src/options.html @@ -61,14 +61,16 @@

Custom tools


- + -

Specify custom hostnames to send the parsed data to, separated by commas.

-

Each hostname must not contain https:// or http://

+

+ Specify custom hosts to send the parsed data to, separated by commas. Each host must not contain https:// or + http://. +


diff --git a/src/options.ts b/src/options.ts index 8b046808..1db319f5 100644 --- a/src/options.ts +++ b/src/options.ts @@ -7,21 +7,6 @@ const customRulesContainer = document.querySelector('#custom-rul const requestTimeoutInput = document.querySelector('#request-timeout'); const debugModeInput = document.querySelector('#debug-mode'); -async function fillCustomValues(): Promise { - const customHosts = await config.get('customHosts'); - const customPorts = await config.get('customPorts'); - const customRules = await config.get('customRules'); - - customHostsInput.value = customHosts.join(','); - customPortsInput.value = customPorts.join(','); - customRulesContainer.innerHTML = ''; - for (const rule of customRules) { - addCustomRulesRow(rule[0], rule[1]); - } - addCustomRulesRow(); -} -window.addEventListener('load', fillCustomValues); - function updateCustomRules(): void { const rows = customRulesContainer.querySelectorAll('.custom-rules-row'); const rules: [string, string][] = []; @@ -113,6 +98,24 @@ function addCustomRulesRow(regex?: string, parserName?: string): void { customRulesContainer.appendChild(row); } +async function fillCustomValues(): Promise { + const customHosts = await config.get('customHosts'); + const customPorts = await config.get('customPorts'); + const customRules = await config.get('customRules'); + + customHostsInput.value = customHosts.join(','); + customPortsInput.value = customPorts.join(','); + customRulesContainer.innerHTML = ''; + + for (const rule of customRules) { + addCustomRulesRow(rule[0], rule[1]); + } + + addCustomRulesRow(); +} + +window.addEventListener('load', fillCustomValues); + customHostsInput.addEventListener('input', function (): void { const hosts = this.value .split(',') From c3e5db2c775026b51ae76fd39d08057d7989d560 Mon Sep 17 00:00:00 2001 From: Jasper van Merle Date: Tue, 11 Feb 2025 21:09:14 +0100 Subject: [PATCH 7/7] Remove localhost permission --- scripts/build/extension.ts | 1 - src/background.ts | 13 +------------ 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/scripts/build/extension.ts b/scripts/build/extension.ts index fca82362..fa0e8030 100644 --- a/scripts/build/extension.ts +++ b/scripts/build/extension.ts @@ -32,7 +32,6 @@ await Promise.all( homepage_url: packageJson.repository, permissions: ['activeTab', 'contextMenus', 'storage', 'scripting'], - host_permissions: ['http://localhost/'], icons: { '16': 'icons/icon-16.png', diff --git a/src/background.ts b/src/background.ts index 2d03190e..e7691c64 100644 --- a/src/background.ts +++ b/src/background.ts @@ -44,8 +44,7 @@ function createContextMenu(): void { } async function loadContentScript(tab: Tabs.Tab, parserName: string): Promise { - const permissionOrigins: string[] = ['http://localhost/']; - + const permissionOrigins: string[] = []; for (const prefix in requiredPermissions) { if (tab.url.startsWith(prefix)) { permissionOrigins.push(requiredPermissions[prefix]); @@ -78,16 +77,6 @@ function onContextMenu(info: Menus.OnClickData, tab: Tabs.Tab): void { } async function sendTask(tabId: number, messageId: string, data: string): Promise { - const permissionGranted = await browser.permissions.contains({ origins: ['http://localhost/'] }); - if (!permissionGranted) { - sendToContent(tabId, MessageAction.SendTaskFailed, { - messageId, - message: 'Competitive Companion does not have permission to send problems to localhost', - }); - - return; - } - try { const hosts = await getHosts();