From d8465b1aae0d5513f524fea81ffaba9c10b58093 Mon Sep 17 00:00:00 2001 From: Snazzah <7025343+Snazzah@users.noreply.github.com> Date: Mon, 30 Aug 2021 14:08:13 +0000 Subject: [PATCH] Add trusted link handling in renderer/prompt --- src/components/markdown/Renderer.tsx | 39 ++++++++++++------- .../modals/ExternalLinkPrompt.tsx | 16 ++++++++ 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/components/markdown/Renderer.tsx b/src/components/markdown/Renderer.tsx index 9fe876b4..5e84d2c1 100644 --- a/src/components/markdown/Renderer.tsx +++ b/src/components/markdown/Renderer.tsx @@ -18,13 +18,15 @@ import { useCallback, useContext } from "preact/hooks"; import { internalEmit } from "../../lib/eventEmitter"; +import { getState } from "../../redux"; + +import { useIntermediate } from "../../context/intermediate/Intermediate"; import { AppContext } from "../../context/revoltjs/RevoltClient"; import { generateEmoji } from "../common/Emoji"; import { emojiDictionary } from "../../assets/emojis"; import { MarkdownProps } from "./Markdown"; -import {useIntermediate} from "../../context/intermediate/Intermediate"; // TODO: global.d.ts file for defining globals declare global { @@ -35,9 +37,9 @@ declare global { const ALLOWED_ORIGINS = [ location.hostname, - 'app.revolt.chat', - 'nightly.revolt.chat', - 'local.revolt.chat', + "app.revolt.chat", + "nightly.revolt.chat", + "local.revolt.chat", ]; // Handler for code block copy. @@ -176,13 +178,16 @@ export default function Renderer({ content, disallowBigEmoji }: MarkdownProps) { element.removeAttribute("data-type"); element.removeAttribute("target"); - let internal; + let internal, + url: URL | null = null; const href = element.href; if (href) { try { - const url = new URL(href, location.href); + url = new URL(href, location.href); - if (ALLOWED_ORIGINS.includes(url.hostname)) { + if ( + ALLOWED_ORIGINS.includes(url.hostname) + ) { internal = true; element.addEventListener( "click", @@ -202,12 +207,20 @@ export default function Renderer({ content, disallowBigEmoji }: MarkdownProps) { if (!internal) { element.setAttribute("target", "_blank"); element.onclick = (ev) => { - ev.preventDefault(); - openScreen({ - id: "external_link_prompt", - link: href - }) - } + const { trustedLinks } = getState(); + if ( + !url || + !trustedLinks.domains?.includes( + url.hostname, + ) + ) { + ev.preventDefault(); + openScreen({ + id: "external_link_prompt", + link: href, + }); + } + }; } }, ); diff --git a/src/context/intermediate/modals/ExternalLinkPrompt.tsx b/src/context/intermediate/modals/ExternalLinkPrompt.tsx index b0f5e6df..4c90b325 100644 --- a/src/context/intermediate/modals/ExternalLinkPrompt.tsx +++ b/src/context/intermediate/modals/ExternalLinkPrompt.tsx @@ -1,6 +1,7 @@ import { Text } from "preact-i18n"; import Modal from "../../../components/ui/Modal"; +import { dispatch } from "../../../redux"; interface Props { onClose: () => void; @@ -29,6 +30,21 @@ export function ExternalLinkModal({ onClose, link }: Props) { confirmation: false, children: "Cancel", }, + { + onClick: () => { + try { + const url = new URL(link); + dispatch({ + type: "TRUSTED_LINKS_ADD_DOMAIN", + domain: url.hostname + }); + } catch(e) {} + window.open(link, "_blank"); + onClose(); + }, + plain: true, + children: "Trust this domain", + } ]}>
{link}