Explicitly deny bad URLs.

Fixes #252.
Handle embed untrusted links better.
This commit is contained in:
Paul 2021-09-25 10:54:32 +01:00
parent 66289911ba
commit 81379d6ec4
5 changed files with 26 additions and 22 deletions

View file

@ -1,5 +1,5 @@
.embed { .embed {
margin: .2em 0; margin: 0.2em 0;
iframe { iframe {
border: none; border: none;
@ -87,26 +87,30 @@
.footer { .footer {
font-size: 12px; font-size: 12px;
} }
img.image { img.image {
cursor: pointer; cursor: pointer;
object-fit: contain; object-fit: contain;
border-radius: var(--border-radius); border-radius: var(--border-radius);
} }
a {
cursor: pointer;
}
} }
} }
// TODO: unified actions css (see attachment.module.scss for other actions css) // TODO: unified actions css (see attachment.module.scss for other actions css)
.actions { .actions {
display: grid; display: grid;
grid-template: grid-template:
"name open" auto "name open" auto
"size open" auto "size open" auto
/ minmax(20px, 1fr) min-content; / minmax(20px, 1fr) min-content;
align-items: center; align-items: center;
column-gap: 12px; column-gap: 12px;
width: 100%; width: 100%;
padding: 8px; padding: 8px;
overflow: none; overflow: none;
@ -119,7 +123,7 @@
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
} }
.filesize { .filesize {
grid-area: size; grid-area: size;

View file

@ -111,14 +111,11 @@ export default function Embed({ embed }: Props) {
{embed.title && ( {embed.title && (
<span> <span>
<a <a
onClick={(e) => onMouseDown={(ev) =>
openLink(e.currentTarget.href) && (ev.button === 0 || ev.button === 1) &&
e.preventDefault() openLink(embed.url)
} }
href={embed.url} className={styles.title}>
target={"_blank"}
className={styles.title}
rel="noreferrer">
{embed.title} {embed.title}
</a> </a>
</span> </span>
@ -159,9 +156,7 @@ export default function Embed({ embed }: Props) {
frameBorder="0" frameBorder="0"
loading="lazy" loading="lazy"
onClick={() => openScreen({ id: "image_viewer", embed })} onClick={() => openScreen({ id: "image_viewer", embed })}
onMouseDown={(ev) => onMouseDown={(ev) => ev.button === 1 && openLink(embed.url)}
ev.button === 1 && window.open(embed.url, "_blank")
}
/> />
); );
} }

View file

@ -151,11 +151,9 @@ export default function Intermediate(props: Props) {
id: "external_link_prompt", id: "external_link_prompt",
link: link.href, link: link.href,
}); });
} else {
return true; window.open(link.href, "_blank", "noreferrer");
} }
return false;
} }
} }

View file

@ -4,12 +4,16 @@ import { dispatch } from "../../../redux";
import Modal from "../../../components/ui/Modal"; import Modal from "../../../components/ui/Modal";
import { useIntermediate } from "../Intermediate";
interface Props { interface Props {
onClose: () => void; onClose: () => void;
link: string; link: string;
} }
export function ExternalLinkModal({ onClose, link }: Props) { export function ExternalLinkModal({ onClose, link }: Props) {
const { openLink } = useIntermediate();
return ( return (
<Modal <Modal
visible={true} visible={true}
@ -18,7 +22,7 @@ export function ExternalLinkModal({ onClose, link }: Props) {
actions={[ actions={[
{ {
onClick: () => { onClick: () => {
window.open(link, "_blank", "noreferrer"); openLink(link);
onClose(); onClose();
}, },
confirmation: true, confirmation: true,
@ -40,7 +44,8 @@ export function ExternalLinkModal({ onClose, link }: Props) {
domain: url.hostname, domain: url.hostname,
}); });
} catch (e) {} } catch (e) {}
window.open(link, "_blank", "noreferrer");
openLink(link);
onClose(); onClose();
}, },
plain: true, plain: true,

View file

@ -52,7 +52,9 @@ export function determineLink(href?: string): LinkType {
} catch (err) {} } catch (err) {}
if (!internal && url) { if (!internal && url) {
return { type: "external", href, url }; if (url.protocol !== "javascript") {
return { type: "external", href, url };
}
} }
} }