mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-08 08:39:59 +00:00
Re-work whitelist feature to allow per-site UA configuration
This commit is contained in:
@@ -35,17 +35,43 @@ Missing/outdated strings:
|
||||
- `optionsMirroringCategoryDescription`
|
||||
- `optionsMirroringEnabled`
|
||||
- `optionsMirroringAppId`
|
||||
- `popupWhitelistNotWhitelisted`
|
||||
- `popupWhitelistAddToWhitelist`
|
||||
- `popupMediaTypeAppNotFound`
|
||||
- `optionsBridgeCompatible`
|
||||
- `optionsBridgeLikelyCompatible`
|
||||
- `optionsBridgeIncompatible`
|
||||
- `optionsSiteWhitelistCategoryName`
|
||||
- `optionsSiteWhitelistCategoryDescription`
|
||||
- `optionsSiteWhitelistEnabled`
|
||||
- `optionsSiteWhitelistEnabledDescription`
|
||||
- `optionsSiteWhitelistContent`
|
||||
- `optionsSiteWhitelistBasicView`
|
||||
- `optionsSiteWhitelistRawView`
|
||||
- `optionsSiteWhitelistSaveRaw`
|
||||
- `optionsSiteWhitelistAddItem`
|
||||
- `optionsSiteWhitelistUserAgent`
|
||||
- `optionsSiteWhitelistEditItem`
|
||||
- `optionsSiteWhitelistRemoveItem`
|
||||
- `optionsSiteWhitelistInvalidMatchPattern`
|
||||
- `popupWhitelistNotWhitelisted`
|
||||
- `popupWhitelistAddToWhitelist`
|
||||
- `popupMediaTypeAppNotFound`
|
||||
- `popupCastMenuTitle`
|
||||
- `popupStopMenuTitle`
|
||||
|
||||
- `es`
|
||||
|
||||
- `optionsSiteWhitelistCategoryName`
|
||||
- `optionsSiteWhitelistCategoryDescription`
|
||||
- `optionsSiteWhitelistEnabled`
|
||||
- `optionsSiteWhitelistEnabledDescription`
|
||||
- `optionsSiteWhitelistContent`
|
||||
- `optionsSiteWhitelistBasicView`
|
||||
- `optionsSiteWhitelistRawView`
|
||||
- `optionsSiteWhitelistSaveRaw`
|
||||
- `optionsSiteWhitelistAddItem`
|
||||
- `optionsSiteWhitelistUserAgent`
|
||||
- `optionsSiteWhitelistEditItem`
|
||||
- `optionsSiteWhitelistRemoveItem`
|
||||
- `optionsSiteWhitelistInvalidMatchPattern`
|
||||
- `popupWhitelistNotWhitelisted`
|
||||
- `popupWhitelistAddToWhitelist`
|
||||
- `popupCastMenuTitle`
|
||||
@@ -54,23 +80,47 @@ Missing/outdated strings:
|
||||
- `nl`
|
||||
|
||||
- `optionsBridgeBackupEnabled`
|
||||
- `optionsUserAgentWhitelistRestrictedEnabled`
|
||||
- `optionsUserAgentWhitelistRestrictedEnabledDescription`
|
||||
- `optionsBridgeCompatible`
|
||||
- `optionsBridgeLikelyCompatible`
|
||||
- `optionsBridgeIncompatible`
|
||||
- `optionsOptionRecommended`
|
||||
- `optionsMirroringCategoryName`
|
||||
- `optionsMirroringCategoryDescription`
|
||||
- `optionsMirroringEnabled`
|
||||
- `optionsMirroringAppId`
|
||||
- `optionsSiteWhitelistCategoryName`
|
||||
- `optionsSiteWhitelistCategoryDescription`
|
||||
- `optionsSiteWhitelistEnabled`
|
||||
- `optionsSiteWhitelistEnabledDescription`
|
||||
- `optionsSiteWhitelistContent`
|
||||
- `optionsSiteWhitelistBasicView`
|
||||
- `optionsSiteWhitelistRawView`
|
||||
- `optionsSiteWhitelistSaveRaw`
|
||||
- `optionsSiteWhitelistAddItem`
|
||||
- `optionsSiteWhitelistUserAgent`
|
||||
- `optionsSiteWhitelistEditItem`
|
||||
- `optionsSiteWhitelistRemoveItem`
|
||||
- `optionsSiteWhitelistInvalidMatchPattern`
|
||||
- `popupWhitelistNotWhitelisted`
|
||||
- `popupWhitelistAddToWhitelist`
|
||||
- `popupMediaTypeAppNotFound`
|
||||
- `optionsBridgeCompatible`
|
||||
- `optionsBridgeLikelyCompatible`
|
||||
- `optionsBridgeIncompatible`
|
||||
- `popupCastMenuTitle`
|
||||
- `popupStopMenuTitle`
|
||||
|
||||
- `no`
|
||||
- `optionsSiteWhitelistCategoryName`
|
||||
- `optionsSiteWhitelistCategoryDescription`
|
||||
- `optionsSiteWhitelistEnabled`
|
||||
- `optionsSiteWhitelistEnabledDescription`
|
||||
- `optionsSiteWhitelistContent`
|
||||
- `optionsSiteWhitelistBasicView`
|
||||
- `optionsSiteWhitelistRawView`
|
||||
- `optionsSiteWhitelistSaveRaw`
|
||||
- `optionsSiteWhitelistAddItem`
|
||||
- `optionsSiteWhitelistUserAgent`
|
||||
- `optionsSiteWhitelistEditItem`
|
||||
- `optionsSiteWhitelistRemoveItem`
|
||||
- `optionsSiteWhitelistInvalidMatchPattern`
|
||||
- `popupWhitelistNotWhitelisted`
|
||||
- `popupWhitelistAddToWhitelist`
|
||||
- `popupCastMenuTitle`
|
||||
|
||||
@@ -259,55 +259,55 @@
|
||||
"description": "Receiver selector close if focus lost option checkbox label."
|
||||
},
|
||||
|
||||
"optionsUserAgentWhitelistCategoryName": {
|
||||
"optionsSiteWhitelistCategoryName": {
|
||||
"message": "Useragent-Whitelist",
|
||||
"description": "Options page whitelist category title."
|
||||
},
|
||||
"optionsUserAgentWhitelistCategoryDescription": {
|
||||
"optionsSiteWhitelistCategoryDescription": {
|
||||
"message": "Seiten auf denen der Useragent aus Kompatibilitätsgründen mit einer Chrome-Version ersetzt wird. Suchmuster müssen gültig sein.",
|
||||
"description": "Options page whitelist category description."
|
||||
},
|
||||
"optionsUserAgentWhitelistEnabled": {
|
||||
"optionsSiteWhitelistEnabled": {
|
||||
"message": "Webseiten-Whitelist aktivieren",
|
||||
"description": "Whitelist enabled checkbox label."
|
||||
},
|
||||
"optionsUserAgentWhitelistRestrictedEnabled": {
|
||||
"optionsSiteWhitelistRestrictedEnabled": {
|
||||
"message": "Eingeschränkten Modus aktivieren",
|
||||
"description": "Whitelist restricted mode enabled checkbox label."
|
||||
},
|
||||
"optionsUserAgentWhitelistRestrictedEnabledDescription": {
|
||||
"optionsSiteWhitelistRestrictedEnabledDescription": {
|
||||
"message": "Whitelist-Einschränkungen auch auf Seiten anwenden, die unabhängig vom aktuellen Useragent versuchen Stream-Funktionen zu laden.",
|
||||
"description": "Whitelist restricted mode enabled description."
|
||||
},
|
||||
"optionsUserAgentWhitelistContent": {
|
||||
"optionsSiteWhitelistContent": {
|
||||
"message": "Suchmuster:",
|
||||
"description": "Match patterns editor widget label."
|
||||
},
|
||||
"optionsUserAgentWhitelistBasicView": {
|
||||
"optionsSiteWhitelistBasicView": {
|
||||
"message": "Einfache Ansicht",
|
||||
"description": "Switch to basic view button title."
|
||||
},
|
||||
"optionsUserAgentWhitelistRawView": {
|
||||
"optionsSiteWhitelistRawView": {
|
||||
"message": "Rohdatenansicht",
|
||||
"description": "Switch to raw view button title."
|
||||
},
|
||||
"optionsUserAgentWhitelistSaveRaw": {
|
||||
"optionsSiteWhitelistSaveRaw": {
|
||||
"message": "Rohdaten speichern",
|
||||
"description": "Save raw view edits button title."
|
||||
},
|
||||
"optionsUserAgentWhitelistAddItem": {
|
||||
"optionsSiteWhitelistAddItem": {
|
||||
"message": "Eintrag hinzufügen",
|
||||
"description": "Add new whitelist item button title."
|
||||
},
|
||||
"optionsUserAgentWhitelistEditItem": {
|
||||
"optionsSiteWhitelistEditItem": {
|
||||
"message": "Bearbeiten",
|
||||
"description": "Edit whitelist item button title. Displayed on each item."
|
||||
},
|
||||
"optionsUserAgentWhitelistRemoveItem": {
|
||||
"optionsSiteWhitelistRemoveItem": {
|
||||
"message": "Entfernen",
|
||||
"description": "Remove whitelist item button title. Displayed on each item."
|
||||
},
|
||||
"optionsUserAgentWhitelistInvalidMatchPattern": {
|
||||
"optionsSiteWhitelistInvalidMatchPattern": {
|
||||
"message": "Ungültiges Suchmuster $matchPattern$",
|
||||
"description": "Error displayed by input indicating an invalid match pattern.",
|
||||
"placeholders": {
|
||||
|
||||
@@ -302,55 +302,55 @@
|
||||
"description": "Receiver selector close if focus lost option checkbox label."
|
||||
},
|
||||
|
||||
"optionsUserAgentWhitelistCategoryName": {
|
||||
"message": "User agent whitelist",
|
||||
"optionsSiteWhitelistCategoryName": {
|
||||
"message": "Site whitelist",
|
||||
"description": "Options page whitelist category title."
|
||||
},
|
||||
"optionsUserAgentWhitelistCategoryDescription": {
|
||||
"message": "Sites for which to replace the user agent with a Chrome version for compatibility. Must be valid match patterns.",
|
||||
"optionsSiteWhitelistCategoryDescription": {
|
||||
"message": "Site where cast functionality will be enabled and the user agent string will be replaced with a Chrome version for compatibility.",
|
||||
"description": "Options page whitelist category description."
|
||||
},
|
||||
"optionsUserAgentWhitelistEnabled": {
|
||||
"optionsSiteWhitelistEnabled": {
|
||||
"message": "Enable site whitelist",
|
||||
"description": "Whitelist enabled checkbox label."
|
||||
},
|
||||
"optionsUserAgentWhitelistRestrictedEnabled": {
|
||||
"message": "Enable restricted mode",
|
||||
"description": "Whitelist restricted mode enabled checkbox label."
|
||||
},
|
||||
"optionsUserAgentWhitelistRestrictedEnabledDescription": {
|
||||
"message": "Also apply whitelist restrictions to sites attempting to load cast functionality regardless of the current user agent.",
|
||||
"optionsSiteWhitelistEnabledDescription": {
|
||||
"message": "Disabling this option will enable cast functionality on any site, but the user agent string will not be replaced.",
|
||||
"description": "Whitelist restricted mode enabled description."
|
||||
},
|
||||
"optionsUserAgentWhitelistContent": {
|
||||
"optionsSiteWhitelistContent": {
|
||||
"message": "Match patterns:",
|
||||
"description": "Match patterns editor widget label."
|
||||
},
|
||||
"optionsUserAgentWhitelistBasicView": {
|
||||
"optionsSiteWhitelistBasicView": {
|
||||
"message": "Basic View",
|
||||
"description": "Switch to basic view button title."
|
||||
},
|
||||
"optionsUserAgentWhitelistRawView": {
|
||||
"optionsSiteWhitelistRawView": {
|
||||
"message": "Raw View",
|
||||
"description": "Switch to raw view button title."
|
||||
},
|
||||
"optionsUserAgentWhitelistSaveRaw": {
|
||||
"optionsSiteWhitelistSaveRaw": {
|
||||
"message": "Save Raw",
|
||||
"description": "Save raw view edits button title."
|
||||
},
|
||||
"optionsUserAgentWhitelistAddItem": {
|
||||
"optionsSiteWhitelistAddItem": {
|
||||
"message": "Add Item",
|
||||
"description": "Add new whitelist item button title."
|
||||
},
|
||||
"optionsUserAgentWhitelistEditItem": {
|
||||
"optionsSiteWhitelistUserAgent": {
|
||||
"message": "Enable UA",
|
||||
"description": "Whitelist item user agent checkbox title."
|
||||
},
|
||||
"optionsSiteWhitelistEditItem": {
|
||||
"message": "Edit",
|
||||
"description": "Edit whitelist item button title. Displayed on each item."
|
||||
},
|
||||
"optionsUserAgentWhitelistRemoveItem": {
|
||||
"optionsSiteWhitelistRemoveItem": {
|
||||
"message": "Remove",
|
||||
"description": "Remove whitelist item button title. Displayed on each item."
|
||||
},
|
||||
"optionsUserAgentWhitelistInvalidMatchPattern": {
|
||||
"optionsSiteWhitelistInvalidMatchPattern": {
|
||||
"message": "Invalid match pattern $matchPattern$",
|
||||
"description": "Error displayed by input indicating an invalid match pattern.",
|
||||
"placeholders": {
|
||||
|
||||
@@ -275,55 +275,55 @@
|
||||
"description": "Receiver selector close if focus lost option checkbox label."
|
||||
},
|
||||
|
||||
"optionsUserAgentWhitelistCategoryName": {
|
||||
"optionsSiteWhitelistCategoryName": {
|
||||
"message": "Lista blanca de agentes de usuario",
|
||||
"description": "Options page whitelist category title."
|
||||
},
|
||||
"optionsUserAgentWhitelistCategoryDescription": {
|
||||
"optionsSiteWhitelistCategoryDescription": {
|
||||
"message": "Sitios en los cuales reemplazar el agente de usuario con una versión de Chrome para compatibilidad. Deben ser patrones de coincidencia válidos.",
|
||||
"description": "Options page whitelist category description."
|
||||
},
|
||||
"optionsUserAgentWhitelistEnabled": {
|
||||
"optionsSiteWhitelistEnabled": {
|
||||
"message": "Activar lista blanca de sitios",
|
||||
"description": "Whitelist enabled checkbox label."
|
||||
},
|
||||
"optionsUserAgentWhitelistRestrictedEnabled": {
|
||||
"optionsSiteWhitelistRestrictedEnabled": {
|
||||
"message": "Activar modo restringido",
|
||||
"description": "Whitelist restricted mode enabled checkbox label."
|
||||
},
|
||||
"optionsUserAgentWhitelistRestrictedEnabledDescription": {
|
||||
"optionsSiteWhitelistRestrictedEnabledDescription": {
|
||||
"message": "También aplica restricciones de la lista blanca a sitios intentando cargar la funcionalidad de transmisión sin importar el agente de usuario actual.",
|
||||
"description": "Whitelist restricted mode enabled description."
|
||||
},
|
||||
"optionsUserAgentWhitelistContent": {
|
||||
"optionsSiteWhitelistContent": {
|
||||
"message": "Patrones de coincidencia:",
|
||||
"description": "Match patterns editor widget label."
|
||||
},
|
||||
"optionsUserAgentWhitelistBasicView": {
|
||||
"optionsSiteWhitelistBasicView": {
|
||||
"message": "Vista básica",
|
||||
"description": "Switch to basic view button title."
|
||||
},
|
||||
"optionsUserAgentWhitelistRawView": {
|
||||
"optionsSiteWhitelistRawView": {
|
||||
"message": "Vista en bruto",
|
||||
"description": "Switch to raw view button title."
|
||||
},
|
||||
"optionsUserAgentWhitelistSaveRaw": {
|
||||
"optionsSiteWhitelistSaveRaw": {
|
||||
"message": "Guardar archivo en bruto",
|
||||
"description": "Save raw view edits button title."
|
||||
},
|
||||
"optionsUserAgentWhitelistAddItem": {
|
||||
"optionsSiteWhitelistAddItem": {
|
||||
"message": "Añadir elemento",
|
||||
"description": "Add new whitelist item button title."
|
||||
},
|
||||
"optionsUserAgentWhitelistEditItem": {
|
||||
"optionsSiteWhitelistEditItem": {
|
||||
"message": "Editar",
|
||||
"description": "Edit whitelist item button title. Displayed on each item."
|
||||
},
|
||||
"optionsUserAgentWhitelistRemoveItem": {
|
||||
"optionsSiteWhitelistRemoveItem": {
|
||||
"message": "Eliminar",
|
||||
"description": "Remove whitelist item button title. Displayed on each item."
|
||||
},
|
||||
"optionsUserAgentWhitelistInvalidMatchPattern": {
|
||||
"optionsSiteWhitelistInvalidMatchPattern": {
|
||||
"message": "Patrón de coincidencia $matchPattern$ inválido",
|
||||
"description": "Error displayed by input indicating an invalid match pattern.",
|
||||
"placeholders": {
|
||||
|
||||
@@ -243,47 +243,47 @@
|
||||
"message": "Sluit na het verliezen van de focus",
|
||||
"description": "Receiver selector close if focus lost option checkbox label."
|
||||
},
|
||||
"optionsUserAgentWhitelistCategoryName": {
|
||||
"optionsSiteWhitelistCategoryName": {
|
||||
"message": "Gebruikersagent - Whitelist",
|
||||
"description": "Options page whitelist category title."
|
||||
},
|
||||
"optionsUserAgentWhitelistCategoryDescription": {
|
||||
"optionsSiteWhitelistCategoryDescription": {
|
||||
"message": "Websites waarvan de gebruikersagent omwille van compatibiliteit moet worden ingesteld op Chrome. De patronen moeten geldig zijn.",
|
||||
"description": "Options page whitelist category description."
|
||||
},
|
||||
"optionsUserAgentWhitelistEnabled": {
|
||||
"optionsSiteWhitelistEnabled": {
|
||||
"message": "Whitelist ingeschakeld",
|
||||
"description": "Whitelist enabled checkbox label."
|
||||
},
|
||||
"optionsUserAgentWhitelistContent": {
|
||||
"optionsSiteWhitelistContent": {
|
||||
"message": "Patronen:",
|
||||
"description": "Match patterns editor widget label."
|
||||
},
|
||||
"optionsUserAgentWhitelistBasicView": {
|
||||
"optionsSiteWhitelistBasicView": {
|
||||
"message": "Basisweergave",
|
||||
"description": "Switch to basic view button title."
|
||||
},
|
||||
"optionsUserAgentWhitelistRawView": {
|
||||
"optionsSiteWhitelistRawView": {
|
||||
"message": "Ruwe weergave",
|
||||
"description": "Switch to raw view button title."
|
||||
},
|
||||
"optionsUserAgentWhitelistSaveRaw": {
|
||||
"optionsSiteWhitelistSaveRaw": {
|
||||
"message": "Ruwe weergave opslaan",
|
||||
"description": "Save raw view edits button title."
|
||||
},
|
||||
"optionsUserAgentWhitelistAddItem": {
|
||||
"optionsSiteWhitelistAddItem": {
|
||||
"message": "Voeg toe",
|
||||
"description": "Add new whitelist item button title."
|
||||
},
|
||||
"optionsUserAgentWhitelistEditItem": {
|
||||
"optionsSiteWhitelistEditItem": {
|
||||
"message": "Bewerken",
|
||||
"description": "Edit whitelist item button title. Displayed on each item."
|
||||
},
|
||||
"optionsUserAgentWhitelistRemoveItem": {
|
||||
"optionsSiteWhitelistRemoveItem": {
|
||||
"message": "Verwijderen",
|
||||
"description": "Remove whitelist item button title. Displayed on each item."
|
||||
},
|
||||
"optionsUserAgentWhitelistInvalidMatchPattern": {
|
||||
"optionsSiteWhitelistInvalidMatchPattern": {
|
||||
"message": "Ongeldig patroon $matchPattern$",
|
||||
"description": "Error displayed by input indicating an invalid match pattern.",
|
||||
"placeholders": {
|
||||
|
||||
@@ -263,55 +263,55 @@
|
||||
"description": "Receiver selector close if focus lost option checkbox label."
|
||||
},
|
||||
|
||||
"optionsUserAgentWhitelistCategoryName": {
|
||||
"optionsSiteWhitelistCategoryName": {
|
||||
"message": "Brukeragent whitelist",
|
||||
"description": "Options page whitelist category title."
|
||||
},
|
||||
"optionsUserAgentWhitelistCategoryDescription": {
|
||||
"optionsSiteWhitelistCategoryDescription": {
|
||||
"message": "Sider hvor man kan erstatte brukeragent med en Chrome-versjon for kompatibilitet. Må være et gjenkjennbart mønster.",
|
||||
"description": "Options page whitelist category description."
|
||||
},
|
||||
"optionsUserAgentWhitelistEnabled": {
|
||||
"optionsSiteWhitelistEnabled": {
|
||||
"message": "Skru på whitelist",
|
||||
"description": "Whitelist enabled checkbox label."
|
||||
},
|
||||
"optionsUserAgentWhitelistRestrictedEnabled": {
|
||||
"optionsSiteWhitelistRestrictedEnabled": {
|
||||
"message": "Skru på ",
|
||||
"description": "Whitelist restricted mode enabled checkbox label."
|
||||
},
|
||||
"optionsUserAgentWhitelistRestrictedEnabledDescription": {
|
||||
"optionsSiteWhitelistRestrictedEnabledDescription": {
|
||||
"message": "Legg også til whitelist-begrensninger til side smo prøvde å laste cast-funksjonalitet uavhengig av nåværende brukeragent.",
|
||||
"description": "Whitelist restricted mode enabled description."
|
||||
},
|
||||
"optionsUserAgentWhitelistContent": {
|
||||
"optionsSiteWhitelistContent": {
|
||||
"message": "Match mønster",
|
||||
"description": "Match patterns editor widget label."
|
||||
},
|
||||
"optionsUserAgentWhitelistBasicView": {
|
||||
"optionsSiteWhitelistBasicView": {
|
||||
"message": "Standard visning",
|
||||
"description": "Switch to basic view button title."
|
||||
},
|
||||
"optionsUserAgentWhitelistRawView": {
|
||||
"optionsSiteWhitelistRawView": {
|
||||
"message": "Rå visning",
|
||||
"description": "Switch to raw view button title."
|
||||
},
|
||||
"optionsUserAgentWhitelistSaveRaw": {
|
||||
"optionsSiteWhitelistSaveRaw": {
|
||||
"message": "Lagre rå",
|
||||
"description": "Save raw view edits button title."
|
||||
},
|
||||
"optionsUserAgentWhitelistAddItem": {
|
||||
"optionsSiteWhitelistAddItem": {
|
||||
"message": "Legg til",
|
||||
"description": "Add new whitelist item button title."
|
||||
},
|
||||
"optionsUserAgentWhitelistEditItem": {
|
||||
"optionsSiteWhitelistEditItem": {
|
||||
"message": "Rediger",
|
||||
"description": "Edit whitelist item button title. Displayed on each item."
|
||||
},
|
||||
"optionsUserAgentWhitelistRemoveItem": {
|
||||
"optionsSiteWhitelistRemoveItem": {
|
||||
"message": "Fjern",
|
||||
"description": "Remove whitelist item button title. Displayed on each item."
|
||||
},
|
||||
"optionsUserAgentWhitelistInvalidMatchPattern": {
|
||||
"optionsSiteWhitelistInvalidMatchPattern": {
|
||||
"message": "Ugyldig mønster $matchPattern$",
|
||||
"description": "Error displayed by input indicating an invalid match pattern.",
|
||||
"placeholders": {
|
||||
|
||||
@@ -137,11 +137,11 @@ async function onMenuClicked(
|
||||
);
|
||||
}
|
||||
|
||||
const whitelist = await options.get("userAgentWhitelist");
|
||||
if (!whitelist.includes(pattern)) {
|
||||
const whitelist = await options.get("siteWhitelist");
|
||||
if (!whitelist.find(item => item.pattern === pattern)) {
|
||||
// Add to whitelist and update options
|
||||
whitelist.push(pattern);
|
||||
await options.set("userAgentWhitelist", whitelist);
|
||||
whitelist.push({ pattern });
|
||||
await options.set("siteWhitelist", whitelist);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
@@ -22,6 +22,11 @@ type OnBeforeRequestDetails = Parameters<
|
||||
frameAncestors?: Array<{ url: string; frameId: number }>;
|
||||
};
|
||||
|
||||
export interface WhitelistItemData {
|
||||
pattern: string;
|
||||
isUserAgentDisabled?: boolean;
|
||||
}
|
||||
|
||||
const originUrlCache: string[] = [];
|
||||
|
||||
let platform: string;
|
||||
@@ -47,18 +52,18 @@ export async function initWhitelist() {
|
||||
}
|
||||
|
||||
// Register on first run
|
||||
await registerUserAgentWhitelist();
|
||||
await registerSiteWhitelist();
|
||||
|
||||
// Re-register when options change
|
||||
options.addEventListener("changed", ev => {
|
||||
const alteredOpts = ev.detail;
|
||||
|
||||
if (
|
||||
alteredOpts.includes("userAgentWhitelist") ||
|
||||
alteredOpts.includes("userAgentWhitelistEnabled")
|
||||
alteredOpts.includes("siteWhitelist") ||
|
||||
alteredOpts.includes("siteWhitelistEnabled")
|
||||
) {
|
||||
unregisterUserAgentWhitelist();
|
||||
registerUserAgentWhitelist();
|
||||
unregisterSiteWhitelist();
|
||||
registerSiteWhitelist();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -189,9 +194,8 @@ async function onBeforeCastSDKRequest(details: OnBeforeRequestDetails) {
|
||||
};
|
||||
}
|
||||
|
||||
async function registerUserAgentWhitelist() {
|
||||
const { userAgentWhitelist, userAgentWhitelistEnabled } =
|
||||
await options.getAll();
|
||||
async function registerSiteWhitelist() {
|
||||
const { siteWhitelist, siteWhitelistEnabled } = await options.getAll();
|
||||
|
||||
browser.webRequest.onBeforeRequest.addListener(
|
||||
onBeforeCastSDKRequest,
|
||||
@@ -199,13 +203,18 @@ async function registerUserAgentWhitelist() {
|
||||
["blocking"]
|
||||
);
|
||||
|
||||
if (!userAgentWhitelistEnabled || !userAgentWhitelist.length) {
|
||||
if (!siteWhitelistEnabled || !siteWhitelist.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
browser.webRequest.onBeforeSendHeaders.addListener(
|
||||
onWhitelistedBeforeSendHeaders,
|
||||
{ urls: userAgentWhitelist },
|
||||
{
|
||||
// Filter for items with UA enabled
|
||||
urls: siteWhitelist.flatMap(item =>
|
||||
!item.isUserAgentDisabled ? [item.pattern] : []
|
||||
)
|
||||
},
|
||||
["blocking", "requestHeaders"]
|
||||
);
|
||||
|
||||
@@ -216,7 +225,7 @@ async function registerUserAgentWhitelist() {
|
||||
);
|
||||
}
|
||||
|
||||
function unregisterUserAgentWhitelist() {
|
||||
function unregisterSiteWhitelist() {
|
||||
originUrlCache.length = 0;
|
||||
|
||||
browser.webRequest.onBeforeSendHeaders.removeListener(
|
||||
|
||||
@@ -16,7 +16,6 @@ export default {
|
||||
mirroringAppId: MIRRORING_APP_ID,
|
||||
receiverSelectorCloseIfFocusLost: true,
|
||||
receiverSelectorWaitForConnection: true,
|
||||
userAgentWhitelistEnabled: true,
|
||||
userAgentWhitelistRestrictedEnabled: true,
|
||||
userAgentWhitelist: ["https://www.netflix.com/*"]
|
||||
siteWhitelistEnabled: true,
|
||||
siteWhitelist: [{ pattern: "https://www.netflix.com/*" }]
|
||||
} as Options;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
import defaultOptions from "../defaultOptions";
|
||||
import type { WhitelistItemData } from "../background/whitelist";
|
||||
|
||||
import logger from "./logger";
|
||||
|
||||
@@ -25,9 +26,8 @@ export interface Options {
|
||||
mirroringAppId: string;
|
||||
receiverSelectorCloseIfFocusLost: boolean;
|
||||
receiverSelectorWaitForConnection: boolean;
|
||||
userAgentWhitelistEnabled: boolean;
|
||||
userAgentWhitelistRestrictedEnabled: boolean;
|
||||
userAgentWhitelist: string[];
|
||||
siteWhitelistEnabled: boolean;
|
||||
siteWhitelist: WhitelistItemData[];
|
||||
|
||||
[key: string]: Options[keyof Options];
|
||||
}
|
||||
|
||||
@@ -1,316 +0,0 @@
|
||||
/* eslint-disable max-len */
|
||||
"use strict";
|
||||
|
||||
import React, { Component } from "react";
|
||||
|
||||
const _ = browser.i18n.getMessage;
|
||||
|
||||
|
||||
interface EditableListProps {
|
||||
data: string[];
|
||||
itemPattern: RegExp;
|
||||
onChange (data: string[]): void;
|
||||
itemPatternError (err?: string): string;
|
||||
}
|
||||
|
||||
interface EditableListState {
|
||||
addingNewItem: boolean;
|
||||
rawView: boolean;
|
||||
rawViewValue: string;
|
||||
}
|
||||
|
||||
export default class EditableList extends Component<
|
||||
EditableListProps, EditableListState> {
|
||||
|
||||
private rawViewTextArea: (HTMLTextAreaElement | null) = null;
|
||||
|
||||
constructor(props: EditableListProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
addingNewItem: false
|
||||
, rawView: false
|
||||
, rawViewValue: ""
|
||||
};
|
||||
|
||||
this.handleItemRemove = this.handleItemRemove.bind(this);
|
||||
this.handleItemEdit = this.handleItemEdit.bind(this);
|
||||
this.handleSwitchView = this.handleSwitchView.bind(this);
|
||||
this.handleSaveRaw = this.handleSaveRaw.bind(this);
|
||||
this.handleRawViewTextAreaChange = this.handleRawViewTextAreaChange.bind(this);
|
||||
this.handleAddItem = this.handleAddItem.bind(this);
|
||||
this.handleNewItemRemove = this.handleNewItemRemove.bind(this);
|
||||
this.handleNewItemEdit = this.handleNewItemEdit.bind(this);
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<div className="editable-list">
|
||||
{ this.state.rawView
|
||||
? (
|
||||
<textarea className="editable-list__raw-view"
|
||||
rows={ Math.min(this.props.data.length, 10) }
|
||||
value={ this.state.rawViewValue }
|
||||
onChange={ this.handleRawViewTextAreaChange }
|
||||
ref={ el => { this.rawViewTextArea = el; }}>
|
||||
</textarea>
|
||||
) : (
|
||||
<ul className="editable-list__items">
|
||||
{ this.props.data.map((item, i) =>
|
||||
<EditableListItem text={ item }
|
||||
itemPattern={ this.props.itemPattern }
|
||||
itemPatternError={ this.props.itemPatternError }
|
||||
onRemove={ this.handleItemRemove }
|
||||
onEdit={ this.handleItemEdit }
|
||||
key={ i } /> )}
|
||||
|
||||
{ this.state.addingNewItem &&
|
||||
<EditableListItem text=""
|
||||
itemPattern={ this.props.itemPattern }
|
||||
itemPatternError={ this.props.itemPatternError }
|
||||
onRemove={ this.handleNewItemRemove }
|
||||
onEdit={ this.handleNewItemEdit }
|
||||
editing={ true } /> }
|
||||
</ul>
|
||||
)}
|
||||
<hr />
|
||||
<div className="editable-list__view-actions">
|
||||
{ !this.state.rawView &&
|
||||
<button className="editable-list__add-button ghost"
|
||||
title={ _("optionsUserAgentWhitelistAddItem") }
|
||||
onClick={ this.handleAddItem }
|
||||
type="button">
|
||||
<img src="assets/photon_new.svg" alt="icon, add" />
|
||||
</button> }
|
||||
|
||||
{ this.state.rawView &&
|
||||
<button className="editable-list__save-raw-button"
|
||||
onClick={ this.handleSaveRaw }
|
||||
type="button">
|
||||
{ _("optionsUserAgentWhitelistSaveRaw") }
|
||||
</button> }
|
||||
|
||||
<button className="editable-list__view-button"
|
||||
onClick={ this.handleSwitchView }
|
||||
type="button">
|
||||
{ this.state.rawView
|
||||
? _("optionsUserAgentWhitelistBasicView")
|
||||
: _("optionsUserAgentWhitelistRawView") }
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private handleItemRemove(item: string) {
|
||||
const newItems = new Set(this.props.data);
|
||||
newItems.delete(item);
|
||||
|
||||
this.props.onChange([ ...newItems ]);
|
||||
}
|
||||
|
||||
private handleItemEdit(item: string, newValue: string) {
|
||||
this.props.onChange(this.props.data.map(
|
||||
currentItem => currentItem === item
|
||||
? newValue
|
||||
: currentItem));
|
||||
}
|
||||
|
||||
private handleSwitchView() {
|
||||
this.setState(currentState => {
|
||||
if (currentState.rawView) {
|
||||
return {
|
||||
rawView: false
|
||||
, rawViewValue: ""
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
rawView: true
|
||||
, rawViewValue: this.props.data.join("\n")
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private handleSaveRaw() {
|
||||
this.setState(currentState => {
|
||||
const newItems = currentState.rawViewValue.split("\n")
|
||||
.filter(item => item !== "");
|
||||
|
||||
if ("itemPattern" in this.props) {
|
||||
for (const item of newItems) {
|
||||
if (!this.props.itemPattern.test(item)) {
|
||||
this.rawViewTextArea?.setCustomValidity(
|
||||
this.props.itemPatternError(item));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.rawViewTextArea?.setCustomValidity("");
|
||||
}
|
||||
|
||||
this.props.onChange(newItems);
|
||||
});
|
||||
}
|
||||
|
||||
private handleRawViewTextAreaChange(ev: React.ChangeEvent<HTMLTextAreaElement>) {
|
||||
if (!this.rawViewTextArea) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.rawViewTextArea.scrollHeight > this.rawViewTextArea.clientHeight) {
|
||||
this.rawViewTextArea.style.height = `${this.rawViewTextArea.scrollHeight}px`;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
rawViewValue: ev.target.value
|
||||
});
|
||||
}
|
||||
|
||||
private handleAddItem() {
|
||||
this.setState({
|
||||
addingNewItem: true
|
||||
});
|
||||
}
|
||||
|
||||
private handleNewItemRemove() {
|
||||
this.setState({
|
||||
addingNewItem: false
|
||||
});
|
||||
}
|
||||
|
||||
private handleNewItemEdit(_item: string, newItem: string) {
|
||||
this.setState({
|
||||
addingNewItem: false
|
||||
}, () => {
|
||||
this.props.onChange([ ...this.props.data, newItem ]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
interface EditableListItemProps {
|
||||
text: string;
|
||||
itemPattern: RegExp;
|
||||
editing?: boolean;
|
||||
itemPatternError (err?: string): string;
|
||||
onRemove (item: string): void;
|
||||
onEdit (item: string, newValue: string): void;
|
||||
}
|
||||
|
||||
interface EditableListItemState {
|
||||
editing: boolean;
|
||||
editValue: string;
|
||||
}
|
||||
|
||||
class EditableListItem extends Component<
|
||||
EditableListItemProps, EditableListItemState> {
|
||||
|
||||
private input: (HTMLInputElement | null) = null;
|
||||
|
||||
constructor(props: EditableListItemProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
editing: this.props.editing || false
|
||||
, editValue: ""
|
||||
};
|
||||
|
||||
this.handleRemove = this.handleRemove.bind(this);
|
||||
this.handleEditBegin = this.handleEditBegin.bind(this);
|
||||
this.handleEditEnd = this.handleEditEnd.bind(this);
|
||||
this.handleInputChange = this.handleInputChange.bind(this);
|
||||
this.handleInputKeyPress = this.handleInputKeyPress.bind(this);
|
||||
}
|
||||
|
||||
public render() {
|
||||
const selected = this.state.editing
|
||||
? "editable-list__item--selected" : "";
|
||||
|
||||
return (
|
||||
<li className={`editable-list__item ${selected}`}>
|
||||
<div className="editable-list__title"
|
||||
onDoubleClick={ this.handleEditBegin }>
|
||||
|
||||
{ this.state.editing
|
||||
? <input className="editable-list__edit-field"
|
||||
type="text"
|
||||
ref={ input => this.input = input }
|
||||
value={ this.state.editValue }
|
||||
onBlur={ this.handleEditEnd }
|
||||
onChange={ this.handleInputChange }
|
||||
onKeyPress={ this.handleInputKeyPress }/>
|
||||
: this.props.text }
|
||||
</div>
|
||||
|
||||
<button className="editable-list__edit-button ghost"
|
||||
title={ _("optionsUserAgentWhitelistEditItem") }
|
||||
onClick={ this.handleEditBegin }
|
||||
type="button">
|
||||
<img src="assets/photon_edit.svg" alt="icon, edit" />
|
||||
</button>
|
||||
|
||||
<button className="editable-list__remove-button ghost"
|
||||
title={ _("optionsUserAgentWhitelistRemoveItem") }
|
||||
onClick={ this.handleRemove }
|
||||
type="button">
|
||||
<img src="assets/photon_delete.svg" alt="icon, remove" />
|
||||
</button>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
private stopEditing(input: HTMLInputElement) {
|
||||
if (this.props.editing
|
||||
&& !this.props.itemPattern.test(this.state.editValue)) {
|
||||
input.setCustomValidity(this.props.itemPatternError());
|
||||
}
|
||||
|
||||
if (!input.validity.valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.onEdit(this.props.text, this.state.editValue);
|
||||
this.setState({
|
||||
editing: false
|
||||
, editValue: ""
|
||||
});
|
||||
}
|
||||
|
||||
private handleRemove() {
|
||||
this.props.onRemove(this.props.text);
|
||||
}
|
||||
|
||||
private handleEditBegin() {
|
||||
if (!this.state.editing) {
|
||||
this.setState({
|
||||
editing: true
|
||||
, editValue: this.props.text
|
||||
}, () => {
|
||||
this.input?.focus();
|
||||
this.input?.select();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private handleEditEnd(ev: React.FocusEvent<HTMLInputElement>) {
|
||||
this.stopEditing(ev.target);
|
||||
}
|
||||
|
||||
private handleInputChange(ev: React.ChangeEvent<HTMLInputElement>) {
|
||||
this.setState({
|
||||
editValue: ev.target.value
|
||||
});
|
||||
|
||||
// If invalid, set custom error from parent
|
||||
ev.target.setCustomValidity(!this.props.itemPattern.test(ev.target.value)
|
||||
? this.props.itemPatternError()
|
||||
: "");
|
||||
}
|
||||
|
||||
private handleInputKeyPress(ev: React.KeyboardEvent<HTMLInputElement>) {
|
||||
if (ev.key === "Enter") {
|
||||
this.stopEditing(ev.target as HTMLInputElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
225
ext/src/ui/options/Whitelist.tsx
Normal file
225
ext/src/ui/options/Whitelist.tsx
Normal file
@@ -0,0 +1,225 @@
|
||||
/* eslint-disable max-len */
|
||||
"use strict";
|
||||
|
||||
import React, { Component } from "react";
|
||||
|
||||
import type { WhitelistItemData } from "../../background/whitelist";
|
||||
import { REMOTE_MATCH_PATTERN_REGEX } from "../../lib/matchPattern";
|
||||
|
||||
const _ = browser.i18n.getMessage;
|
||||
|
||||
interface WhitelistProps {
|
||||
items: WhitelistItemData[];
|
||||
onChange: (items: WhitelistItemData[]) => void;
|
||||
}
|
||||
interface WhitelistState {
|
||||
addingNewItem: boolean;
|
||||
}
|
||||
|
||||
/** Editable list component for site whitelist. */
|
||||
export default class Whitelist extends Component<
|
||||
WhitelistProps,
|
||||
WhitelistState
|
||||
> {
|
||||
state: WhitelistState = {
|
||||
addingNewItem: false
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="whitelist">
|
||||
<ul className="whitelist__items">
|
||||
{this.props.items.map((item, i) => (
|
||||
<WhitelistItem
|
||||
value={item}
|
||||
onEdit={(oldValue, newValue) => {
|
||||
// Replace item
|
||||
this.props.onChange(
|
||||
this.props.items.map(item =>
|
||||
item.pattern === oldValue?.pattern
|
||||
? newValue
|
||||
: item
|
||||
)
|
||||
);
|
||||
}}
|
||||
onRemove={value => {
|
||||
// Remove item
|
||||
this.props.onChange(
|
||||
this.props.items.filter(
|
||||
item => item.pattern !== value?.pattern
|
||||
)
|
||||
);
|
||||
}}
|
||||
key={i}
|
||||
/>
|
||||
))}
|
||||
|
||||
{this.state.addingNewItem && (
|
||||
<WhitelistItem
|
||||
isEditing={true}
|
||||
onEdit={(__, newValue) => {
|
||||
// Add new item
|
||||
this.setState({ addingNewItem: false }, () => {
|
||||
this.props.onChange([
|
||||
...this.props.items,
|
||||
newValue
|
||||
]);
|
||||
});
|
||||
}}
|
||||
onRemove={() => {
|
||||
// Cancel adding new item
|
||||
this.setState({ addingNewItem: false });
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</ul>
|
||||
|
||||
<hr />
|
||||
|
||||
<div className="whitelist__view-actions">
|
||||
<button
|
||||
className="whitelist__add-button ghost"
|
||||
title={_("optionsSiteWhitelistAddItem")}
|
||||
onClick={() => this.setState({ addingNewItem: true })}
|
||||
type="button"
|
||||
>
|
||||
<img src="assets/photon_new.svg" alt="icon, add" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
interface WhitelistItemProps {
|
||||
value?: WhitelistItemData;
|
||||
/** Initial editing state */
|
||||
isEditing?: boolean;
|
||||
onEdit: (
|
||||
oldValue: WhitelistItemData | undefined,
|
||||
newValue: WhitelistItemData
|
||||
) => void;
|
||||
onRemove: (value?: WhitelistItemData) => void;
|
||||
}
|
||||
interface WhitelistItemState {
|
||||
isEditing: boolean;
|
||||
editValue?: WhitelistItemData;
|
||||
}
|
||||
|
||||
/** Editable item component for whitelist. */
|
||||
class WhitelistItem extends Component<WhitelistItemProps, WhitelistItemState> {
|
||||
private inputElement: HTMLInputElement | null = null;
|
||||
|
||||
constructor(props: WhitelistItemProps) {
|
||||
super(props);
|
||||
this.state = { isEditing: props.isEditing ?? false };
|
||||
|
||||
this.beginEditing = this.beginEditing.bind(this);
|
||||
this.finishEditing = this.finishEditing.bind(this);
|
||||
}
|
||||
|
||||
/** Sets editing state and focuses input field. */
|
||||
private beginEditing() {
|
||||
if (this.state.isEditing) return;
|
||||
|
||||
this.setState(
|
||||
{
|
||||
isEditing: true,
|
||||
editValue: this.props.value
|
||||
},
|
||||
() => {
|
||||
this.inputElement?.focus();
|
||||
this.inputElement?.select();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/** Checks input validity and sends edit update. */
|
||||
private finishEditing() {
|
||||
if (!this.state.isEditing || !this.state.editValue) return;
|
||||
|
||||
if (this.inputElement?.validity.valid) {
|
||||
this.props.onEdit(this.props.value, this.state.editValue);
|
||||
this.setState({
|
||||
isEditing: false,
|
||||
editValue: undefined
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const selectedClassName = this.state.isEditing
|
||||
? "whitelist__item--selected"
|
||||
: "";
|
||||
|
||||
return (
|
||||
<li className={`whitelist__item ${selectedClassName}`}>
|
||||
<div
|
||||
className="whitelist__title"
|
||||
onDoubleClick={this.beginEditing}
|
||||
>
|
||||
{this.state.isEditing ? (
|
||||
<input
|
||||
ref={el => (this.inputElement = el)}
|
||||
type="text"
|
||||
className="whitelist__input-pattern"
|
||||
value={this.state.editValue?.pattern}
|
||||
pattern={REMOTE_MATCH_PATTERN_REGEX.source}
|
||||
onChange={ev => {
|
||||
this.setState(prevState => ({
|
||||
editValue: {
|
||||
...prevState.editValue,
|
||||
pattern: ev.target.value
|
||||
}
|
||||
}));
|
||||
}}
|
||||
onBlur={this.finishEditing}
|
||||
onKeyPress={ev => {
|
||||
if (ev.key === "Enter") {
|
||||
this.finishEditing();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
this.props.value?.pattern
|
||||
)}
|
||||
</div>
|
||||
|
||||
<label className="whitelist__user-agent">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={!this.props.value?.isUserAgentDisabled}
|
||||
onChange={ev => {
|
||||
if (!this.props.value) return;
|
||||
this.props.onEdit(this.props.value, {
|
||||
...this.props.value,
|
||||
isUserAgentDisabled: !ev.target.checked
|
||||
});
|
||||
}}
|
||||
/>
|
||||
{_("optionsSiteWhitelistUserAgent")}
|
||||
</label>
|
||||
|
||||
<button
|
||||
className="whitelist__edit-button ghost"
|
||||
title={_("optionsSiteWhitelistEditItem")}
|
||||
onClick={this.beginEditing}
|
||||
type="button"
|
||||
>
|
||||
<img src="assets/photon_edit.svg" alt="icon, edit" />
|
||||
</button>
|
||||
|
||||
<button
|
||||
className="whitelist__remove-button ghost"
|
||||
title={_("optionsSiteWhitelistRemoveItem")}
|
||||
onClick={() => {
|
||||
this.props.onRemove(this.props.value);
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
<img src="assets/photon_delete.svg" alt="icon, remove" />
|
||||
</button>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -5,14 +5,14 @@ import React, { Component } from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
import defaultOptions from "../../defaultOptions";
|
||||
import type { WhitelistItemData } from "../../background/whitelist";
|
||||
|
||||
import Bridge from "./Bridge";
|
||||
import EditableList from "./EditableList";
|
||||
import Whitelist from "./Whitelist";
|
||||
|
||||
import bridge, { BridgeInfo, BridgeTimedOutError } from "../../lib/bridge";
|
||||
import logger from "../../lib/logger";
|
||||
import options, { Options } from "../../lib/options";
|
||||
import { REMOTE_MATCH_PATTERN_REGEX } from "../../lib/matchPattern";
|
||||
|
||||
const _ = browser.i18n.getMessage;
|
||||
|
||||
@@ -77,9 +77,6 @@ class OptionsApp extends Component<OptionsAppProps, OptionsAppState> {
|
||||
this.handleFormChange = this.handleFormChange.bind(this);
|
||||
this.handleInputChange = this.handleInputChange.bind(this);
|
||||
this.handleWhitelistChange = this.handleWhitelistChange.bind(this);
|
||||
|
||||
this.getWhitelistItemPatternError =
|
||||
this.getWhitelistItemPatternError.bind(this);
|
||||
}
|
||||
|
||||
public async componentDidMount() {
|
||||
@@ -333,77 +330,43 @@ class OptionsApp extends Component<OptionsAppProps, OptionsAppState> {
|
||||
|
||||
<fieldset className="category">
|
||||
<legend className="category__name">
|
||||
<h2>
|
||||
{_("optionsUserAgentWhitelistCategoryName")}
|
||||
</h2>
|
||||
<h2>{_("optionsSiteWhitelistCategoryName")}</h2>
|
||||
</legend>
|
||||
<p className="category__description">
|
||||
{_("optionsUserAgentWhitelistCategoryDescription")}
|
||||
{_("optionsSiteWhitelistCategoryDescription")}
|
||||
</p>
|
||||
|
||||
<label className="option option--inline">
|
||||
<div className="option__control">
|
||||
<input
|
||||
name="userAgentWhitelistEnabled"
|
||||
name="siteWhitelistEnabled"
|
||||
type="checkbox"
|
||||
checked={
|
||||
this.state.options
|
||||
?.userAgentWhitelistEnabled
|
||||
this.state.options?.siteWhitelistEnabled
|
||||
}
|
||||
onChange={this.handleInputChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="option__label">
|
||||
{_("optionsUserAgentWhitelistEnabled")}
|
||||
<span className="option__recommended">
|
||||
{_("optionsOptionRecommended")}
|
||||
</span>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<label className="option option--inline">
|
||||
<div className="option__control">
|
||||
<input
|
||||
name="userAgentWhitelistRestrictedEnabled"
|
||||
type="checkbox"
|
||||
checked={
|
||||
this.state.options
|
||||
?.userAgentWhitelistRestrictedEnabled
|
||||
}
|
||||
onChange={this.handleInputChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="option__label">
|
||||
{_(
|
||||
"optionsUserAgentWhitelistRestrictedEnabled"
|
||||
)}
|
||||
{_("optionsSiteWhitelistEnabled")}
|
||||
<span className="option__recommended">
|
||||
{_("optionsOptionRecommended")}
|
||||
</span>
|
||||
</div>
|
||||
<div className="option__description">
|
||||
{_(
|
||||
"optionsUserAgentWhitelistRestrictedEnabledDescription"
|
||||
)}
|
||||
{_("optionsSiteWhitelistEnabledDescription")}
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<div className="option">
|
||||
<div className="option__label">
|
||||
{_("optionsUserAgentWhitelistContent")}
|
||||
{_("optionsSiteWhitelistContent")}
|
||||
</div>
|
||||
<div className="option__control">
|
||||
{this.state.options?.userAgentWhitelist && (
|
||||
<EditableList
|
||||
data={
|
||||
this.state.options
|
||||
.userAgentWhitelist
|
||||
}
|
||||
<Whitelist
|
||||
items={this.state.options.siteWhitelist}
|
||||
onChange={this.handleWhitelistChange}
|
||||
itemPattern={REMOTE_MATCH_PATTERN_REGEX}
|
||||
itemPatternError={
|
||||
this.getWhitelistItemPatternError
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
@@ -485,22 +448,15 @@ class OptionsApp extends Component<OptionsAppProps, OptionsAppState> {
|
||||
});
|
||||
}
|
||||
|
||||
private handleWhitelistChange(whitelist: string[]) {
|
||||
private handleWhitelistChange(whitelist: WhitelistItemData[]) {
|
||||
this.setState(currentState => {
|
||||
if (currentState.options) {
|
||||
currentState.options.userAgentWhitelist = whitelist;
|
||||
currentState.options.siteWhitelist = whitelist;
|
||||
}
|
||||
|
||||
return currentState;
|
||||
});
|
||||
}
|
||||
|
||||
private getWhitelistItemPatternError(info: string): string {
|
||||
return _("optionsUserAgentWhitelistInvalidMatchPattern", info);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ReactDOM.render(
|
||||
<OptionsApp />
|
||||
, document.querySelector("#root"));
|
||||
ReactDOM.render(<OptionsApp />, document.querySelector("#root"));
|
||||
|
||||
@@ -316,7 +316,7 @@ button.ghost:not(:hover) {
|
||||
}
|
||||
|
||||
|
||||
.editable-list {
|
||||
.whitelist {
|
||||
background-color: var(--box-background);
|
||||
border: 1px solid var(--border-color);
|
||||
color: var(--box-color);
|
||||
@@ -324,22 +324,18 @@ button.ghost:not(:hover) {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.editable-list__view-actions {
|
||||
.whitelist__view-actions {
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
}
|
||||
|
||||
.editable-list__save-raw-button {
|
||||
margin-inline-end: 5px;
|
||||
}
|
||||
|
||||
.editable-list hr {
|
||||
.whitelist hr {
|
||||
border: initial;
|
||||
border-top: 1px solid var(--border-color);
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.editable-list__items {
|
||||
.whitelist__items {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: initial;
|
||||
@@ -348,22 +344,22 @@ button.ghost:not(:hover) {
|
||||
width: calc(100% + 10px);
|
||||
}
|
||||
|
||||
.editable-list__item {
|
||||
.whitelist__item {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
height: 34px;
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
.editable-list__item:nth-child(odd) {
|
||||
.whitelist__item:nth-child(odd) {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.editable-list__item--selected {
|
||||
.whitelist__item--selected {
|
||||
background-color: var(--blue-50-a30) !important;
|
||||
}
|
||||
|
||||
.editable-list__title {
|
||||
.whitelist__title {
|
||||
flex: 1;
|
||||
font-family: monospace;
|
||||
overflow: hidden;
|
||||
@@ -372,28 +368,24 @@ button.ghost:not(:hover) {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.editable-list__item:not(.editable-list__item--selected) > .editable-list__title {
|
||||
.whitelist__item:not(.whitelist__item--selected) > .whitelist__title {
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.editable-list__title + button {
|
||||
.whitelist__title + button {
|
||||
margin-inline-end: 5px;
|
||||
}
|
||||
|
||||
.editable-list__edit-field {
|
||||
.whitelist__input-pattern {
|
||||
font: inherit;
|
||||
margin-inline-end: 1em;
|
||||
width: -moz-available;
|
||||
}
|
||||
|
||||
.editable-list__raw-view {
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
resize: vertical;
|
||||
width: 100%;
|
||||
.whitelist__user-agent {
|
||||
margin-inline-end: 5px;
|
||||
}
|
||||
|
||||
.editable-list__add-button {
|
||||
.whitelist__add-button {
|
||||
margin-inline-end: auto;
|
||||
}
|
||||
|
||||
@@ -410,7 +402,7 @@ button.ghost:not(:hover) {
|
||||
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.editable-list__item:nth-child(odd) {
|
||||
.whitelist__item:nth-child(odd) {
|
||||
background-color: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import React, { Component } from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
import { menuIdPopupCast, menuIdPopupStop } from "../../background/menus";
|
||||
import type { ReceiverSelectorPageInfo } from "../../background/ReceiverSelector";
|
||||
import type { WhitelistItemData } from "../../background/whitelist";
|
||||
|
||||
import knownApps, { KnownApp } from "../../cast/knownApps";
|
||||
import options from "../../lib/options";
|
||||
@@ -20,7 +22,6 @@ import {
|
||||
ReceiverSelectorMediaType
|
||||
} from "../../types";
|
||||
|
||||
import { ReceiverSelectorPageInfo } from "../../background/ReceiverSelector";
|
||||
import { Capability } from "../../cast/sdk/enums";
|
||||
|
||||
const _ = browser.i18n.getMessage;
|
||||
@@ -92,8 +93,8 @@ interface PopupAppState {
|
||||
|
||||
// Options
|
||||
mirroringEnabled: boolean;
|
||||
userAgentWhitelistEnabled: boolean;
|
||||
userAgentWhitelist: string[];
|
||||
siteWhitelistEnabled: boolean;
|
||||
siteWhitelist: WhitelistItemData[];
|
||||
}
|
||||
|
||||
class PopupApp extends Component<PopupAppProps, PopupAppState> {
|
||||
@@ -114,8 +115,8 @@ class PopupApp extends Component<PopupAppProps, PopupAppState> {
|
||||
isPageWhitelisted: false,
|
||||
isConnecting: false,
|
||||
mirroringEnabled: false,
|
||||
userAgentWhitelistEnabled: true,
|
||||
userAgentWhitelist: []
|
||||
siteWhitelistEnabled: true,
|
||||
siteWhitelist: []
|
||||
};
|
||||
|
||||
// Store window ref
|
||||
@@ -229,8 +230,8 @@ class PopupApp extends Component<PopupAppProps, PopupAppState> {
|
||||
|
||||
// Check if target page URL is whitelisted.
|
||||
if (this.state.pageInfo) {
|
||||
for (const patternString of this.state.userAgentWhitelist) {
|
||||
const pattern = new RemoteMatchPattern(patternString);
|
||||
for (const item of this.state.siteWhitelist) {
|
||||
const pattern = new RemoteMatchPattern(item.pattern);
|
||||
if (pattern.matches(this.state.pageInfo.url)) {
|
||||
isPageWhitelisted = true;
|
||||
break;
|
||||
@@ -249,10 +250,10 @@ class PopupApp extends Component<PopupAppProps, PopupAppState> {
|
||||
return;
|
||||
}
|
||||
|
||||
const whitelist = await options.get("userAgentWhitelist");
|
||||
if (!whitelist.includes(app.matches)) {
|
||||
whitelist.push(app.matches);
|
||||
await options.set("userAgentWhitelist", whitelist);
|
||||
const whitelist = await options.get("siteWhitelist");
|
||||
if (!whitelist.find(item => item.pattern === app.matches)) {
|
||||
whitelist.push({ pattern: app.matches });
|
||||
await options.set("siteWhitelist", whitelist);
|
||||
|
||||
await browser.tabs.reload(pageInfo.tabId);
|
||||
window.close();
|
||||
@@ -382,8 +383,8 @@ class PopupApp extends Component<PopupAppProps, PopupAppState> {
|
||||
options.getAll().then(opts => {
|
||||
this.setState({
|
||||
mirroringEnabled: opts.mirroringEnabled,
|
||||
userAgentWhitelistEnabled: opts.userAgentWhitelistEnabled,
|
||||
userAgentWhitelist: opts.userAgentWhitelist
|
||||
siteWhitelistEnabled: opts.siteWhitelistEnabled,
|
||||
siteWhitelist: opts.siteWhitelist
|
||||
});
|
||||
});
|
||||
|
||||
@@ -429,9 +430,9 @@ class PopupApp extends Component<PopupAppProps, PopupAppState> {
|
||||
// If we don't know the app
|
||||
!this.state.knownApp ||
|
||||
// If the whitelist is disabled
|
||||
!this.state.userAgentWhitelistEnabled ||
|
||||
!this.state.siteWhitelistEnabled ||
|
||||
// If the whitelist is enabled, and the page is whitelisted
|
||||
(this.state.userAgentWhitelistEnabled &&
|
||||
(this.state.siteWhitelistEnabled &&
|
||||
this.state.isPageWhitelisted) ||
|
||||
// If an app is already loaded on the page
|
||||
!!(
|
||||
|
||||
Reference in New Issue
Block a user