Add site-specific custom user agent option and new whitelist option UI

This commit is contained in:
hensm
2022-08-08 17:29:14 +01:00
parent 0c8106ffef
commit 23a8c0b62f
7 changed files with 194 additions and 41 deletions

View File

@@ -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",

View File

@@ -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,

View File

@@ -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>

View File

@@ -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>

View 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

View 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

View File

@@ -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;
}