diff --git a/ts/components/dialog/OpenUrlModal.tsx b/ts/components/dialog/OpenUrlModal.tsx index a610f2b720..28cabad7ba 100644 --- a/ts/components/dialog/OpenUrlModal.tsx +++ b/ts/components/dialog/OpenUrlModal.tsx @@ -1,6 +1,6 @@ import { shell } from 'electron'; import { isEmpty } from 'lodash'; -import { Dispatch } from 'react'; +import { Dispatch, useCallback, useMemo, useState } from 'react'; import { useDispatch } from 'react-redux'; import styled from 'styled-components'; import { MessageInteraction } from '../../interactions'; @@ -14,7 +14,13 @@ import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/S import { SpacerXS } from '../basic/Text'; import { ModalDescription } from './shared/ModalDescriptionContainer'; import { tr } from '../../localization/localeTools'; -import { registerUrlInteraction, URLInteraction } from '../../util/urlHistory'; +import { + getUrlInteractionsForUrl, + registerUrlInteraction, + removeUrlInteraction, + URLInteraction, +} from '../../util/urlHistory'; +import { PanelToggleButton } from '../buttons/panel/PanelToggleButton'; const StyledScrollDescriptionContainer = styled.div` max-height: 150px; @@ -22,6 +28,46 @@ const StyledScrollDescriptionContainer = styled.div` text-align: center; `; +function TrustToggle({ url }: { url: string }) { + const [active, setActive] = useState(false); + + const origin = useMemo(() => { + if (URL.canParse(url)) { + return new URL(url).origin; + } + return null; + }, [url]); + + const onClick = useCallback(async () => { + if (!origin) { + return; + } + const newValue = !active; + + if (newValue) { + await registerUrlInteraction(origin, URLInteraction.TRUST); + } else { + await removeUrlInteraction(origin, URLInteraction.TRUST); + } + setActive(newValue); + }, [origin, active]); + + return ( + Trust {origin} links from now on} + active={active} + onClick={onClick} + toggleDataTestId={'enable-typing-indicators-settings-toggle'} + rowDataTestId={'enable-typing-indicators-settings-row'} + /> + ); +} + +async function openUrl(url: string) { + void shell.openExternal(url); + await registerUrlInteraction(url, URLInteraction.OPEN); +} + export function OpenUrlModal(props: OpenUrlModalState) { const dispatch = useDispatch(); @@ -35,9 +81,8 @@ export function OpenUrlModal(props: OpenUrlModalState) { } async function onClickOpen() { - void shell.openExternal(url); + await openUrl(url); onClose(); - await registerUrlInteraction(url, URLInteraction.OPEN); } async function onClickCopy() { @@ -74,6 +119,8 @@ export function OpenUrlModal(props: OpenUrlModalState) { dataTestId="modal-description" localizerProps={{ token: 'urlOpenDescription', asTag: 'span', url }} /> + + @@ -82,6 +129,15 @@ export function OpenUrlModal(props: OpenUrlModalState) { } export const showLinkVisitWarningDialog = (urlToOpen: string, dispatch: Dispatch) => { + const urlOrigin = URL.canParse(urlToOpen) ? new URL(urlToOpen).origin : null; + if (urlOrigin) { + const urlInteractions = getUrlInteractionsForUrl(urlOrigin); + if (urlInteractions.includes(URLInteraction.TRUST)) { + void openUrl(urlToOpen); + return; + } + } + dispatch( updateOpenUrlModal({ urlToOpen, diff --git a/ts/util/urlHistory.ts b/ts/util/urlHistory.ts index 264f4dcb1c..41241df4b1 100644 --- a/ts/util/urlHistory.ts +++ b/ts/util/urlHistory.ts @@ -68,6 +68,26 @@ export async function registerUrlInteraction(url: string, interaction: URLIntera await Storage.put(SettingsKey.urlInteractions, interactions); } +export async function removeUrlInteraction(url: string, interaction: URLInteraction) { + if (!isValidUrl(url)) { + return; + } + + const interactions = getUrlInteractions(); + const idx = interactions.findIndex(item => item.url === url); + + if (idx !== -1) { + const interactionIdx = interactions[idx].interactions.findIndex(item => item === interaction); + if (interactionIdx !== -1) { + interactions[idx].interactions.splice(interactionIdx); + if (!interactions[idx].interactions.length) { + interactions.splice(idx); + } + await Storage.put(SettingsKey.urlInteractions, interactions); + } + } +} + export function getUrlInteractionsForUrl(url: string): Array { if (!isValidUrl(url)) { return [];