diff --git a/packages/core/src/dom_components/model/ComponentVideo.ts b/packages/core/src/dom_components/model/ComponentVideo.ts index 4288d25c4..be5fb6a49 100644 --- a/packages/core/src/dom_components/model/ComponentVideo.ts +++ b/packages/core/src/dom_components/model/ComponentVideo.ts @@ -9,6 +9,7 @@ const yt = 'yt'; const vi = 'vi'; const ytnc = 'ytnc'; const defProvider = 'so'; +export const YT_REFERRER_POLICY = 'strict-origin-when-cross-origin'; const hasParam = (value: string) => value && value !== '0'; @@ -65,6 +66,24 @@ export default class ComponentVideo extends ComponentImage { } } + updateProviderAttributes() { + const { provider, attributes = {} } = this.attributes; + const attrs = { ...attributes }; + let hasChanges = false; + + if (provider === yt || provider === ytnc) { + if (!isDef(attrs.referrerpolicy)) { + attrs.referrerpolicy = YT_REFERRER_POLICY; + hasChanges = true; + } + } else if (attrs.referrerpolicy === YT_REFERRER_POLICY) { + delete attrs.referrerpolicy; + hasChanges = true; + } + + hasChanges && this.setAttributes(attrs); + } + /** * Update traits by provider * @private @@ -88,6 +107,7 @@ export default class ComponentVideo extends ComponentImage { traits = this.getSourceTraits(); } + this.updateProviderAttributes(); this.set({ tagName }, { silent: true }); // avoid break in view // @ts-ignore this.set({ traits }); diff --git a/packages/core/src/dom_components/view/ComponentVideoView.ts b/packages/core/src/dom_components/view/ComponentVideoView.ts index 68f0063d2..2bc8e036c 100644 --- a/packages/core/src/dom_components/view/ComponentVideoView.ts +++ b/packages/core/src/dom_components/view/ComponentVideoView.ts @@ -1,4 +1,4 @@ -import ComponentVideo from '../model/ComponentVideo'; +import ComponentVideo, { YT_REFERRER_POLICY } from '../model/ComponentVideo'; import ComponentImageView from './ComponentImageView'; import ComponentView from './ComponentView'; @@ -117,8 +117,7 @@ export default class ComponentVideoView extends ComponentImageView { + const videoId = 'jNQXAC9IVRw'; + let testEditor: ReturnType; + + beforeEach(() => { + testEditor = setupTestEditor(); + }); + + const appendVideo = (provider: 'yt' | 'ytnc') => + testEditor.editor.getWrapper()!.append({ + type: 'video', + provider, + videoId, + })[0]; + + afterEach(() => { + testEditor.editor.destroy(); + }); + + describe('YouTube', () => { + test.each([ + ['yt', 'https://www.youtube.com/embed/'], + ['ytnc', 'https://www.youtube-nocookie.com/embed/'], + ] as const)('renders %s with the required referrer policy', (provider, srcPrefix) => { + const component = appendVideo(provider); + const iframe = component.getEl()?.querySelector('iframe'); + + expect(component.getAttributes().referrerpolicy).toEqual(YT_REFERRER_POLICY); + expect(component.toHTML()).toContain(`referrerpolicy="${YT_REFERRER_POLICY}"`); + expect(iframe?.getAttribute('referrerpolicy')).toEqual(YT_REFERRER_POLICY); + expect(iframe?.getAttribute('src')).toContain(srcPrefix); + }); + + test('removes the default referrer policy when switching away from YouTube', () => { + const component = appendVideo('yt'); + + component.set('provider', 'vi'); + + expect(component.getAttributes().referrerpolicy).toBeUndefined(); + }); + }); +});