mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-08 08:39:59 +00:00
Add site-specific custom user agent option and new whitelist option UI
This commit is contained in:
@@ -329,10 +329,6 @@
|
||||
"message": "Add Item",
|
||||
"description": "Add new whitelist item button title."
|
||||
},
|
||||
"optionsSiteWhitelistUserAgent": {
|
||||
"message": "Disable UA",
|
||||
"description": "Whitelist item user agent checkbox title."
|
||||
},
|
||||
"optionsSiteWhitelistEditItem": {
|
||||
"message": "Edit",
|
||||
"description": "Edit whitelist item button title. Displayed on each item."
|
||||
@@ -350,13 +346,29 @@
|
||||
"description": "Default <option> for knownApps <select>."
|
||||
},
|
||||
"optionsSiteWhitelistCustomUserAgent": {
|
||||
"message": "Custom user agent:",
|
||||
"message": "User agent:",
|
||||
"description": "Custom user agent option label."
|
||||
},
|
||||
"optionsSiteWhitelistCustomUserAgentDescription": {
|
||||
"message": "If specified, a custom user agent string to use for whitelisted sites.",
|
||||
"description": "Custom user agent option description."
|
||||
},
|
||||
"optionsSiteWhitelistUserAgentDisabled": {
|
||||
"message": "Disable user agent",
|
||||
"description": "Whitelist item user agent disabled checkbox label."
|
||||
},
|
||||
"optionsSiteWhitelistUserAgentDisabledDescription": {
|
||||
"message": "Entirely disable user agent replacement for sites matching this pattern.",
|
||||
"description": "Whitelist item user agent disabled checkbox description."
|
||||
},
|
||||
"optionsSiteWhitelistSiteSpecificUserAgent": {
|
||||
"message": "User agent:",
|
||||
"description": "Whitelist item user agent option label."
|
||||
},
|
||||
"optionsSiteWhitelistSiteSpecificUserAgentDescription": {
|
||||
"message": "If specified, a custom user agent string to use specifically for this sites matching this pattern.",
|
||||
"description": "Whitelist item user agent option label."
|
||||
},
|
||||
|
||||
"optionsMirroringCategoryName": {
|
||||
"message": "Screen/tab casting",
|
||||
|
||||
@@ -4,6 +4,7 @@ import logger from "../lib/logger";
|
||||
import options from "../lib/options";
|
||||
|
||||
import { getChromeUserAgent } from "../lib/userAgents";
|
||||
import { RemoteMatchPattern } from "../lib/matchPattern";
|
||||
|
||||
import {
|
||||
CAST_FRAMEWORK_LOADER_SCRIPT_URL,
|
||||
@@ -25,6 +26,7 @@ type OnBeforeRequestDetails = Parameters<
|
||||
export interface WhitelistItemData {
|
||||
pattern: string;
|
||||
isUserAgentDisabled?: boolean;
|
||||
customUserAgent?: string;
|
||||
}
|
||||
|
||||
const originUrlCache: string[] = [];
|
||||
@@ -33,6 +35,8 @@ let platform: string;
|
||||
let chromeUserAgent: string | undefined;
|
||||
let chromeUserAgentHybrid: string | undefined;
|
||||
|
||||
let siteWhitelistEnabled = false;
|
||||
let siteWhitelist: Nullable<WhitelistItemData[]> = null;
|
||||
let customUserAgent: string | undefined;
|
||||
|
||||
export async function initWhitelist() {
|
||||
@@ -65,7 +69,6 @@ export async function initWhitelist() {
|
||||
if (alteredOpts.includes("siteWhitelistCustomUserAgent")) {
|
||||
customUserAgent = await options.get("siteWhitelistCustomUserAgent");
|
||||
}
|
||||
|
||||
if (
|
||||
alteredOpts.includes("siteWhitelist") ||
|
||||
alteredOpts.includes("siteWhitelistEnabled")
|
||||
@@ -76,6 +79,30 @@ export async function initWhitelist() {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configured user agent matching the specified URL or
|
||||
* undefined if the user agent is disabled.
|
||||
*/
|
||||
function getUserAgent(url: string, host?: string): Optional<string> {
|
||||
if (!siteWhitelistEnabled || !siteWhitelist) return;
|
||||
|
||||
// Search site-specific user agents
|
||||
const matchingItem = siteWhitelist.find(
|
||||
item =>
|
||||
item.customUserAgent &&
|
||||
new RemoteMatchPattern(item.pattern).matches(url)
|
||||
);
|
||||
if (matchingItem) {
|
||||
if (matchingItem.isUserAgentDisabled) return;
|
||||
return matchingItem.customUserAgent;
|
||||
}
|
||||
|
||||
return (
|
||||
customUserAgent ||
|
||||
(host === "www.youtube.com" ? chromeUserAgentHybrid : chromeUserAgent)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Web apps usually only load the sender library and
|
||||
* provide cast functionality if the browser is detected
|
||||
@@ -99,11 +126,7 @@ async function onWhitelistedBeforeSendHeaders(
|
||||
|
||||
for (const header of details.requestHeaders) {
|
||||
if (header.name === "User-Agent") {
|
||||
header.value =
|
||||
customUserAgent ||
|
||||
(host?.value === "www.youtube.com"
|
||||
? chromeUserAgentHybrid
|
||||
: chromeUserAgent);
|
||||
header.value = getUserAgent(details.url, host?.value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -134,11 +157,7 @@ function onWhitelistedChildBeforeSendHeaders(
|
||||
|
||||
for (const header of details.requestHeaders) {
|
||||
if (header.name === "User-Agent") {
|
||||
header.value =
|
||||
customUserAgent ||
|
||||
(host?.value === "www.youtube.com"
|
||||
? chromeUserAgentHybrid
|
||||
: chromeUserAgent);
|
||||
header.value = getUserAgent(details.url, host?.value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -205,7 +224,9 @@ async function onBeforeCastSDKRequest(details: OnBeforeRequestDetails) {
|
||||
}
|
||||
|
||||
async function registerSiteWhitelist() {
|
||||
const { siteWhitelist, siteWhitelistEnabled } = await options.getAll();
|
||||
const opts = await options.getAll();
|
||||
siteWhitelist = opts.siteWhitelist;
|
||||
siteWhitelistEnabled = opts.siteWhitelistEnabled;
|
||||
|
||||
browser.webRequest.onBeforeRequest.addListener(
|
||||
onBeforeCastSDKRequest,
|
||||
|
||||
@@ -18,11 +18,12 @@
|
||||
let isFormValid = true;
|
||||
let isSavedIndicatorVisible = false;
|
||||
|
||||
let platform: string;
|
||||
let defaultUserAgent: Optional<string>;
|
||||
|
||||
let opts: Options | undefined;
|
||||
onMount(async () => {
|
||||
platform = (await browser.runtime.getPlatformInfo()).os;
|
||||
const platform = (await browser.runtime.getPlatformInfo()).os;
|
||||
defaultUserAgent = getChromeUserAgent(platform);
|
||||
|
||||
opts = await options.getAll();
|
||||
options.addEventListener("changed", async () => {
|
||||
@@ -45,6 +46,9 @@
|
||||
if (item.isUserAgentDisabled === false) {
|
||||
delete item.isUserAgentDisabled;
|
||||
}
|
||||
if (item.customUserAgent === "") {
|
||||
delete item.customUserAgent;
|
||||
}
|
||||
}
|
||||
|
||||
await options.setAll(opts);
|
||||
@@ -68,7 +72,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if opts && platform}
|
||||
{#if opts}
|
||||
<form
|
||||
id="form"
|
||||
bind:this={formElement}
|
||||
@@ -281,7 +285,7 @@
|
||||
id="siteWhitelistCustomUserAgent"
|
||||
type="text"
|
||||
bind:value={opts.siteWhitelistCustomUserAgent}
|
||||
placeholder={getChromeUserAgent(platform)}
|
||||
placeholder={defaultUserAgent}
|
||||
/>
|
||||
<div class="option__description">
|
||||
{_("optionsSiteWhitelistCustomUserAgentDescription")}
|
||||
@@ -294,7 +298,11 @@
|
||||
{_("optionsSiteWhitelistContent")}
|
||||
</div>
|
||||
<div class="option__control">
|
||||
<Whitelist bind:items={opts.siteWhitelist} />
|
||||
<Whitelist
|
||||
bind:items={opts.siteWhitelist}
|
||||
{opts}
|
||||
{defaultUserAgent}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
@@ -4,11 +4,14 @@
|
||||
import knownApps, { KnownApp } from "../../cast/knownApps";
|
||||
import { WhitelistItemData } from "../../background/whitelist";
|
||||
import { REMOTE_MATCH_PATTERN_REGEX } from "../../lib/matchPattern";
|
||||
import { Options } from "../../lib/options";
|
||||
|
||||
const _ = browser.i18n.getMessage;
|
||||
|
||||
/** Whitelist items to display. */
|
||||
export let items: WhitelistItemData[];
|
||||
export let opts: Options;
|
||||
export let defaultUserAgent: Optional<string>;
|
||||
|
||||
let isEditing = false;
|
||||
let isEditingValid = false;
|
||||
@@ -16,6 +19,8 @@
|
||||
let editingInput: HTMLInputElement;
|
||||
let editingValue: string;
|
||||
|
||||
let expandedItemIndices = new Set();
|
||||
|
||||
let knownAppToAdd: Nullable<KnownApp> = null;
|
||||
$: filteredKnownApps = Object.values(knownApps).filter(app => {
|
||||
// If no pattern or name matches default media sender
|
||||
@@ -115,13 +120,17 @@
|
||||
<ul class="whitelist__items">
|
||||
{#each items as item, i}
|
||||
{@const isEditingItem = isEditing && editingIndex === i}
|
||||
{@const isItemExpanded = expandedItemIndices.has(i)}
|
||||
|
||||
<li
|
||||
class="whitelist__item"
|
||||
class:whitelist__item--selected={isEditingItem}
|
||||
on:dblclick={() => beginEditing(i)}
|
||||
class:whitelist__item--expanded={isItemExpanded}
|
||||
>
|
||||
<div class="whitelist__title">
|
||||
<div
|
||||
class="whitelist__title"
|
||||
on:dblclick={() => beginEditing(i)}
|
||||
>
|
||||
{#if isEditingItem}
|
||||
<input
|
||||
type="text"
|
||||
@@ -150,13 +159,6 @@
|
||||
</div>
|
||||
|
||||
{#if !isEditingItem}
|
||||
<label class="whitelist__user-agent">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={item.isUserAgentDisabled}
|
||||
/>
|
||||
{_("optionsSiteWhitelistUserAgent")}
|
||||
</label>
|
||||
<button
|
||||
type="button"
|
||||
class="whitelist__edit-button ghost"
|
||||
@@ -177,6 +179,80 @@
|
||||
>
|
||||
<img src="assets/photon_delete.svg" alt="icon, remove" />
|
||||
</button>
|
||||
|
||||
{#if !isEditingItem}
|
||||
<button
|
||||
type="button"
|
||||
class="whitelist__expand-button ghost"
|
||||
title={_("optionsSiteWhitelistRemoveItem")}
|
||||
on:click={() => {
|
||||
// Toggle expanded state
|
||||
if (isItemExpanded) {
|
||||
expandedItemIndices.delete(i);
|
||||
} else {
|
||||
expandedItemIndices.add(i);
|
||||
}
|
||||
expandedItemIndices = expandedItemIndices;
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src="assets/{isItemExpanded
|
||||
? 'photon_arrowhead_up.svg'
|
||||
: 'photon_arrowhead_down.svg'}"
|
||||
alt="icon, arrow down"
|
||||
/>
|
||||
</button>
|
||||
|
||||
{#if isItemExpanded}
|
||||
<div class="whitelist__expanded">
|
||||
<div class="option option--inline">
|
||||
<div class="option__control">
|
||||
<input
|
||||
id="isUserAgentDisabled-{i}"
|
||||
type="checkbox"
|
||||
bind:checked={item.isUserAgentDisabled}
|
||||
/>
|
||||
</div>
|
||||
<label
|
||||
class="option__label"
|
||||
for="isUserAgentDisabled-{i}"
|
||||
>
|
||||
{_("optionsSiteWhitelistUserAgentDisabled")}
|
||||
</label>
|
||||
<div class="option__description">
|
||||
{_(
|
||||
"optionsSiteWhitelistUserAgentDisabledDescription"
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="option">
|
||||
<label
|
||||
class="option__label"
|
||||
for="customUserAgentString-{i}"
|
||||
>
|
||||
{_(
|
||||
"optionsSiteWhitelistSiteSpecificUserAgent"
|
||||
)}
|
||||
</label>
|
||||
<div class="option__control">
|
||||
<input
|
||||
id="customUserAgentString-{i}"
|
||||
type="text"
|
||||
bind:value={item.customUserAgent}
|
||||
placeholder={opts.siteWhitelistCustomUserAgent ||
|
||||
defaultUserAgent}
|
||||
/>
|
||||
<div class="option__description">
|
||||
{_(
|
||||
"optionsSiteWhitelistSiteSpecificUserAgentDescription"
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
|
||||
13
ext/src/ui/options/assets/photon_arrowhead_down.svg
Normal file
13
ext/src/ui/options/assets/photon_arrowhead_down.svg
Normal file
@@ -0,0 +1,13 @@
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<style>
|
||||
@media (prefers-color-scheme: dark) {
|
||||
path {
|
||||
fill: rgba(249, 249, 250, .8);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<path fill="rgba(12, 12, 13, .8)" d="M8 12a1 1 0 0 1-.707-.293l-5-5a1 1 0 0 1 1.414-1.414L8 9.586l4.293-4.293a1 1 0 0 1 1.414 1.414l-5 5A1 1 0 0 1 8 12z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 629 B |
13
ext/src/ui/options/assets/photon_arrowhead_up.svg
Normal file
13
ext/src/ui/options/assets/photon_arrowhead_up.svg
Normal file
@@ -0,0 +1,13 @@
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<style>
|
||||
@media (prefers-color-scheme: dark) {
|
||||
path {
|
||||
fill: rgba(249, 249, 250, .8);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<path fill="rgba(12, 12, 13, .8)" d="M13 11a1 1 0 0 1-.707-.293L8 6.414l-4.293 4.293a1 1 0 0 1-1.414-1.414l5-5a1 1 0 0 1 1.414 0l5 5A1 1 0 0 1 13 11z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 625 B |
@@ -1,11 +1,11 @@
|
||||
:root {
|
||||
--border-color: rgb(225, 225, 225);
|
||||
--border-color: var(--grey-90-a20);
|
||||
--secondary-color: rgb(125, 125, 125);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--border-color: var(--grey-50);
|
||||
--border-color: var(--grey-10-a20);
|
||||
--secondary-color: var(--grey-10-a60);
|
||||
}
|
||||
}
|
||||
@@ -223,10 +223,6 @@ button.ghost:not(:hover) {
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.category:disabled {
|
||||
color: var(--secondary-color);
|
||||
}
|
||||
|
||||
#form > .category {
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
@@ -350,13 +346,13 @@ button.ghost:not(:hover) {
|
||||
.whitelist__item {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
height: 34px;
|
||||
flex-wrap: wrap;
|
||||
column-gap: 5px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.whitelist__item:nth-child(even) {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.whitelist__item--selected {
|
||||
@@ -365,7 +361,9 @@ button.ghost:not(:hover) {
|
||||
|
||||
.whitelist__title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
min-height: 34px;
|
||||
min-width: 0;
|
||||
padding: 4px;
|
||||
white-space: nowrap;
|
||||
@@ -389,6 +387,16 @@ button.ghost:not(:hover) {
|
||||
margin-inline-end: auto;
|
||||
}
|
||||
|
||||
.whitelist__expanded {
|
||||
border-top: 1px solid var(--border-color);
|
||||
display: grid;
|
||||
grid-template-columns: 80px minmax(0, 1fr);
|
||||
grid-column-gap: 10px;
|
||||
grid-row-gap: 5px;
|
||||
padding: 10px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.translator__tag {
|
||||
color: #0a84ff;
|
||||
display: inline-block;
|
||||
@@ -399,7 +407,9 @@ button.ghost:not(:hover) {
|
||||
vertical-align: text-top;
|
||||
}
|
||||
|
||||
#siteWhitelistCustomUserAgent {
|
||||
/* Option specific styles */
|
||||
#siteWhitelistCustomUserAgent,
|
||||
input[id^="customUserAgentString-"] {
|
||||
width: -moz-available;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user