X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/a6633642232efd164d4708967ab59e498fbff896..refs/pull/3000/head:/tests/Entity/PageContentTest.php
diff --git a/tests/Entity/PageContentTest.php b/tests/Entity/PageContentTest.php
index 6d5200794..ca2a24131 100644
--- a/tests/Entity/PageContentTest.php
+++ b/tests/Entity/PageContentTest.php
@@ -1,16 +1,22 @@
-id)->first();
+ $page = Page::query()->first();
+ $secondPage = Page::query()->where('id', '!=', $page->id)->first();
$secondPage->html = "
Hello, This is a test
This is a second block of content
";
$secondPage->save();
@@ -38,8 +44,8 @@ class PageContentTest extends TestCase
public function test_saving_page_with_includes()
{
- $page = Page::first();
- $secondPage = Page::where('id', '!=', $page->id)->first();
+ $page = Page::query()->first();
+ $secondPage = Page::query()->where('id', '!=', $page->id)->first();
$this->asEditor();
$includeTag = '{{@' . $secondPage->id . '}}';
@@ -56,8 +62,8 @@ class PageContentTest extends TestCase
public function test_page_includes_do_not_break_tables()
{
- $page = Page::first();
- $secondPage = Page::where('id', '!=', $page->id)->first();
+ $page = Page::query()->first();
+ $secondPage = Page::query()->where('id', '!=', $page->id)->first();
$content = '';
$secondPage->html = $content;
@@ -93,7 +99,7 @@ class PageContentTest extends TestCase
public function test_page_content_scripts_removed_by_default()
{
$this->asEditor();
- $page = Page::first();
+ $page = Page::query()->first();
$script = 'abc123abc123';
$page->html = "escape {$script}";
$page->save();
@@ -116,7 +122,7 @@ class PageContentTest extends TestCase
];
$this->asEditor();
- $page = Page::first();
+ $page = Page::query()->first();
foreach ($checks as $check) {
$page->html = $check;
@@ -127,21 +133,32 @@ class PageContentTest extends TestCase
$pageView->assertElementNotContains('.page-content', '');
}
-
}
- public function test_iframe_js_and_base64_urls_are_removed()
+ public function test_js_and_base64_src_urls_are_removed()
{
$checks = [
'',
+ '',
+ '',
'',
'',
+ '',
'',
- ''
+ '
',
+ '
',
+ '
',
+ '
',
+ '
',
+ '
',
+ '
',
+ '',
+ '',
+ '
',
];
$this->asEditor();
- $page = Page::first();
+ $page = Page::query()->first();
foreach ($checks as $check) {
$page->html = $check;
@@ -150,24 +167,26 @@ class PageContentTest extends TestCase
$pageView = $this->get($page->getUrl());
$pageView->assertStatus(200);
$pageView->assertElementNotContains('.page-content', '');
$pageView->assertElementNotContains('.page-content', 'src=');
$pageView->assertElementNotContains('.page-content', 'javascript:');
$pageView->assertElementNotContains('.page-content', 'data:');
$pageView->assertElementNotContains('.page-content', 'base64');
}
-
}
public function test_javascript_uri_links_are_removed()
{
$checks = [
'');
+ $pageView->assertElementNotContains('.page-content', 'assertElementNotContains('.page-content', 'href=javascript:');
}
}
+
public function test_form_actions_with_javascript_are_removed()
{
$checks = [
'',
+ '',
'',
- ''
+ '',
+ '',
];
$this->asEditor();
- $page = Page::first();
+ $page = Page::query()->first();
foreach ($checks as $check) {
$page->html = $check;
@@ -203,15 +225,17 @@ class PageContentTest extends TestCase
$pageView->assertElementNotContains('.page-content', 'formaction=javascript:');
}
}
-
+
public function test_metadata_redirects_are_removed()
{
$checks = [
'',
+ '',
+ '',
];
$this->asEditor();
- $page = Page::first();
+ $page = Page::query()->first();
foreach ($checks as $check) {
$page->html = $check;
@@ -225,10 +249,11 @@ class PageContentTest extends TestCase
$pageView->assertElementNotContains('.page-content', 'external_url');
}
}
+
public function test_page_inline_on_attributes_removed_by_default()
{
$this->asEditor();
- $page = Page::first();
+ $page = Page::query()->first();
$script = 'Hello
';
$page->html = "escape {$script}";
$page->save();
@@ -243,15 +268,17 @@ class PageContentTest extends TestCase
{
$checks = [
'Hello
',
+ 'Hello
',
'Lorem ipsum dolor sit amet.
Hello
',
'Lorem ipsum dolor sit amet.
Hello
',
'Lorem ipsum dolor sit amet.
Hello
',
'Lorem ipsum dolor sit amet.
Hello
',
'xss link\',
];
$this->asEditor();
- $page = Page::first();
+ $page = Page::query()->first();
foreach ($checks as $check) {
$page->html = $check;
@@ -261,13 +288,12 @@ class PageContentTest extends TestCase
$pageView->assertStatus(200);
$pageView->assertElementNotContains('.page-content', 'onclick');
}
-
}
public function test_page_content_scripts_show_when_configured()
{
$this->asEditor();
- $page = Page::first();
+ $page = Page::query()->first();
config()->push('app.allow_content_scripts', 'true');
$script = 'abc123abc123';
@@ -279,10 +305,32 @@ class PageContentTest extends TestCase
$pageView->assertDontSee('abc123abc123');
}
+ public function test_svg_xlink_hrefs_are_removed()
+ {
+ $checks = [
+ '',
+ '',
+ ];
+
+ $this->asEditor();
+ $page = Page::query()->first();
+
+ foreach ($checks as $check) {
+ $page->html = $check;
+ $page->save();
+
+ $pageView = $this->get($page->getUrl());
+ $pageView->assertStatus(200);
+ $pageView->assertElementNotContains('.page-content', 'alert');
+ $pageView->assertElementNotContains('.page-content', 'xlink:href');
+ $pageView->assertElementNotContains('.page-content', 'application/xml');
+ }
+ }
+
public function test_page_inline_on_attributes_show_if_configured()
{
$this->asEditor();
- $page = Page::first();
+ $page = Page::query()->first();
config()->push('app.allow_content_scripts', 'true');
$script = 'Hello
';
@@ -297,14 +345,14 @@ class PageContentTest extends TestCase
public function test_duplicate_ids_does_not_break_page_render()
{
$this->asEditor();
- $pageA = Page::first();
+ $pageA = Page::query()->first();
$pageB = Page::query()->where('id', '!=', $pageA->id)->first();
$content = ' ';
$pageA->html = $content;
$pageA->save();
- $pageB->html = ' {{@'. $pageA->id .'#test}}
';
+ $pageB->html = ' {{@' . $pageA->id . '#test}}
';
$pageB->save();
$pageView = $this->get($pageB->getUrl());
@@ -314,33 +362,33 @@ class PageContentTest extends TestCase
public function test_duplicate_ids_fixed_on_page_save()
{
$this->asEditor();
- $page = Page::first();
+ $page = Page::query()->first();
$content = '';
$pageSave = $this->put($page->getUrl(), [
- 'name' => $page->name,
- 'html' => $content,
- 'summary' => ''
+ 'name' => $page->name,
+ 'html' => $content,
+ 'summary' => '',
]);
$pageSave->assertRedirect();
- $updatedPage = Page::where('id', '=', $page->id)->first();
- $this->assertEquals(substr_count($updatedPage->html, "bkmrk-test\""), 1);
+ $updatedPage = Page::query()->where('id', '=', $page->id)->first();
+ $this->assertEquals(substr_count($updatedPage->html, 'bkmrk-test"'), 1);
}
public function test_anchors_referencing_non_bkmrk_ids_rewritten_after_save()
{
$this->asEditor();
- $page = Page::first();
+ $page = Page::query()->first();
$content = 'test
link
';
$this->put($page->getUrl(), [
- 'name' => $page->name,
- 'html' => $content,
- 'summary' => ''
+ 'name' => $page->name,
+ 'html' => $content,
+ 'summary' => '',
]);
- $updatedPage = Page::where('id', '=', $page->id)->first();
+ $updatedPage = Page::query()->where('id', '=', $page->id)->first();
$this->assertStringContainsString('id="bkmrk-test"', $updatedPage->html);
$this->assertStringContainsString('href="#bkmrk-test"', $updatedPage->html);
}
@@ -354,21 +402,21 @@ class PageContentTest extends TestCase
$this->assertCount(3, $navMap);
$this->assertArrayMapIncludes([
'nodeName' => 'h1',
- 'link' => '#testa',
- 'text' => 'Hello',
- 'level' => 1,
+ 'link' => '#testa',
+ 'text' => 'Hello',
+ 'level' => 1,
], $navMap[0]);
$this->assertArrayMapIncludes([
'nodeName' => 'h2',
- 'link' => '#testb',
- 'text' => 'There',
- 'level' => 2,
+ 'link' => '#testb',
+ 'text' => 'There',
+ 'level' => 2,
], $navMap[1]);
$this->assertArrayMapIncludes([
'nodeName' => 'h3',
- 'link' => '#testc',
- 'text' => 'Donkey',
- 'level' => 3,
+ 'link' => '#testc',
+ 'text' => 'Donkey',
+ 'level' => 3,
], $navMap[2]);
}
@@ -381,8 +429,8 @@ class PageContentTest extends TestCase
$this->assertCount(1, $navMap);
$this->assertArrayMapIncludes([
'nodeName' => 'h1',
- 'link' => '#testa',
- 'text' => 'Hello'
+ 'link' => '#testa',
+ 'text' => 'Hello',
], $navMap[0]);
}
@@ -395,15 +443,15 @@ class PageContentTest extends TestCase
$this->assertCount(3, $navMap);
$this->assertArrayMapIncludes([
'nodeName' => 'h4',
- 'level' => 1,
+ 'level' => 1,
], $navMap[0]);
$this->assertArrayMapIncludes([
'nodeName' => 'h5',
- 'level' => 2,
+ 'level' => 2,
], $navMap[1]);
$this->assertArrayMapIncludes([
'nodeName' => 'h6',
- 'level' => 3,
+ 'level' => 3,
], $navMap[2]);
}
@@ -432,7 +480,7 @@ class PageContentTest extends TestCase
| Paragraph | Text |';
$this->put($page->getUrl(), [
'name' => $page->name, 'markdown' => $content,
- 'html' => '', 'summary' => ''
+ 'html' => '', 'summary' => '',
]);
$page->refresh();
@@ -451,7 +499,7 @@ class PageContentTest extends TestCase
- [x] Item b';
$this->put($page->getUrl(), [
'name' => $page->name, 'markdown' => $content,
- 'html' => '', 'summary' => ''
+ 'html' => '', 'summary' => '',
]);
$page->refresh();
@@ -459,7 +507,8 @@ class PageContentTest extends TestCase
$this->assertStringContainsString('type="checkbox"', $page->html);
$pageView = $this->get($page->getUrl());
- $pageView->assertElementExists('.page-content input[type=checkbox]');
+ $pageView->assertElementExists('.page-content li.task-list-item input[type=checkbox]');
+ $pageView->assertElementExists('.page-content li.task-list-item input[type=checkbox][checked=checked]');
}
public function test_page_markdown_strikethrough_rendering()
@@ -470,7 +519,7 @@ class PageContentTest extends TestCase
$content = '~~some crossed out text~~';
$this->put($page->getUrl(), [
'name' => $page->name, 'markdown' => $content,
- 'html' => '', 'summary' => ''
+ 'html' => '', 'summary' => '',
]);
$page->refresh();
@@ -479,4 +528,119 @@ class PageContentTest extends TestCase
$pageView = $this->get($page->getUrl());
$pageView->assertElementExists('.page-content p > s');
}
+
+ public function test_page_markdown_single_html_comment_saving()
+ {
+ $this->asEditor();
+ $page = Page::query()->first();
+
+ $content = '';
+ $this->put($page->getUrl(), [
+ 'name' => $page->name, 'markdown' => $content,
+ 'html' => '', 'summary' => '',
+ ]);
+
+ $page->refresh();
+ $this->assertStringMatchesFormat($content, $page->html);
+
+ $pageView = $this->get($page->getUrl());
+ $pageView->assertStatus(200);
+ $pageView->assertSee($content);
+ }
+
+ public function test_base64_images_get_extracted_from_page_content()
+ {
+ $this->asEditor();
+ $page = Page::query()->first();
+
+ $this->put($page->getUrl(), [
+ 'name' => $page->name, 'summary' => '',
+ 'html' => 'test
',
+ ]);
+
+ $page->refresh();
+ $this->assertStringMatchesFormat('%Atest
%A
%A', $page->html);
+
+ $matches = [];
+ preg_match('/src="https:\/\/p.rizon.top:443\/http\/localhost(.*?)"/', $page->html, $matches);
+ $imagePath = $matches[1];
+ $imageFile = public_path($imagePath);
+ $this->assertEquals(base64_decode($this->base64Jpeg), file_get_contents($imageFile));
+
+ $this->deleteImage($imagePath);
+ }
+
+ public function test_base64_images_get_extracted_when_containing_whitespace()
+ {
+ $this->asEditor();
+ $page = Page::query()->first();
+
+ $base64PngWithWhitespace = "iVBORw0KGg\noAAAANSUhE\tUgAAAAEAAAA BCA YAAAAfFcSJAAA\n\t ACklEQVR4nGMAAQAABQAB";
+ $base64PngWithoutWhitespace = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQAB';
+ $this->put($page->getUrl(), [
+ 'name' => $page->name, 'summary' => '',
+ 'html' => 'test
',
+ ]);
+
+ $page->refresh();
+ $this->assertStringMatchesFormat('%Atest
%A
%A', $page->html);
+
+ $matches = [];
+ preg_match('/src="https:\/\/p.rizon.top:443\/http\/localhost(.*?)"/', $page->html, $matches);
+ $imagePath = $matches[1];
+ $imageFile = public_path($imagePath);
+ $this->assertEquals(base64_decode($base64PngWithoutWhitespace), file_get_contents($imageFile));
+
+ $this->deleteImage($imagePath);
+ }
+
+ public function test_base64_images_within_html_blanked_if_not_supported_extension_for_extract()
+ {
+ $this->asEditor();
+ $page = Page::query()->first();
+
+ $this->put($page->getUrl(), [
+ 'name' => $page->name, 'summary' => '',
+ 'html' => 'test
',
+ ]);
+
+ $page->refresh();
+ $this->assertStringContainsString('
html);
+ }
+
+ public function test_base64_images_get_extracted_from_markdown_page_content()
+ {
+ $this->asEditor();
+ $page = Page::query()->first();
+
+ $this->put($page->getUrl(), [
+ 'name' => $page->name, 'summary' => '',
+ 'markdown' => 'test ',
+ ]);
+
+ $page->refresh();
+ $this->assertStringMatchesFormat('%Atest
%A
%A', $page->html);
+
+ $matches = [];
+ preg_match('/src="https:\/\/p.rizon.top:443\/http\/localhost(.*?)"/', $page->html, $matches);
+ $imagePath = $matches[1];
+ $imageFile = public_path($imagePath);
+ $this->assertEquals(base64_decode($this->base64Jpeg), file_get_contents($imageFile));
+
+ $this->deleteImage($imagePath);
+ }
+
+ public function test_base64_images_within_markdown_blanked_if_not_supported_extension_for_extract()
+ {
+ $this->asEditor();
+ $page = Page::query()->first();
+
+ $this->put($page->getUrl(), [
+ 'name' => $page->name, 'summary' => '',
+ 'markdown' => 'test ',
+ ]);
+
+ $page->refresh();
+ $this->assertStringContainsString('
html);
+ }
}