Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 60 additions & 4 deletions ts/components/dialog/OpenUrlModal.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -14,14 +14,60 @@ 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;
overflow-y: auto;
text-align: center;
`;

function TrustToggle({ url }: { url: string }) {
const [active, setActive] = useState<boolean>(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 (
<PanelToggleButton
textElement={<span style={{ textAlign: 'start' }}>Trust {origin} links from now on</span>}
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();

Expand All @@ -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() {
Expand Down Expand Up @@ -74,6 +119,8 @@ export function OpenUrlModal(props: OpenUrlModalState) {
dataTestId="modal-description"
localizerProps={{ token: 'urlOpenDescription', asTag: 'span', url }}
/>
<SpacerXS />
<TrustToggle url={url} />
</StyledScrollDescriptionContainer>

<SpacerXS />
Expand All @@ -82,6 +129,15 @@ export function OpenUrlModal(props: OpenUrlModalState) {
}

export const showLinkVisitWarningDialog = (urlToOpen: string, dispatch: Dispatch<any>) => {
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,
Expand Down
20 changes: 20 additions & 0 deletions ts/util/urlHistory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<URLInteraction> {
if (!isValidUrl(url)) {
return [];
Expand Down