diff --git a/.env.example b/.env.example index 4dee3b33441..13114b8b076 100644 --- a/.env.example +++ b/.env.example @@ -26,6 +26,13 @@ DB_DATABASE=database_database DB_USERNAME=database_username DB_PASSWORD=database_user_password +# Storage system to use +# By default files are stored on the local filesystem, with images being placed in +# public web space so they can be efficiently served directly by the web-server. +# For other options with different security levels & considerations, refer to: +# https://www.bookstackapp.com/docs/admin/upload-config/ +STORAGE_TYPE=local + # Mail system to use # Can be 'smtp' or 'sendmail' MAIL_DRIVER=smtp diff --git a/.env.example.complete b/.env.example.complete index 18e7bd00d9c..6c773f601f1 100644 --- a/.env.example.complete +++ b/.env.example.complete @@ -351,10 +351,25 @@ EXPORT_PDF_COMMAND_TIMEOUT=15 # Only used if 'ALLOW_UNTRUSTED_SERVER_FETCHING=true' which disables security protections. WKHTMLTOPDF=false -# Allow diff --git a/resources/views/layouts/parts/back-to-top.blade.php b/resources/views/layouts/parts/back-to-top.blade.php new file mode 100644 index 00000000000..b6efc97497b --- /dev/null +++ b/resources/views/layouts/parts/back-to-top.blade.php @@ -0,0 +1,15 @@ +
+ + + + +
diff --git a/resources/views/layouts/parts/custom-head.blade.php b/resources/views/layouts/parts/custom-head.blade.php index a13215cf813..caa177030fa 100644 --- a/resources/views/layouts/parts/custom-head.blade.php +++ b/resources/views/layouts/parts/custom-head.blade.php @@ -1,6 +1,6 @@ @inject('headContent', 'BookStack\Theming\CustomHtmlHeadContentProvider') -@if(setting('app-custom-head') && !request()->routeIs('settings.category')) +@if(!request()->routeIs('settings.category')) {!! $headContent->forWeb() !!} diff --git a/resources/views/layouts/parts/custom-styles.blade.php b/resources/views/layouts/parts/custom-styles.blade.php index bfdcc851289..b31334e7331 100644 --- a/resources/views/layouts/parts/custom-styles.blade.php +++ b/resources/views/layouts/parts/custom-styles.blade.php @@ -1,15 +1,22 @@ -@php - $settingSuffix = setting()->getForCurrentUser('dark-mode-enabled') ? '-dark' : ''; -@endphp diff --git a/resources/views/layouts/parts/header-logo.blade.php b/resources/views/layouts/parts/header-logo.blade.php index c1bbd7849bc..4c2dfb74ea8 100644 --- a/resources/views/layouts/parts/header-logo.blade.php +++ b/resources/views/layouts/parts/header-logo.blade.php @@ -1,6 +1,8 @@
- @include('pages.parts.pointer', ['page' => $page]) + @include('pages.parts.pointer', ['page' => $page, 'commentTree' => $commentTree]) @include('entities.sibling-navigation', ['next' => $next, 'previous' => $previous]) @@ -36,159 +36,9 @@ class="page-content clearfix"> @stop @section('left') - - @if($page->tags->count() > 0) -
- @include('entities.tag-list', ['entity' => $page]) -
- @endif - - @if ($page->attachments->count() > 0) -
-
{{ trans('entities.pages_attachments') }}
-
- @include('attachments.list', ['attachments' => $page->attachments]) -
-
- @endif - - @if (isset($pageNav) && count($pageNav)) - - @endif - - @include('entities.book-tree', ['book' => $book, 'sidebarTree' => $sidebarTree]) + @include('common.view-blocks', ['location' => 'pages-show', 'position' => 'left']) @stop @section('right') -
-
{{ trans('common.details') }}
- -
- -
-
{{ trans('common.actions') }}
- - - -
+ @include('common.view-blocks', ['location' => 'pages-show', 'position' => 'right']) @stop diff --git a/resources/views/search/all.blade.php b/resources/views/search/all.blade.php index ad437604b1c..48250816fef 100644 --- a/resources/views/search/all.blade.php +++ b/resources/views/search/all.blade.php @@ -87,11 +87,7 @@ @include('entities.list', ['entities' => $entities, 'showPath' => true, 'showTags' => true])
- @if($hasNextPage) -
- {{ trans('entities.search_more') }} -
- @endif + {{ $paginator->render() }} diff --git a/resources/views/settings/audit.blade.php b/resources/views/settings/audit.blade.php index 8e477668040..ce6a0463427 100644 --- a/resources/views/settings/audit.blade.php +++ b/resources/views/settings/audit.blade.php @@ -88,7 +88,11 @@ class="text-item">{{ $type }} @foreach($activities as $activity)
- @include('settings.parts.table-user', ['user' => $activity->user, 'user_id' => $activity->user_id]) + @if($activity->user && $activity->user->created_at <= $activity->created_at) + @include('settings.parts.table-user', ['user' => $activity->user]) + @else + [ID: {{ $activity->user_id }}] {{ trans('common.deleted_user') }} + @endif
{{ trans('settings.audit_table_event') }} @@ -111,7 +115,7 @@ class="mr-xs hide-over-m">{{ trans('settings.audit_table_ip') }} :
{{ $activity->ip }}
{{ trans('settings.audit_table_date') }} - :
{{ $activity->created_at }}
+ :
{{ $dates->absolute($activity->created_at) }}
@endforeach diff --git a/resources/views/settings/categories/sorting.blade.php b/resources/views/settings/categories/sorting.blade.php index 9d1d9814b96..5678434e0a5 100644 --- a/resources/views/settings/categories/sorting.blade.php +++ b/resources/views/settings/categories/sorting.blade.php @@ -11,13 +11,36 @@
+
+
+ +

{{ trans('settings.sorting_page_limits_desc') }}

+
+
+ @php + $labelByKey = ['shelves' => trans('entities.shelves'), 'books' => trans('entities.books'), 'search' => trans('entities.search_results')]; + @endphp + @foreach($labelByKey as $key => $label) +
+ + @include('form.number', [ + 'name' => 'setting-lists-page-count-' . $key, + 'value' => setting()->getInteger('lists-page-count-' . $key, 18, 1, 1000), + 'min' => 1, + 'step' => 1, + ]) +
+ @endforeach +
+
+
-

{{ trans('settings.sorting_book_default_desc') }}

+

{{ trans('settings.sorting_book_default_desc') }}

-
+
+

+ {{ trans('settings.sort_rule_create') }} +

diff --git a/resources/views/settings/layout.blade.php b/resources/views/settings/layout.blade.php index 930d407a508..2ca06b86ac0 100644 --- a/resources/views/settings/layout.blade.php +++ b/resources/views/settings/layout.blade.php @@ -18,7 +18,7 @@
{{ trans('settings.system_version') }}
- + BookStack @if(!str_starts_with($version, 'v')) version @endif {{ $version }}
diff --git a/resources/views/settings/layouts/edit.blade.php b/resources/views/settings/layouts/edit.blade.php new file mode 100644 index 00000000000..007eca66633 --- /dev/null +++ b/resources/views/settings/layouts/edit.blade.php @@ -0,0 +1,71 @@ +@extends('layouts.simple') + +@section('body') + +
+ +
+ +
+ +
{{ trans('preferences.layout_edit_layouts') }}
+ +
+ +
+
+
+

{{ trans('preferences.layout_edit') }}

+ {{ $locationName }} +
+ +

{{ trans('preferences.layout_edit_desc') }}

+ @if(!isset($blocks['center'])) +

+ {{ trans('preferences.layout_edit_column_hint') }} +

+ @endif + +
+ {{ method_field('PUT') }} + {{ csrf_field() }} + + + +
+ @include('settings.layouts.parts.block-column', ['columnBlocks' => $blocks['left'] ?? [], 'label' => trans('preferences.layout_edit_left'), 'id' => 'left']) + @if(isset($blocks['center'])) + @include('settings.layouts.parts.block-column', ['columnBlocks' => $blocks['center'] ?? [], 'label' => trans('preferences.layout_edit_center'), 'id' => 'center']) + @endif + @include('settings.layouts.parts.block-column', ['columnBlocks' => $blocks['right'] ?? [], 'label' => trans('preferences.layout_edit_right'), 'id' => 'right']) +
+ +
+ @include('settings.layouts.parts.block-column', ['columnBlocks' => $blocks['unused'] ?? [], 'label' => trans('preferences.layout_edit_unused'), 'id' => 'unused']) +
+ +
+ {{ trans('common.cancel') }} + + +
+
+ +
+ {{ csrf_field() }} + {{ method_field('PUT') }} +
+
+
+ +
+ +
+ +@stop diff --git a/resources/views/settings/layouts/parts/block-column.blade.php b/resources/views/settings/layouts/parts/block-column.blade.php new file mode 100644 index 00000000000..20da8dff72f --- /dev/null +++ b/resources/views/settings/layouts/parts/block-column.blade.php @@ -0,0 +1,17 @@ +{{-- +$columnBlocks - array - Blocks to list +$label - string - Section title +$id - string - identifier for location/column +--}} +
+ +
    +
  • {{ trans('preferences.layout_edit_empty') }}
  • + @foreach($columnBlocks as $block) + @include('settings.layouts.parts.block', ['block' => $block]) + @endforeach +
+
\ No newline at end of file diff --git a/resources/views/settings/layouts/parts/block.blade.php b/resources/views/settings/layouts/parts/block.blade.php new file mode 100644 index 00000000000..1885c4254cf --- /dev/null +++ b/resources/views/settings/layouts/parts/block.blade.php @@ -0,0 +1,23 @@ +@php /** @var $block class-string<\BookStack\View\ViewBlockInterface> */ @endphp +
  • +
    @icon('grip')
    +
    {{ $block::getLabel() }}
    + +
  • \ No newline at end of file diff --git a/resources/views/settings/parts/table-user.blade.php b/resources/views/settings/parts/table-user.blade.php index d29ad1979a0..affc7b6c4c4 100644 --- a/resources/views/settings/parts/table-user.blade.php +++ b/resources/views/settings/parts/table-user.blade.php @@ -1,12 +1,7 @@ {{-- -$user - User mode to display, Can be null. -$user_id - Id of user to show. Must be provided. +$user - User to display. --}} -@if($user) - -
    {{ $user->name }}
    -
    {{ $user->name }}
    -
    -@else - [ID: {{ $user_id }}] {{ trans('common.deleted_user') }} -@endif \ No newline at end of file + +
    {{ $user->name }}
    +
    {{ $user->name }}
    +
    \ No newline at end of file diff --git a/resources/views/settings/recycle-bin/parts/recycle-bin-list-item.blade.php b/resources/views/settings/recycle-bin/parts/recycle-bin-list-item.blade.php index b18f9cbe08c..2dad617dcad 100644 --- a/resources/views/settings/recycle-bin/parts/recycle-bin-list-item.blade.php +++ b/resources/views/settings/recycle-bin/parts/recycle-bin-list-item.blade.php @@ -33,7 +33,14 @@ @endif
    -
    {{ trans('settings.recycle_bin_deleted_by') }}:
    @include('settings.parts.table-user', ['user' => $deletion->deleter, 'user_id' => $deletion->deleted_by])
    +
    + {{ trans('settings.recycle_bin_deleted_by') }}:
    + @if($deletion->deleter) + @include('settings.parts.table-user', ['user' => $deletion->deleter, 'user_id' => $deletion->deleted_by]) + @else + {{ trans('common.deleted_user') }} + @endif +
    {{ trans('settings.recycle_bin_deleted_at') }}:
    {{ $deletion->created_at }}
    diff --git a/resources/views/settings/roles/parts/asset-permissions-row.blade.php b/resources/views/settings/roles/parts/asset-permissions-row.blade.php index 8bff570cb85..200153b1b71 100644 --- a/resources/views/settings/roles/parts/asset-permissions-row.blade.php +++ b/resources/views/settings/roles/parts/asset-permissions-row.blade.php @@ -6,27 +6,35 @@
    {{ trans('common.create') }}
    @if($permissionPrefix === 'page' || $permissionPrefix === 'chapter') - @include('settings.roles.parts.checkbox', ['permission' => $permissionPrefix . '-create-own', 'label' => trans('settings.role_own')]) + @php $createOwnAria = trans('settings.role_permission_aria', ['action' => trans('common.create'), 'resource' => strtolower($title), 'value' => trans('settings.role_own')]); @endphp + @include('settings.roles.parts.checkbox', ['permission' => $permissionPrefix . '-create-own', 'label' => trans('settings.role_own'), 'ariaLabel' => $createOwnAria])
    @endif - @include('settings.roles.parts.checkbox', ['permission' => $permissionPrefix . '-create-all', 'label' => trans('settings.role_all')]) + @php $createAllAria = trans('settings.role_permission_aria', ['action' => trans('common.create'), 'resource' => strtolower($title), 'value' => trans('settings.role_all')]); @endphp + @include('settings.roles.parts.checkbox', ['permission' => $permissionPrefix . '-create-all', 'label' => trans('settings.role_all'), 'ariaLabel' => $createAllAria])
    {{ trans('common.view') }}
    - @include('settings.roles.parts.checkbox', ['permission' => $permissionPrefix . '-view-own', 'label' => trans('settings.role_own')]) + @php $viewOwnAria = trans('settings.role_permission_aria', ['action' => trans('common.view'), 'resource' => strtolower($title), 'value' => trans('settings.role_own')]); @endphp + @include('settings.roles.parts.checkbox', ['permission' => $permissionPrefix . '-view-own', 'label' => trans('settings.role_own'), 'ariaLabel' => $viewOwnAria])
    - @include('settings.roles.parts.checkbox', ['permission' => $permissionPrefix . '-view-all', 'label' => trans('settings.role_all')]) + @php $viewAllAria = trans('settings.role_permission_aria', ['action' => trans('common.view'), 'resource' => strtolower($title), 'value' => trans('settings.role_all')]); @endphp + @include('settings.roles.parts.checkbox', ['permission' => $permissionPrefix . '-view-all', 'label' => trans('settings.role_all'), 'ariaLabel' => $viewAllAria])
    {{ trans('common.edit') }}
    - @include('settings.roles.parts.checkbox', ['permission' => $permissionPrefix . '-update-own', 'label' => trans('settings.role_own')]) + @php $editOwnAria = trans('settings.role_permission_aria', ['action' => trans('common.edit'), 'resource' => strtolower($title), 'value' => trans('settings.role_own')]); @endphp + @include('settings.roles.parts.checkbox', ['permission' => $permissionPrefix . '-update-own', 'label' => trans('settings.role_own'), 'ariaLabel' => $editOwnAria])
    - @include('settings.roles.parts.checkbox', ['permission' => $permissionPrefix . '-update-all', 'label' => trans('settings.role_all')]) + @php $editAllAria = trans('settings.role_permission_aria', ['action' => trans('common.edit'), 'resource' => strtolower($title), 'value' => trans('settings.role_all')]); @endphp + @include('settings.roles.parts.checkbox', ['permission' => $permissionPrefix . '-update-all', 'label' => trans('settings.role_all'), 'ariaLabel' => $editAllAria])
    {{ trans('common.delete') }}
    - @include('settings.roles.parts.checkbox', ['permission' => $permissionPrefix . '-delete-own', 'label' => trans('settings.role_own')]) + @php $deleteOwnAria = trans('settings.role_permission_aria', ['action' => trans('common.delete'), 'resource' => strtolower($title), 'value' => trans('settings.role_own')]); @endphp + @include('settings.roles.parts.checkbox', ['permission' => $permissionPrefix . '-delete-own', 'label' => trans('settings.role_own'), 'ariaLabel' => $deleteOwnAria])
    - @include('settings.roles.parts.checkbox', ['permission' => $permissionPrefix . '-delete-all', 'label' => trans('settings.role_all')]) + @php $deleteAllAria = trans('settings.role_permission_aria', ['action' => trans('common.delete'), 'resource' => strtolower($title), 'value' => trans('settings.role_all')]); @endphp + @include('settings.roles.parts.checkbox', ['permission' => $permissionPrefix . '-delete-all', 'label' => trans('settings.role_all'), 'ariaLabel' => $deleteAllAria])
    -
    \ No newline at end of file +
    diff --git a/resources/views/settings/roles/parts/checkbox.blade.php b/resources/views/settings/roles/parts/checkbox.blade.php index 44cdd22bdf6..5818888d723 100644 --- a/resources/views/settings/roles/parts/checkbox.blade.php +++ b/resources/views/settings/roles/parts/checkbox.blade.php @@ -3,5 +3,6 @@ 'name' => 'permissions[' . $permission . ']', 'value' => 'true', 'checked' => old('permissions'.$permission, false)|| (!old('display_name', false) && (isset($role) && $role->hasPermission($permission))), - 'label' => $label + 'label' => $label, + 'ariaLabel' => $ariaLabel ?? null ]) \ No newline at end of file diff --git a/resources/views/settings/roles/parts/form.blade.php b/resources/views/settings/roles/parts/form.blade.php index a77b80e4c69..dec8d574e7d 100644 --- a/resources/views/settings/roles/parts/form.blade.php +++ b/resources/views/settings/roles/parts/form.blade.php @@ -30,10 +30,10 @@ {{ trans('common.toggle_all') }} -
    +
    -
    @include('settings.roles.parts.checkbox', ['permission' => 'restrictions-manage-all', 'label' => trans('settings.role_manage_entity_permissions')])
    -
    @include('settings.roles.parts.checkbox', ['permission' => 'restrictions-manage-own', 'label' => trans('settings.role_manage_own_entity_permissions')])
    +
    @include('settings.roles.parts.checkbox', ['permission' => 'restrictions-manage-all', 'label' => trans('settings.role_manage_entity_permissions')]) 1
    +
    @include('settings.roles.parts.checkbox', ['permission' => 'restrictions-manage-own', 'label' => trans('settings.role_manage_own_entity_permissions')]) 1
    @include('settings.roles.parts.checkbox', ['permission' => 'templates-manage', 'label' => trans('settings.role_manage_page_templates')])
    @include('settings.roles.parts.checkbox', ['permission' => 'access-api', 'label' => trans('settings.role_access_api')])
    @include('settings.roles.parts.checkbox', ['permission' => 'content-export', 'label' => trans('settings.role_export_content')])
    @@ -48,6 +48,10 @@

    {{ trans('settings.roles_system_warning') }}

    + +

    + 1 {{ trans('settings.role_permission_note_users_and_roles') }} +

    @@ -61,7 +65,7 @@
    + class="item-list custom-checkbox-list">
    {{ trans('common.toggle_all') }} @@ -75,7 +79,8 @@ class="item-list toggle-switch-list"> @include('settings.roles.parts.asset-permissions-row', ['title' => trans('entities.books'), 'permissionPrefix' => 'book']) @include('settings.roles.parts.asset-permissions-row', ['title' => trans('entities.chapters'), 'permissionPrefix' => 'chapter']) @include('settings.roles.parts.asset-permissions-row', ['title' => trans('entities.pages'), 'permissionPrefix' => 'page']) - @include('settings.roles.parts.related-asset-permissions-row', ['title' => trans('entities.images'), 'permissionPrefix' => 'image', 'refMark' => '1']) + @include('settings.roles.parts.revisions-permissions-row', ['title' => trans('entities.revisions'), 'permissionPrefix' => 'revision']) + @include('settings.roles.parts.related-asset-permissions-row', ['title' => trans('entities.images'), 'permissionPrefix' => 'image']) @include('settings.roles.parts.related-asset-permissions-row', ['title' => trans('entities.attachments'), 'permissionPrefix' => 'attachment']) @include('settings.roles.parts.related-asset-permissions-row', ['title' => trans('entities.comments'), 'permissionPrefix' => 'comment'])
    @@ -83,6 +88,8 @@ class="item-list toggle-switch-list">

    1 {{ trans('settings.role_asset_image_view_note') }} +
    + 2 {{ trans('settings.role_asset_users_note') }}

    diff --git a/resources/views/settings/roles/parts/related-asset-permissions-row.blade.php b/resources/views/settings/roles/parts/related-asset-permissions-row.blade.php index 62fdd6b744a..ac8e7422e43 100644 --- a/resources/views/settings/roles/parts/related-asset-permissions-row.blade.php +++ b/resources/views/settings/roles/parts/related-asset-permissions-row.blade.php @@ -5,22 +5,30 @@
    {{ trans('common.create') }}
    - @include('settings.roles.parts.checkbox', ['permission' => $permissionPrefix . '-create-all', 'label' => '']) + @php $createAllAria = trans('settings.role_permission_aria', ['action' => trans('common.create'), 'resource' => strtolower($title), 'value' => trans('settings.role_all')]); @endphp + @include('settings.roles.parts.checkbox', ['permission' => $permissionPrefix . '-create-all', 'label' => '', 'ariaLabel' => $createAllAria]) + @if($permissionPrefix === 'comment')2@endif
    {{ trans('common.view') }}
    - {{ trans('settings.role_controlled_by_asset') }}@if($refMark ?? false){{ $refMark }}@endif + {{ trans('settings.role_controlled_by_asset') }}@if($permissionPrefix === 'image')1@endif
    {{ trans('common.edit') }}
    - @include('settings.roles.parts.checkbox', ['permission' => $permissionPrefix . '-update-own', 'label' => trans('settings.role_own')]) + @php $editOwnAria = trans('settings.role_permission_aria', ['action' => trans('common.edit'), 'resource' => strtolower($title), 'value' => trans('settings.role_own')]); @endphp + @include('settings.roles.parts.checkbox', ['permission' => $permissionPrefix . '-update-own', 'label' => trans('settings.role_own'), 'ariaLabel' => $editOwnAria]) + @if($permissionPrefix === 'comment')2@endif
    - @include('settings.roles.parts.checkbox', ['permission' => $permissionPrefix . '-update-all', 'label' => trans('settings.role_all')]) + @php $editAllAria = trans('settings.role_permission_aria', ['action' => trans('common.edit'), 'resource' => strtolower($title), 'value' => trans('settings.role_all')]); @endphp + @include('settings.roles.parts.checkbox', ['permission' => $permissionPrefix . '-update-all', 'label' => trans('settings.role_all'), 'ariaLabel' => $editAllAria]) + @if($permissionPrefix === 'comment')2@endif
    {{ trans('common.delete') }}
    - @include('settings.roles.parts.checkbox', ['permission' => $permissionPrefix . '-delete-own', 'label' => trans('settings.role_own')]) + @php $deleteOwnAria = trans('settings.role_permission_aria', ['action' => trans('common.delete'), 'resource' => strtolower($title), 'value' => trans('settings.role_own')]); @endphp + @include('settings.roles.parts.checkbox', ['permission' => $permissionPrefix . '-delete-own', 'label' => trans('settings.role_own'), 'ariaLabel' => $deleteOwnAria])
    - @include('settings.roles.parts.checkbox', ['permission' => $permissionPrefix . '-delete-all', 'label' => trans('settings.role_all')]) + @php $deleteAllAria = trans('settings.role_permission_aria', ['action' => trans('common.delete'), 'resource' => strtolower($title), 'value' => trans('settings.role_all')]); @endphp + @include('settings.roles.parts.checkbox', ['permission' => $permissionPrefix . '-delete-all', 'label' => trans('settings.role_all'), 'ariaLabel' => $deleteAllAria])
    -
    \ No newline at end of file +
    diff --git a/resources/views/settings/roles/parts/revisions-permissions-row.blade.php b/resources/views/settings/roles/parts/revisions-permissions-row.blade.php new file mode 100644 index 00000000000..50b714de468 --- /dev/null +++ b/resources/views/settings/roles/parts/revisions-permissions-row.blade.php @@ -0,0 +1,23 @@ +
    +
    + {{ $title }}
    + {{ trans('common.toggle_all') }} +
    +
    + {{ trans('common.create') }}
    + - +
    +
    + {{ trans('common.view') }}
    + @php $viewAllAria = trans('settings.role_permission_aria', ['action' => trans('common.view'), 'resource' => strtolower($title), 'value' => trans('settings.role_all')]); @endphp + @include('settings.roles.parts.checkbox', ['permission' => $permissionPrefix . '-view-all', 'label' => trans('settings.role_all'), 'ariaLabel' => $viewAllAria]) +
    +
    + {{ trans('common.edit') }}
    + - +
    +
    + {{ trans('common.delete') }}
    + {{ trans('settings.role_controlled_by_page_delete') }} +
    +
    diff --git a/resources/views/settings/webhooks/parts/form.blade.php b/resources/views/settings/webhooks/parts/form.blade.php index 56929e3cee7..fede1afbad3 100644 --- a/resources/views/settings/webhooks/parts/form.blade.php +++ b/resources/views/settings/webhooks/parts/form.blade.php @@ -36,9 +36,9 @@

    {{ trans('settings.webhooks_events_desc') }}

    {{ trans('settings.webhooks_events_warning') }}

    -
    +
    @include('form.custom-checkbox', [ - 'name' => 'events[]', + 'name' => 'events[all]', 'value' => 'all', 'label' => trans('settings.webhooks_events_all'), 'checked' => old('events') ? in_array('all', old('events')) : (isset($webhook) ? $webhook->tracksEvent('all') : false), @@ -47,11 +47,11 @@
    -
    +
    @foreach(\BookStack\Activity\ActivityType::all() as $activityType)
    @include('form.custom-checkbox', [ - 'name' => 'events[]', + 'name' => 'events[' . $activityType . ']', 'value' => $activityType, 'label' => $activityType, 'checked' => old('events') ? in_array($activityType, old('events')) : (isset($webhook) ? $webhook->tracksEvent($activityType) : false), diff --git a/resources/views/settings/webhooks/parts/format-example.blade.php b/resources/views/settings/webhooks/parts/format-example.blade.php index e10a6c69e28..476fca661e6 100644 --- a/resources/views/settings/webhooks/parts/format-example.blade.php +++ b/resources/views/settings/webhooks/parts/format-example.blade.php @@ -50,7 +50,6 @@ "updated_at": "2021-12-11T21:53:24.000000Z", "slug": "my-wonderful-updated-page", "book_slug": "my-awesome-book", - "type": "version", "summary": "Updated the title and fixed some spelling", "revision_number": 2 } diff --git a/resources/views/shelves/index.blade.php b/resources/views/shelves/index.blade.php index bb7c57e0fde..87c6392983f 100644 --- a/resources/views/shelves/index.blade.php +++ b/resources/views/shelves/index.blade.php @@ -4,52 +4,10 @@ @include('shelves.parts.list', ['shelves' => $shelves, 'view' => $view, 'listOptions' => $listOptions]) @stop -@section('right') - -
    -
    {{ trans('common.actions') }}
    - -
    - -@stop - @section('left') - @if($recents) -
    -
    {{ trans('entities.recently_viewed') }}
    - @include('entities.list', ['entities' => $recents, 'style' => 'compact']) -
    - @endif - - + @include('common.view-blocks', ['location' => 'shelves-index', 'position' => 'left']) +@stop -
    -
    {{ trans('entities.shelves_new') }}
    - @if(count($new) > 0) - @include('entities.list', ['entities' => $new, 'style' => 'compact']) - @else -

    {{ trans('entities.shelves_new_empty') }}

    - @endif -
    -@stop \ No newline at end of file +@section('right') + @include('common.view-blocks', ['location' => 'shelves-index', 'position' => 'right']) +@stop diff --git a/resources/views/shelves/parts/form.blade.php b/resources/views/shelves/parts/form.blade.php index 0207d72780b..0a5343b16eb 100644 --- a/resources/views/shelves/parts/form.blade.php +++ b/resources/views/shelves/parts/form.blade.php @@ -26,9 +26,12 @@ class="icon-button px-xs py-xxs mx-xs text-bigger" @icon('more')
    @@ -42,7 +45,8 @@ class="scroll-box configured-option-list">
    - +
      @@ -54,7 +58,6 @@ class="scroll-box available-option-list">
    -
    - {{ trans('common.cancel') }} + {{ trans('common.cancel') }}
    diff --git a/resources/views/shelves/parts/index-sidebar-section-actions.blade.php b/resources/views/shelves/parts/index-sidebar-section-actions.blade.php new file mode 100644 index 00000000000..d5cdb4056a4 --- /dev/null +++ b/resources/views/shelves/parts/index-sidebar-section-actions.blade.php @@ -0,0 +1,18 @@ +
    +
    {{ trans('common.actions') }}
    + +
    \ No newline at end of file diff --git a/resources/views/shelves/parts/index-sidebar-section-new.blade.php b/resources/views/shelves/parts/index-sidebar-section-new.blade.php new file mode 100644 index 00000000000..602f60ebeaa --- /dev/null +++ b/resources/views/shelves/parts/index-sidebar-section-new.blade.php @@ -0,0 +1,8 @@ +
    +
    {{ trans('entities.shelves_new') }}
    + @if(count($new) > 0) + @include('entities.list', ['entities' => $new, 'style' => 'compact']) + @else +

    {{ trans('entities.shelves_new_empty') }}

    + @endif +
    \ No newline at end of file diff --git a/resources/views/shelves/parts/index-sidebar-section-popular.blade.php b/resources/views/shelves/parts/index-sidebar-section-popular.blade.php new file mode 100644 index 00000000000..956321c5e01 --- /dev/null +++ b/resources/views/shelves/parts/index-sidebar-section-popular.blade.php @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/resources/views/shelves/parts/index-sidebar-section-recents.blade.php b/resources/views/shelves/parts/index-sidebar-section-recents.blade.php new file mode 100644 index 00000000000..f1a68ba4f99 --- /dev/null +++ b/resources/views/shelves/parts/index-sidebar-section-recents.blade.php @@ -0,0 +1,6 @@ +@if($recents) +
    +
    {{ trans('entities.recently_viewed') }}
    + @include('entities.list', ['entities' => $recents, 'style' => 'compact']) +
    +@endif \ No newline at end of file diff --git a/resources/views/shelves/parts/list-item.blade.php b/resources/views/shelves/parts/list-item.blade.php index 00cacfa707c..5fc8a362b32 100644 --- a/resources/views/shelves/parts/list-item.blade.php +++ b/resources/views/shelves/parts/list-item.blade.php @@ -1,5 +1,5 @@ -
    +
    @icon('bookshelf')
    diff --git a/resources/views/shelves/parts/show-sidebar-section-actions.blade.php b/resources/views/shelves/parts/show-sidebar-section-actions.blade.php new file mode 100644 index 00000000000..ba92e5f703b --- /dev/null +++ b/resources/views/shelves/parts/show-sidebar-section-actions.blade.php @@ -0,0 +1,43 @@ +
    +
    {{ trans('common.actions') }}
    +
    +
    \ No newline at end of file diff --git a/resources/views/shelves/parts/show-sidebar-section-activity.blade.php b/resources/views/shelves/parts/show-sidebar-section-activity.blade.php new file mode 100644 index 00000000000..c1c5c1d3ecf --- /dev/null +++ b/resources/views/shelves/parts/show-sidebar-section-activity.blade.php @@ -0,0 +1,6 @@ +@if(count($activity) > 0) +
    +
    {{ trans('entities.recent_activity') }}
    + @include('common.activity-list', ['activity' => $activity]) +
    +@endif \ No newline at end of file diff --git a/resources/views/shelves/parts/show-sidebar-section-details.blade.php b/resources/views/shelves/parts/show-sidebar-section-details.blade.php new file mode 100644 index 00000000000..8933cc41973 --- /dev/null +++ b/resources/views/shelves/parts/show-sidebar-section-details.blade.php @@ -0,0 +1,21 @@ +
    +
    {{ trans('common.details') }}
    + +
    \ No newline at end of file diff --git a/resources/views/shelves/parts/show-sidebar-section-tags.blade.php b/resources/views/shelves/parts/show-sidebar-section-tags.blade.php new file mode 100644 index 00000000000..265d61cd0d3 --- /dev/null +++ b/resources/views/shelves/parts/show-sidebar-section-tags.blade.php @@ -0,0 +1,5 @@ +@if($shelf->tags->count() > 0) +
    + @include('entities.tag-list', ['entity' => $shelf]) +
    +@endif \ No newline at end of file diff --git a/resources/views/shelves/show.blade.php b/resources/views/shelves/show.blade.php index 633f959f3c9..b942f35ff7a 100644 --- a/resources/views/shelves/show.blade.php +++ b/resources/views/shelves/show.blade.php @@ -2,8 +2,8 @@ @push('social-meta') - @if($shelf->cover) - + @if($shelf->coverInfo()->exists()) + @endif @endpush @@ -28,7 +28,7 @@
    -
    {!! $shelf->descriptionHtml() !!}
    +
    {!! $shelf->descriptionInfo()->getHtml() !!}
    @if(count($sortedVisibleShelfBooks) > 0) @if($view === 'list')
    @@ -69,89 +69,9 @@ @stop @section('left') - - @if($shelf->tags->count() > 0) -
    - @include('entities.tag-list', ['entity' => $shelf]) -
    - @endif - -
    -
    {{ trans('common.details') }}
    - -
    - - @if(count($activity) > 0) -
    -
    {{ trans('entities.recent_activity') }}
    - @include('common.activity-list', ['activity' => $activity]) -
    - @endif + @include('common.view-blocks', ['location' => 'shelves-show', 'position' => 'left']) @stop @section('right') -
    -
    {{ trans('common.actions') }}
    - -
    + @include('common.view-blocks', ['location' => 'shelves-show', 'position' => 'right']) @stop - - - - diff --git a/resources/views/users/account/auth.blade.php b/resources/views/users/account/auth.blade.php index 57e6c1f9cb3..1dadded3d7b 100644 --- a/resources/views/users/account/auth.blade.php +++ b/resources/views/users/account/auth.blade.php @@ -14,17 +14,22 @@ {{ trans('preferences.auth_change_password_desc') }}

    -
    +
    - + @include('form.password', ['name' => 'password', 'autocomplete' => 'new-password'])
    - + @include('form.password', ['name' => 'password-confirm'])
    +
    + + @include('form.password', ['name' => 'password-current']) +
    +
    diff --git a/resources/views/users/account/interface.blade.php b/resources/views/users/account/interface.blade.php new file mode 100644 index 00000000000..7d78f08c81b --- /dev/null +++ b/resources/views/users/account/interface.blade.php @@ -0,0 +1,54 @@ +@extends('users.account.layout') + +@section('main') +
    +
    + {{ method_field('put') }} + {{ csrf_field() }} + +

    {{ trans('preferences.interface') }}

    +

    {{ trans('preferences.interface_desc') }}

    + +
    + @include('users.parts.language-option-row', ['value' => old('language') ?? user()->getLocale()->appLocale()]) + @include('users.account.parts.display-mode-option-row') +
    + +
    + +
    + +
    +
    + +
    +

    {{ trans('preferences.layouts') }}

    +

    {{ trans('preferences.layouts_desc') }}

    + +
    + @foreach($namedLocations as $locationKey => $locationName) + + @endforeach +
    + +
    + +
    +
    +
    +

    {{ trans('preferences.shortcuts_interface') }}

    +

    {{ trans('preferences.shortcuts_overview_desc') }}

    +
    + +
    +
    +@stop diff --git a/resources/views/users/account/layout.blade.php b/resources/views/users/account/layout.blade.php index df8ebc2d904..94f1f328de0 100644 --- a/resources/views/users/account/layout.blade.php +++ b/resources/views/users/account/layout.blade.php @@ -11,6 +11,7 @@

    ", + "

    Some script

    ", + ]; + + $this->asEditor(); + $page = $this->entities->page(); + + foreach ($checks as $check) { + $page->html = $check; + $page->save(); + + $pageView = $this->get($page->getUrl()); + $pageView->assertStatus(200); + $this->withHtml($pageView)->assertElementNotContains('.page-content', ''); + } + } + + public function test_js_and_base64_src_urls_are_removed() + { + config()->set('app.content_filtering', 'j'); + + $checks = [ + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + ]; + + $this->asEditor(); + $page = $this->entities->page(); + + foreach ($checks as $check) { + $page->html = $check; + $page->save(); + + $pageView = $this->get($page->getUrl()); + $pageView->assertStatus(200); + $html = $this->withHtml($pageView); + $html->assertElementNotContains('.page-content', 'assertElementNotContains('.page-content', 'data='); + $html->assertElementNotContains('.page-content', ''); + $html->assertElementNotContains('.page-content', 'src='); + $html->assertElementNotContains('.page-content', 'javascript:'); + $html->assertElementNotContains('.page-content', 'data:'); + $html->assertElementNotContains('.page-content', 'base64'); + } + } + + public function test_javascript_uri_links_are_removed() + { + config()->set('app.content_filtering', 'j'); + + $checks = [ + 'withHtml($pageView)->assertElementNotContains('.page-content', 'href=javascript:'); + } + } + + public function test_form_filtering_is_controlled_by_config() + { + config()->set('app.content_filtering', ''); + $page = $this->entities->page(); + $page->html = '
    '; + $page->save(); + + $this->asEditor()->get($page->getUrl())->assertSee('dont-see-this', false); + + config()->set('app.content_filtering', 'f'); + $this->get($page->getUrl())->assertDontSee('dont-see-this', false); + } + + public function test_form_actions_with_javascript_are_removed() + { + config()->set('app.content_filtering', 'j'); + + $checks = [ + '', + 'Click me', + 'Click me', + '', + '', + ]; + + $this->asEditor(); + $page = $this->entities->page(); + + foreach ($checks as $check) { + $page->html = $check; + $page->save(); + + $pageView = $this->get($page->getUrl()); + $pageView->assertStatus(200); + $pageView->assertDontSee('id="xss"', false); + $pageView->assertDontSee('action=javascript:', false); + $pageView->assertDontSee('action=JaVaScRiPt:', false); + $pageView->assertDontSee('formaction=javascript:', false); + $pageView->assertDontSee('formaction=JaVaScRiPt:', false); + } + } + + public function test_form_elements_are_removed() + { + config()->set('app.content_filtering', 'f'); + + $checks = [ + '

    thisisacattofind

    thisdogshouldnotbefound
    ', + '

    thisisacattofind

    ', + '

    thisisacattofind

    ', + '

    thisisacattofind

    ', + '

    thisisacattofind

    thisdogshouldnotbefound
    ', + '

    thisisacattofind

    ', + '

    thisisacattofind

    ', + <<<'TESTCASE' + + + + +

    thisisacattofind

    +
    +

    thisdogshouldnotbefound

    +
    + + + + +
    +
    +TESTCASE + + ]; + + $this->asEditor(); + $page = $this->entities->page(); + + foreach ($checks as $check) { + $page->html = $check; + $page->save(); + + $pageView = $this->get($page->getUrl()); + $pageView->assertStatus(200); + $pageView->assertSee('thisisacattofind'); + $pageView->assertDontSee('thisdogshouldnotbefound'); + } + } + + public function test_form_attributes_are_removed() + { + config()->set('app.content_filtering', 'f'); + + $withinSvgSample = <<<'TESTCASE' + + + + +

    thisisacattofind

    +

    thisisacattofind

    + + +
    +
    +TESTCASE; + + $checks = [ + 'formaction' => '

    thisisacattofind

    ', + 'form' => '

    thisisacattofind

    ', + 'formmethod' => '

    thisisacattofind

    ', + 'formtarget' => '

    thisisacattofind

    ', + 'FORMTARGET' => '

    thisisacattofind

    ', + ]; + + $this->asEditor(); + $page = $this->entities->page(); + + foreach ($checks as $attribute => $check) { + $page->html = $check; + $page->save(); + + $pageView = $this->get($page->getUrl()); + $pageView->assertStatus(200); + $pageView->assertSee('thisisacattofind'); + $this->withHtml($pageView)->assertElementNotExists(".page-content [{$attribute}]"); + } + + $page->html = $withinSvgSample; + $page->save(); + $pageView = $this->get($page->getUrl()); + $pageView->assertStatus(200); + $html = $this->withHtml($pageView); + foreach ($checks as $attribute => $check) { + $pageView->assertSee('thisisacattofind'); + $html->assertElementNotExists(".page-content [{$attribute}]"); + } + } + + public function test_metadata_redirects_are_removed() + { + config()->set('app.content_filtering', 'h'); + + $checks = [ + '', + '', + '', + ]; + + $this->asEditor(); + $page = $this->entities->page(); + + foreach ($checks as $check) { + $page->html = $check; + $page->save(); + + $pageView = $this->get($page->getUrl()); + $pageView->assertStatus(200); + $this->withHtml($pageView)->assertElementNotContains('.page-content', ''); + $this->withHtml($pageView)->assertElementNotContains('.page-content', ''); + $this->withHtml($pageView)->assertElementNotContains('.page-content', 'content='); + $this->withHtml($pageView)->assertElementNotContains('.page-content', 'external_url'); + } + } + + public function test_page_inline_on_attributes_removed_by_default() + { + config()->set('app.content_filtering', 'j'); + + $this->asEditor(); + $page = $this->entities->page(); + $script = '

    Hello

    '; + $page->html = "escape {$script}"; + $page->save(); + + $pageView = $this->get($page->getUrl()); + $pageView->assertStatus(200); + $pageView->assertDontSee($script, false); + $pageView->assertSee('

    Hello

    ', false); + } + + public function test_more_complex_inline_on_attributes_escaping_scenarios() + { + config()->set('app.content_filtering', 'j'); + + $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 = $this->entities->page(); + + foreach ($checks as $check) { + $page->html = $check; + $page->save(); + + $pageView = $this->get($page->getUrl()); + $pageView->assertStatus(200); + $this->withHtml($pageView)->assertElementNotContains('.page-content', 'onclick'); + } + } + + public function test_page_content_scripts_show_with_filters_disabled() + { + $this->asEditor(); + $page = $this->entities->page(); + config()->set('app.content_filtering', ''); + + $script = 'abc123abc123'; + $page->html = "no escape {$script}"; + $page->save(); + + $pageView = $this->get($page->getUrl()); + $pageView->assertSee($script, false); + $pageView->assertDontSee('abc123abc123'); + } + + public function test_svg_script_usage_is_removed() + { + config()->set('app.content_filtering', 'j'); + + $checks = [ + '', + '', + '', + '', + '', + 'XSS', + 'XSS', + '', + ]; + + $this->asEditor(); + $page = $this->entities->page(); + + foreach ($checks as $check) { + $page->html = $check; + $page->save(); + + $pageView = $this->get($page->getUrl()); + $pageView->assertStatus(200); + $html = $this->withHtml($pageView); + $html->assertElementNotContains('.page-content', 'alert'); + $html->assertElementNotContains('.page-content', 'xlink:href'); + $html->assertElementNotContains('.page-content', 'application/xml'); + $html->assertElementNotContains('.page-content', 'javascript'); + } + } + + public function test_page_inline_on_attributes_show_with_filters_disabled() + { + $this->asEditor(); + $page = $this->entities->page(); + config()->set('app.content_filtering', ''); + + $script = '

    Hello

    '; + $page->html = "escape {$script}"; + $page->save(); + + $pageView = $this->get($page->getUrl()); + $pageView->assertSee($script, false); + $pageView->assertDontSee('

    Hello

    ', false); + } + + public function test_non_content_filtering_is_controlled_by_config() + { + config()->set('app.content_filtering', ''); + $page = $this->entities->page(); + $html = <<<'HTML' + + +HTML; + $page->html = $html; + $page->save(); + + $resp = $this->asEditor()->get($page->getUrl()); + $resp->assertSee('superbeans', false); + + config()->set('app.content_filtering', 'h'); + + $resp = $this->asEditor()->get($page->getUrl()); + $resp->assertDontSee('superbeans', false); + } + + public function test_non_content_filtering() + { + config()->set('app.content_filtering', 'h'); + $page = $this->entities->page(); + $html = <<<'HTML' + +

    inbetweenpsection

    + + +superbeans! + +HTML; + + $page->html = $html; + $page->save(); + + $resp = $this->asEditor()->get($page->getUrl()); + $resp->assertDontSee('superbeans', false); + $resp->assertSee('inbetweenpsection', false); + } + + public function test_allow_list_filtering_is_controlled_by_config() + { + config()->set('app.content_filtering', ''); + $page = $this->entities->page(); + $page->html = '
    Hello!
    '; + $page->save(); + + $resp = $this->asEditor()->get($page->getUrl()); + $resp->assertSee('style="position: absolute; left: 0;color:#00FFEE;"', false); + + config()->set('app.content_filtering', 'a'); + $resp = $this->get($page->getUrl()); + $resp->assertDontSee('style="position: absolute; left: 0;color:#00FFEE;"', false); + $resp->assertSee('style="color:#00FFEE;"', false); + } + + public function test_allow_list_style_filtering() + { + $testCasesExpectedByInput = [ + '
    Hello!
    ' => '
    Hello!
    ', + '
    Hello!
    ' => '
    Hello!
    ', + '
    Hello!
    ' => '
    Hello!
    ', + '
    Hello!
    ' => '
    Hello!
    ', + '' => '', + '' => '', + '' => '', + '
    My local image
    ' => '
    ', + '
    My local image
    ' => '
    ', + '
    My local image
    ' => '
    My local image
    ', + '
    cat
    ' => '
    cat
    ', + '' => '', + ]; + + config()->set('app.content_filtering', 'a'); + $page = $this->entities->page(); + $this->asEditor(); + + foreach ($testCasesExpectedByInput as $input => $expected) { + $page->html = $input; + $page->save(); + $resp = $this->get($page->getUrl()); + + $resp->assertSee($expected, false); + $resp->assertDontSee($input, false); + } + } + + public function test_media_protocol_relative_urls_are_given_scheme_depending_on_app_url() + { + $testCasesExpectedByInput = [ + '
    My local image
    ' => '
    My local image
    ', + '' => '', + '' => '', + '' => '', + '
    My local image
    ' => '
    My local image
    ', + ]; + + $baseUrls = ['https://example.com' => 'https', 'http://example.com' => 'http']; + foreach ($baseUrls as $baseUrl => $expectedScheme) { + $this->runWithEnv(['APP_URL' => $baseUrl], function () use ($expectedScheme, $baseUrl, $testCasesExpectedByInput) { + config()->set('app.content_filtering', 'a'); + $page = $this->entities->page(); + $this->asEditor(); + + foreach ($testCasesExpectedByInput as $input => $expected) { + $page->html = $input; + $page->save(); + $resp = $this->get($page->getUrl()); + + $resp->assertSee(str_replace('SCHEME', $expectedScheme, $expected), false); + $resp->assertDontSee($input, false); + } + }); + } + } + + public function test_allow_list_does_not_filter_cases() + { + $testCasesExpectedByInput = [ + '

    New tab linkydoodle

    ', + '

    @mentionusertext

    ', + '

    Link to file

    ', + '

    Link to file

    ', + '

    Link to another section

    ', + '
    Hello

    Mydetailshere

    ', + '
    Hello
    Hello
    ', + ]; + + config()->set('app.content_filtering', 'a'); + $page = $this->entities->page(); + $this->asEditor(); + + foreach ($testCasesExpectedByInput as $input) { + $page->html = $input; + $page->save(); + $resp = $this->get($page->getUrl()); + + $resp->assertSee($input, false); + } + } +} diff --git a/tests/Entity/PageContentTest.php b/tests/Entity/PageContentTest.php index 23a38b5735b..3cbb0e73959 100644 --- a/tests/Entity/PageContentTest.php +++ b/tests/Entity/PageContentTest.php @@ -48,7 +48,7 @@ public function test_saving_page_with_includes() $includeTag = '{{@' . $secondPage->id . '}}'; $page->html = '

    ' . $includeTag . '

    '; - $resp = $this->put($page->getUrl(), ['name' => $page->name, 'html' => $page->html, 'summary' => '']); + $resp = $this->put($page->getUrl(), ['name' => $page->name, 'html' => $page->html, 'changelog' => '']); $resp->assertStatus(302); @@ -101,261 +101,6 @@ public function test_page_includes_to_nonexisting_pages_does_not_error() $pageResp->assertSee('Hello Barry'); } - public function test_page_content_scripts_removed_by_default() - { - $this->asEditor(); - $page = $this->entities->page(); - $script = 'abc123abc123'; - $page->html = "escape {$script}"; - $page->save(); - - $pageView = $this->get($page->getUrl()); - $pageView->assertStatus(200); - $pageView->assertDontSee($script, false); - $pageView->assertSee('abc123abc123'); - } - - public function test_more_complex_content_script_escaping_scenarios() - { - $checks = [ - "

    Some script

    ", - "

    Some script

    ", - "

    Some script

    ", - "

    Some script

    ", - "

    Some script

    ", - "

    Some script

    ", - ]; - - $this->asEditor(); - $page = $this->entities->page(); - - foreach ($checks as $check) { - $page->html = $check; - $page->save(); - - $pageView = $this->get($page->getUrl()); - $pageView->assertStatus(200); - $this->withHtml($pageView)->assertElementNotContains('.page-content', ''); - } - } - - public function test_js_and_base64_src_urls_are_removed() - { - $checks = [ - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - ]; - - $this->asEditor(); - $page = $this->entities->page(); - - foreach ($checks as $check) { - $page->html = $check; - $page->save(); - - $pageView = $this->get($page->getUrl()); - $pageView->assertStatus(200); - $html = $this->withHtml($pageView); - $html->assertElementNotContains('.page-content', ''); - $html->assertElementNotContains('.page-content', 'src='); - $html->assertElementNotContains('.page-content', 'javascript:'); - $html->assertElementNotContains('.page-content', 'data:'); - $html->assertElementNotContains('.page-content', 'base64'); - } - } - - public function test_javascript_uri_links_are_removed() - { - $checks = [ - 'withHtml($pageView)->assertElementNotContains('.page-content', 'href=javascript:'); - } - } - - public function test_form_actions_with_javascript_are_removed() - { - $checks = [ - '
    ', - '
    ', - '
    ', - '
    ', - '
    ', - ]; - - $this->asEditor(); - $page = $this->entities->page(); - - foreach ($checks as $check) { - $page->html = $check; - $page->save(); - - $pageView = $this->get($page->getUrl()); - $pageView->assertStatus(200); - $this->withHtml($pageView)->assertElementNotContains('.page-content', '