diff --git a/app/cypress/e2e/iframe_param_absent.spec.js b/app/cypress/e2e/iframe_param_absent.spec.js new file mode 100644 index 0000000..1fe8150 --- /dev/null +++ b/app/cypress/e2e/iframe_param_absent.spec.js @@ -0,0 +1,31 @@ +describe('A page without an iframe parameter', () => { + beforeEach(() => { + cy.visit('/'); + }); + + it('stays out of fullscreen', () => { + cy.get('body').should('not.have.class', 'fullscreen'); + }); + + it('frames nothing', () => { + cy.get('#main').find('iframe').should('not.exist'); + cy.url().should('not.include', 'iframe='); + }); + + it('never grows an iframe parameter out of its own URL', () => { + cy.wait(2000); + + cy.url().then((url) => { + expect((url.match(/iframe/g) || []).length, 'iframe parameters').to.equal(0); + }); + }); + + it('treats an absent URL as unsafe', () => { + cy.window().then((win) => { + expect(win.safeUrl(null), 'null').to.equal(null); + expect(win.safeUrl(''), 'empty string').to.equal(null); + expect(win.safeUrl('javascript:alert(1)'), 'script URL').to.equal(null); + expect(win.safeUrl('/de/'), 'relative path').to.equal(`${win.location.origin}/de/`); + }); + }); +}); diff --git a/app/static/js/iframe.js b/app/static/js/iframe.js index efe9e87..422f80c 100644 --- a/app/static/js/iframe.js +++ b/app/static/js/iframe.js @@ -14,8 +14,8 @@ function allowedIframeUrl(url) { // === Auto-open iframe if URL parameter is present === window.addEventListener('DOMContentLoaded', () => { - const paramUrl = allowedIframeUrl(new URLSearchParams(window.location.search).get('iframe')); - if (paramUrl) { + const paramUrl = new URLSearchParams(window.location.search).get('iframe'); + if (paramUrl && allowedIframeUrl(paramUrl)) { currentIframeUrl = paramUrl; enterFullscreen(); openIframe(paramUrl); @@ -83,8 +83,8 @@ function openIframe(url) { // URL-State pushen var newUrl = new URL(window.location); - newUrl.searchParams.set('iframe', target); - window.history.pushState({ iframe: target }, '', newUrl); + newUrl.searchParams.set('iframe', url); + window.history.pushState({ iframe: url }, '', newUrl); }); } diff --git a/app/static/js/modal.js b/app/static/js/modal.js index ea928f4..03c17c8 100644 --- a/app/static/js/modal.js +++ b/app/static/js/modal.js @@ -8,8 +8,11 @@ function t(source) { const SAFE_URL_SCHEMES = ['http:', 'https:', 'mailto:']; function safeUrl(url) { + if (url == null || String(url) === '') { + return null; + } try { - const parsed = new URL(String(url == null ? '' : url), window.location.href); + const parsed = new URL(String(url), window.location.href); return SAFE_URL_SCHEMES.includes(parsed.protocol) ? parsed.href : null; } catch (error) { return null;