Stories: Only render text link if it's a valid URL

This commit is contained in:
Scott Nonnenberg 2024-09-14 07:34:48 +10:00 committed by GitHub
parent 2ee7b18d33
commit 733c5b598f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 40 additions and 3 deletions

View file

@ -12,7 +12,7 @@ import { Emojify } from './conversation/Emojify';
import { StoryLinkPreview } from './StoryLinkPreview'; import { StoryLinkPreview } from './StoryLinkPreview';
import { TextAttachmentStyleType } from '../types/Attachment'; import { TextAttachmentStyleType } from '../types/Attachment';
import { count } from '../util/grapheme'; import { count } from '../util/grapheme';
import { getSafeDomain } from '../types/LinkPreview'; import { isValidLink, getSafeDomain } from '../types/LinkPreview';
import { getFontNameByTextScript } from '../util/getFontNameByTextScript'; import { getFontNameByTextScript } from '../util/getFontNameByTextScript';
import { import {
COLOR_WHITE_INT, COLOR_WHITE_INT,
@ -197,7 +197,7 @@ export const TextAttachment = forwardRef<HTMLTextAreaElement, PropsType>(
the story, but it must be positioned using the scaled offset the story, but it must be positioned using the scaled offset
*/} */}
{textAttachment.preview && {textAttachment.preview &&
textAttachment.preview.url && isValidLink(textAttachment.preview.url) &&
linkPreviewOffsetTop && linkPreviewOffsetTop &&
!isThumbnail && ( !isThumbnail && (
<a <a

View file

@ -5,12 +5,36 @@ import { assert } from 'chai';
import { import {
findLinks, findLinks,
isLinkSneaky,
isValidLink,
shouldLinkifyMessage, shouldLinkifyMessage,
shouldPreviewHref, shouldPreviewHref,
isLinkSneaky,
} from '../../types/LinkPreview'; } from '../../types/LinkPreview';
describe('Link previews', () => { describe('Link previews', () => {
describe('#isValidLink', () => {
it('returns false for random, non-https URLs', () => {
assert.isFalse(isValidLink(''));
assert.isFalse(isValidLink('signal.com'));
assert.isFalse(isValidLink('signal.org'));
assert.isFalse(isValidLink('https'));
assert.isFalse(isValidLink('https://'));
assert.isFalse(isValidLink('https://bad url'));
assert.isFalse(isValidLink('http://signal.org'));
});
it('returns true for https:// URLs', () => {
assert.isTrue(isValidLink('https://signal.org'));
assert.isTrue(isValidLink('https://somewhere.someplace.signal.org/'));
assert.isTrue(isValidLink('https://signal.org/something/another/#thing'));
assert.isTrue(
isValidLink(
'https://signal.org/something/another/?one=two&three=four#thing'
)
);
});
});
describe('#shouldPreviewHref', () => { describe('#shouldPreviewHref', () => {
it('returns false for invalid URLs', () => { it('returns false for invalid URLs', () => {
assert.isFalse(shouldPreviewHref('')); assert.isFalse(shouldPreviewHref(''));

View file

@ -48,6 +48,19 @@ export type AddLinkPreviewOptionsType = Readonly<{
const linkify = LinkifyIt(); const linkify = LinkifyIt();
export function isValidLink(maybeUrl: string | undefined): boolean {
if (maybeUrl == null) {
return false;
}
try {
const url = new URL(maybeUrl);
return url.protocol === 'https:';
} catch (_error) {
return false;
}
}
export function shouldPreviewHref(href: string): boolean { export function shouldPreviewHref(href: string): boolean {
const url = maybeParseUrl(href); const url = maybeParseUrl(href);
return Boolean( return Boolean(