]> BookStack Code Mirror - bookstack/commitdiff
Merge pull request #1527 from BookStackApp/129-page-templates
authorDan Brown <redacted>
Sun, 11 Aug 2019 19:21:17 +0000 (20:21 +0100)
committerGitHub <redacted>
Sun, 11 Aug 2019 19:21:17 +0000 (20:21 +0100)
Page Templates Implementation

app/Entities/Repos/EntityRepo.php
app/Http/Controllers/UserController.php
public/.htaccess
public/uploads/.gitignore
public/uploads/.htaccess [new file with mode: 0755]
resources/views/form/text.blade.php
resources/views/users/form.blade.php
tests/Entity/PageContentTest.php
tests/Permissions/RolesTest.php

index aad9a1205895a18bfce0b0143ae244e2d9bffd51..7ca25b785286cb7f4e5e44ccbb4216c1c1881c4e 100644 (file)
@@ -765,6 +765,12 @@ class EntityRepo
             $scriptElem->parentNode->removeChild($scriptElem);
         }
 
+        // Remove data or JavaScript iFrames
+        $badIframes = $xPath->query('//*[contains(@src, \'data:\')] | //*[contains(@src, \'javascript:\')]');
+        foreach ($badIframes as $badIframe) {
+            $badIframe->parentNode->removeChild($badIframe);
+        }
+
         // Remove 'on*' attributes
         $onAttributes = $xPath->query('//@*[starts-with(name(), \'on\')]');
         foreach ($onAttributes as $attr) {
index 8191fbfe276226ab70bed45825d470b353905b88..570896ab60712fb3eb80900e5a26c3287b8b6b9f 100644 (file)
@@ -146,7 +146,12 @@ class UserController extends Controller
         ]);
 
         $user = $this->userRepo->getById($id);
-        $user->fill($request->all());
+        $user->fill($request->except(['email']));
+
+        // Email updates
+        if (userCan('users-manage') && $request->filled('email')) {
+            $user->email = $request->get('email');
+        }
 
         // Role updates
         if (userCan('users-manage') && $request->filled('roles')) {
index 8eb2dd0ddfa5f7b57bd0f351684dfa2e4e3ac0d3..0d55354ec6fb756086be2bcace7be11078064f29 100644 (file)
@@ -1,6 +1,6 @@
 <IfModule mod_rewrite.c>
     <IfModule mod_negotiation.c>
-        Options -MultiViews
+        Options -MultiViews -Indexes
     </IfModule>
 
     RewriteEngine On
index c96a04f008ee21e260b28f7701595ed59e2839e3..cb7328e1934841ba2afd78b3b7ceb100961337bb 100755 (executable)
@@ -1,2 +1,3 @@
 *
-!.gitignore
\ No newline at end of file
+!.gitignore
+!.htaccess
\ No newline at end of file
diff --git a/public/uploads/.htaccess b/public/uploads/.htaccess
new file mode 100755 (executable)
index 0000000..45552cb
--- /dev/null
@@ -0,0 +1 @@
+Options -Indexes
\ No newline at end of file
index 948a55cbc10a2b6e3f68e16626f8a0ff785394a8..909e87286247daaba449ebfc7ae320ba24346660 100644 (file)
@@ -1,6 +1,7 @@
 <input type="text" id="{{ $name }}" name="{{ $name }}"
        @if($errors->has($name)) class="text-neg" @endif
        @if(isset($placeholder)) placeholder="{{$placeholder}}" @endif
+       @if(isset($disabled) && $disabled) disabled="disabled" @endif
        @if(isset($tabindex)) tabindex="{{$tabindex}}" @endif
        @if(isset($model) || old($name)) value="{{ old($name) ? old($name) : $model->$name}}" @endif>
 @if($errors->has($name))
index 96beb7b2f97888bde380b582225b247bb8bc3040..3d073b2c8c0e51a78c2ba383bef2193655779ab5 100644 (file)
@@ -19,7 +19,7 @@
         <div>
             @if($authMethod !== 'ldap' || userCan('users-manage'))
                 <label for="email">{{ trans('auth.email') }}</label>
-                @include('form.text', ['name' => 'email'])
+                @include('form.text', ['name' => 'email', 'disabled' => !userCan('users-manage')])
             @endif
         </div>
     </div>
index c80b5f1d96f1b9c85ec5bf281c42e7f0c3f17895..b447a7c5d87f73c39d87c14f22a3bbcb6c81b40c 100644 (file)
@@ -80,6 +80,7 @@ class PageContentTest extends TestCase
         $page->save();
 
         $pageView = $this->get($page->getUrl());
+        $pageView->assertStatus(200);
         $pageView->assertDontSee($script);
         $pageView->assertSee('abc123abc123');
     }
@@ -103,12 +104,42 @@ class PageContentTest extends TestCase
             $page->save();
 
             $pageView = $this->get($page->getUrl());
+            $pageView->assertStatus(200);
             $pageView->assertElementNotContains('.page-content', '<script>');
             $pageView->assertElementNotContains('.page-content', '</script>');
         }
 
     }
 
+    public function test_iframe_js_and_base64_urls_are_removed()
+    {
+        $checks = [
+            '<iframe src="javascript:alert(document.cookie)"></iframe>',
+            '<iframe SRC=" javascript: alert(document.cookie)"></iframe>',
+            '<iframe src="data:text/html;base64,PHNjcmlwdD5hbGVydCgnaGVsbG8nKTwvc2NyaXB0Pg==" frameborder="0"></iframe>',
+            '<iframe src=" data:text/html;base64,PHNjcmlwdD5hbGVydCgnaGVsbG8nKTwvc2NyaXB0Pg==" frameborder="0"></iframe>',
+
+        ];
+
+        $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', '<iframe>');
+            $pageView->assertElementNotContains('.page-content', '</iframe>');
+            $pageView->assertElementNotContains('.page-content', 'src=');
+            $pageView->assertElementNotContains('.page-content', 'javascript:');
+            $pageView->assertElementNotContains('.page-content', 'data:');
+            $pageView->assertElementNotContains('.page-content', 'base64');
+        }
+
+    }
+
     public function test_page_inline_on_attributes_removed_by_default()
     {
         $this->asEditor();
@@ -118,6 +149,7 @@ class PageContentTest extends TestCase
         $page->save();
 
         $pageView = $this->get($page->getUrl());
+        $pageView->assertStatus(200);
         $pageView->assertDontSee($script);
         $pageView->assertSee('<p>Hello</p>');
     }
@@ -130,6 +162,7 @@ class PageContentTest extends TestCase
             '<div>Lorem ipsum dolor sit amet.<p onclick="console.log(\'test\')">Hello</p></div>',
             '<div><div><div><div>Lorem ipsum dolor sit amet.<p onclick="console.log(\'test\')">Hello</p></div></div></div></div>',
             '<div onclick="console.log(\'test\')">Lorem ipsum dolor sit amet.</div><p onclick="console.log(\'test\')">Hello</p><div></div>',
+            '<a a="<img src=1 onerror=\'alert(1)\'> ',
         ];
 
         $this->asEditor();
@@ -140,6 +173,7 @@ class PageContentTest extends TestCase
             $page->save();
 
             $pageView = $this->get($page->getUrl());
+            $pageView->assertStatus(200);
             $pageView->assertElementNotContains('.page-content', 'onclick');
         }
 
index 5bbdcf0bbb60c5f0c8ecf15d04f2285bbab5f7f5..a1f19364352c5f1ed74fa86f427ff8d0d95d4aac 100644 (file)
@@ -119,6 +119,43 @@ class RolesTest extends BrowserKitTest
         $this->actingAs($this->user)->visit('/')->dontSee($usersLink);
     }
 
+    public function test_user_cannot_change_email_unless_they_have_manage_users_permission()
+    {
+        $userProfileUrl = '/settings/users/' . $this->user->id;
+        $originalEmail = $this->user->email;
+        $this->actingAs($this->user);
+
+        $this->visit($userProfileUrl)
+            ->assertResponseOk()
+            ->seeElement('input[name=email][disabled]');
+        $this->put($userProfileUrl, [
+            'name' => 'my_new_name',
+            'email' => '[email protected]',
+        ]);
+        $this->seeInDatabase('users', [
+            'id' => $this->user->id,
+            'email' => $originalEmail,
+            'name' => 'my_new_name',
+        ]);
+
+        $this->giveUserPermissions($this->user, ['users-manage']);
+
+        $this->visit($userProfileUrl)
+            ->assertResponseOk()
+            ->dontSeeElement('input[name=email][disabled]')
+            ->seeElement('input[name=email]');
+        $this->put($userProfileUrl, [
+            'name' => 'my_new_name_2',
+            'email' => '[email protected]',
+        ]);
+
+        $this->seeInDatabase('users', [
+            'id' => $this->user->id,
+            'email' => '[email protected]',
+            'name' => 'my_new_name_2',
+        ]);
+    }
+
     public function test_user_roles_manage_permission()
     {
         $this->actingAs($this->user)->visit('/settings/roles')