Implement receiver selector whitelist suggestion banner

This commit is contained in:
hensm
2022-04-16 12:02:19 +01:00
committed by Matt Hensman
parent 124a5eb92d
commit 1da709eb5e
14 changed files with 751 additions and 415 deletions

View File

@@ -4,17 +4,19 @@
import React, { Component } from "react";
import ReactDOM from "react-dom";
import knownApps from "../../cast/knownApps";
import knownApps, { KnownApp } from "../../cast/knownApps";
import options from "../../lib/options";
import messaging, { Message, Port } from "../../messaging";
import { getNextEllipsis } from "../../lib/utils";
import { RemoteMatchPattern } from "../../lib/matchPattern";
import { ReceiverDevice } from "../../types";
import {
ReceiverSelectionActionType,
ReceiverSelectorMediaType
} from "../../background/receiverSelector";
import { PageInfo } from "../../background/receiverSelector/ReceiverSelector";
const _ = browser.i18n.getMessage;
@@ -37,8 +39,14 @@ interface PopupAppState {
filePath?: string;
appId?: string;
pageInfo?: PageInfo;
mirroringEnabled: boolean;
userAgentWhitelistEnabled: boolean;
userAgentWhitelist: string[];
knownApp?: KnownApp;
isPageWhitelisted: boolean;
}
class PopupApp extends Component<PopupAppProps, PopupAppState> {
@@ -54,7 +62,10 @@ class PopupApp extends Component<PopupAppProps, PopupAppState> {
mediaType: ReceiverSelectorMediaType.App,
availableMediaTypes: ReceiverSelectorMediaType.App,
isLoading: false,
mirroringEnabled: false
mirroringEnabled: false,
userAgentWhitelistEnabled: true,
userAgentWhitelist: [],
isPageWhitelisted: false
};
// Store window ref
@@ -66,6 +77,7 @@ class PopupApp extends Component<PopupAppProps, PopupAppState> {
this.updateWindowHeight();
}).observe(document.body);
this.onAddToWhitelist = this.onAddToWhitelist.bind(this);
this.onSelectChange = this.onSelectChange.bind(this);
this.onCast = this.onCast.bind(this);
this.onStop = this.onStop.bind(this);
@@ -91,7 +103,8 @@ class PopupApp extends Component<PopupAppProps, PopupAppState> {
switch (message.subject) {
case "popup:init": {
this.setState({
appId: message.data?.appId
appId: message.data?.appId,
pageInfo: message.data?.pageInfo
});
break;
@@ -114,6 +127,8 @@ class PopupApp extends Component<PopupAppProps, PopupAppState> {
});
}
this.updateKnownApp();
break;
}
@@ -124,9 +139,15 @@ class PopupApp extends Component<PopupAppProps, PopupAppState> {
}
});
const opts = await options.getAll();
this.setState({
mirroringEnabled: await options.get("mirroringEnabled")
mirroringEnabled: opts.mirroringEnabled,
userAgentWhitelistEnabled: opts.userAgentWhitelistEnabled,
userAgentWhitelist: opts.userAgentWhitelist
});
this.updateKnownApp();
}
public componentDidUpdate() {
@@ -135,6 +156,58 @@ class PopupApp extends Component<PopupAppProps, PopupAppState> {
}, 1);
}
private updateKnownApp() {
const isAppMediaTypeAvailable = !!(
this.state.availableMediaTypes & ReceiverSelectorMediaType.App
);
let knownApp: Nullable<KnownApp> = null;
/**
* Check knownApps for an app with an ID matching the registered
* app on the target page.
* Or if there isn't an registered app, check for an app with a
* match pattern matching the target page URL.
*/
if (isAppMediaTypeAvailable && this.state.appId) {
knownApp = knownApps[this.state.appId];
} else if (this.state.pageInfo) {
const pageUrl = this.state.pageInfo.url;
for (const [, app] of Object.entries(knownApps)) {
if (!app.matches) {
continue;
}
const pattern = new RemoteMatchPattern(app.matches);
if (pattern.matches(pageUrl)) {
knownApp = app;
break;
}
}
}
let isPageWhitelisted = false;
/**
* Check if target page URL is whitelisted.
*/
if (this.state.pageInfo) {
for (const patternString of this.state.userAgentWhitelist) {
const pattern = new RemoteMatchPattern(patternString);
if (pattern.matches(this.state.pageInfo.url)) {
isPageWhitelisted = true;
break;
}
}
}
this.setState({
knownApp: knownApp ?? undefined,
isPageWhitelisted
});
}
public render() {
/*
@@ -166,9 +239,42 @@ class PopupApp extends Component<PopupAppProps, PopupAppState> {
this.state.availableMediaTypes & ReceiverSelectorMediaType.App
);
return (
<>
<div
className="whitelist-suggest"
hidden={
// If we don't know the app
!this.state.knownApp ||
// If the whitelist is disabled
!this.state.userAgentWhitelistEnabled ||
// If the whitelist is enabled, and the page is whitelisted
(this.state.userAgentWhitelistEnabled &&
this.state.isPageWhitelisted) ||
// If an app is already loaded on the page
isAppMediaTypeAvailable
}
>
<img src="photon_info.svg" />
{_(
"popupWhitelistNotWhitelisted",
this.state.knownApp?.name
)}
<button
onClick={() => {
if (!this.state.knownApp || !this.state.pageInfo) {
return;
}
this.onAddToWhitelist(
this.state.knownApp,
this.state.pageInfo
);
}}
>
{_("popupWhitelistAddToWhitelist")}
</button>
</div>
<div className="media-select">
<div className="media-select__label-cast">
{_("popupMediaSelectCastLabel")}
@@ -187,8 +293,7 @@ class PopupApp extends Component<PopupAppProps, PopupAppState> {
selected={isAppMediaTypeSelected}
disabled={!isAppMediaTypeAvailable}
>
{(this.state.appId &&
knownApps[this.state.appId]?.name) ??
{this.state.knownApp?.name ??
_("popupMediaTypeApp")}
</option>
@@ -248,6 +353,21 @@ class PopupApp extends Component<PopupAppProps, PopupAppState> {
);
}
private async onAddToWhitelist(app: KnownApp, pageInfo: PageInfo) {
if (!app.matches) {
return;
}
const whitelist = await options.get("userAgentWhitelist");
if (!whitelist.includes(app.matches)) {
whitelist.push(app.matches);
await options.set("userAgentWhitelist", whitelist);
await browser.tabs.reload(pageInfo.tabId);
window.close();
}
}
private onCast(receiver: ReceiverDevice) {
this.setState({
isLoading: true