Chat+ link previews: players for Vimeo and SoundCloud too, image links show the image
The YouTube-only field becomes a general embed address, made natively only for the frame hosts X's chat CSP allows (www.youtube.com, player.vimeo.com, w.soundcloud.com) and re-checked in the page. A link to an image previews the image itself. YouTube's thumbnail comes as data.
This commit is contained in:
parent
328264bfe1
commit
27a3b233f0
7 changed files with 115 additions and 32 deletions
|
|
@ -22,8 +22,13 @@ test('link previews: a native answer is checked again: plain fields, capped, dat
|
|||
assert.equal(good.image, 'data:image/png;base64,iVBORw0KGgo=');
|
||||
assert.equal(asPreview({ url: 'https://a.example/', title: 't', image: 'data:image/svg+xml;base64,PHN2Zz4=' })?.image, undefined, 'no SVG');
|
||||
assert.equal(asPreview({ url: 'https://a.example/', title: 't', image: 'https://tracker.example/p.gif' })?.image, undefined, 'no remote image');
|
||||
assert.equal(asPreview({ url: 'https://youtu.be/x', title: 't', youtube: 'dQw4w9WgXcQ' })?.youtube, 'dQw4w9WgXcQ');
|
||||
assert.equal(asPreview({ url: 'https://youtu.be/x', title: 't', youtube: 'a"onload="x' })?.youtube, undefined);
|
||||
for (const embed of [
|
||||
'https://www.youtube.com/embed/dQw4w9WgXcQ?autoplay=1&rel=0',
|
||||
'https://player.vimeo.com/video/76979871?autoplay=1',
|
||||
'https://w.soundcloud.com/player/?url=https%3A%2F%2Fsoundcloud.com%2Fcrtkafa%2Fsets%2Falbums&auto_play=true&visual=true',
|
||||
]) assert.equal(asPreview({ url: 'https://a.example/', title: 't', embed })?.embed, embed, embed);
|
||||
for (const embed of ['https://evil.example/embed', 'https://www.youtube.com/embed/a"onload="x', 'javascript:alert(1)', 'https://open.spotify.com/embed/track/1'])
|
||||
assert.equal(asPreview({ url: 'https://a.example/', title: 't', embed })?.embed, undefined, embed);
|
||||
assert.equal(asPreview({ url: 'javascript:alert(1)', title: 't' }), null, 'the link itself is re-checked');
|
||||
assert.equal(asPreview({ url: 'https://a.example/', title: '' }), null, 'nothing to show, no card');
|
||||
assert.equal(asPreview('nope'), null);
|
||||
|
|
@ -39,10 +44,10 @@ test('link previews: X\'s bare card (a host name and an icon) is replaced; a car
|
|||
assert.equal(isBareCard(anchor('')), false);
|
||||
});
|
||||
|
||||
test('link previews: page text only through textContent, the player only on YouTube\'s host X allows, no request from the page', () => {
|
||||
test('link previews: page text only through textContent, players only on the hosts X allows as frames, no request from the page', () => {
|
||||
const source = readFileSync(new URL('../src/areas/chat/linkPreviews.ts', import.meta.url), 'utf8');
|
||||
assert.doesNotMatch(source, /innerHTML|insertAdjacentHTML|outerHTML|document\.write/);
|
||||
assert.doesNotMatch(source, /\bfetch\(|XMLHttpRequest|WebSocket|sendBeacon/);
|
||||
for (const match of source.matchAll(/https:\/\/([a-z0-9.-]+)\//g)) assert.ok(['i.ytimg.com', 'www.youtube.com'].includes(match[1]!), match[1]);
|
||||
assert.doesNotMatch(source, /i\.ytimg\.com/, 'thumbnails come as data from native code');
|
||||
assert.match(source, /rel = 'noopener noreferrer'/);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue