diff --git a/app/Entities/Managers/PageContent.php b/app/Entities/Managers/PageContent.php index a787e5d99..7338a36b3 100644 --- a/app/Entities/Managers/PageContent.php +++ b/app/Entities/Managers/PageContent.php @@ -296,6 +296,24 @@ class PageContent $scriptElem->parentNode->removeChild($scriptElem); } + // Remove clickable links to JavaScript URI + $badLinks = $xPath->query('//*[contains(@href, \'javascript:\')]'); + foreach ($badLinks as $badLink) { + $badLink->parentNode->removeChild($badLink); + } + + // Remove forms with calls to JavaScript URI + $badForms = $xPath->query('//*[contains(@action, \'javascript:\')] | //*[contains(@formaction, \'javascript:\')]'); + foreach ($badForms as $badForm) { + $badForm->parentNode->removeChild($badForm); + } + + // Remove meta tag to prevent external redirects + $metaTags = $xPath->query('//meta[contains(@content, \'url\')]'); + foreach ($metaTags as $metaTag) { + $metaTag->parentNode->removeChild($metaTag); + } + // Remove data or JavaScript iFrames $badIframes = $xPath->query('//*[contains(@src, \'data:\')] | //*[contains(@src, \'javascript:\')] | //*[@srcdoc]'); foreach ($badIframes as $badIframe) { diff --git a/dev/docker/entrypoint.node.sh b/dev/docker/entrypoint.node.sh index e59e1e8a0..a8f33fd3d 100755 --- a/dev/docker/entrypoint.node.sh +++ b/dev/docker/entrypoint.node.sh @@ -5,4 +5,4 @@ set -e npm install npm rebuild node-sass -exec npm run watch \ No newline at end of file +SHELL=/bin/sh exec npm run watch diff --git a/package.json b/package.json index c3ca2add6..d5e93a31e 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "build:css:watch": "sass ./resources/sass:./public/dist --watch", "build:css:production": "sass ./resources/sass:./public/dist -s compressed", "build:js:dev": "esbuild --bundle ./resources/js/index.js --outfile=public/dist/app.js --sourcemap --target=es2019 --main-fields=module,main", - "build:js:watch": "chokidar \"./resources/**/*.js\" -c \"npm run build:js:dev\"", + "build:js:watch": "chokidar --initial \"./resources/**/*.js\" -c \"npm run build:js:dev\"", "build:js:production": "NODE_ENV=production esbuild --bundle ./resources/js/index.js --outfile=public/dist/app.js --sourcemap --target=es2019 --main-fields=module,main --minify", "build": "npm-run-all --parallel build:*:dev", "production": "npm-run-all --parallel build:*:production", diff --git a/tests/Entity/PageContentTest.php b/tests/Entity/PageContentTest.php index 99547fd17..e97df2c7e 100644 --- a/tests/Entity/PageContentTest.php +++ b/tests/Entity/PageContentTest.php @@ -159,6 +159,72 @@ class PageContentTest extends TestCase } + public function test_javascript_uri_links_are_removed() + { + $checks = [ + ''); + $pageView->assertElementNotContains('.page-content', 'href=javascript:'); + } + } + public function test_form_actions_with_javascript_are_removed() + { + $checks = [ + '
', + '
', + '
' + ]; + + $this->asEditor(); + $page = Page::first(); + + foreach ($checks as $check) { + $page->html = $check; + $page->save(); + + $pageView = $this->get($page->getUrl()); + $pageView->assertStatus(200); + $pageView->assertElementNotContains('.page-content', '