From 94eab12aae6ab26fae87bfdc1c246c31739388e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Munsch?= Date: Tue, 28 Sep 2021 12:25:10 +0200 Subject: [PATCH] Ticket 330 - composer require mews/purifier - Add user.name in AddStatusMessage + html tags bold - purify unescaped output --- app/Events/TicketStatusChanged.php | 7 +- app/Listeners/AddStatusMessages.php | 7 +- app/Models/Ticket.php | 2 +- composer.json | 3 +- composer.lock | 137 +++++++++++++++++++++++++- config/purifier.php | 108 ++++++++++++++++++++ resources/views/ticket/show.blade.php | 2 +- 7 files changed, 260 insertions(+), 6 deletions(-) create mode 100644 config/purifier.php diff --git a/app/Events/TicketStatusChanged.php b/app/Events/TicketStatusChanged.php index 804cb3b..9e786d5 100644 --- a/app/Events/TicketStatusChanged.php +++ b/app/Events/TicketStatusChanged.php @@ -3,6 +3,7 @@ namespace App\Events; use App\Models\Ticket; +use App\Models\User; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\SerializesModels; @@ -16,6 +17,9 @@ class TicketStatusChanged /** @var Ticket */ public $ticket; + /** @var User */ + public $user; + public $status; /** @@ -23,9 +27,10 @@ class TicketStatusChanged * * @return void */ - public function __construct(Ticket $ticket, $status) + public function __construct(Ticket $ticket, $status, User $user = null) { $this->ticket = $ticket; $this->status = $status; + $this->user = $user; } } diff --git a/app/Listeners/AddStatusMessages.php b/app/Listeners/AddStatusMessages.php index fa71d25..e0bc59d 100644 --- a/app/Listeners/AddStatusMessages.php +++ b/app/Listeners/AddStatusMessages.php @@ -17,7 +17,12 @@ class AddStatusMessages { $message = new Message(); $message->ticket_id = $event->ticket->id; - $message->message = "Le status est passé à : " . $event->ticket->status->label; + if ($event->user) { + // phpcs:ignore Generic.Files.LineLength.TooLong + $message->message = "{$event->user->name} a modifié le statut en {$event->ticket->status->label}"; + } else { + $message->message = "Le statut est passé à : {$event->ticket->status->label}"; + } $message->save(); } } diff --git a/app/Models/Ticket.php b/app/Models/Ticket.php index 314e7a9..2e359d5 100644 --- a/app/Models/Ticket.php +++ b/app/Models/Ticket.php @@ -44,7 +44,7 @@ class Ticket extends Model static::updating(function (Ticket $ticket) { $oldStatus = Ticket::where('id', $ticket->id)->first()->status; if (!$ticket->status->equals($oldStatus)) { - event(new TicketStatusChanged($ticket, $oldStatus)); + event(new TicketStatusChanged($ticket, $oldStatus, auth()->user())); event(new NotifySubscriptions($ticket, sprintf( 'Le ticket à changé de status : %s', $ticket->status->label diff --git a/composer.json b/composer.json index 311e7a4..699c053 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,8 @@ "laravel-lang/lang": "~8.0", "laravel/framework": "^8.12", "laravel/tinker": "^2.5", - "laravel/ui": "^3.3" + "laravel/ui": "^3.3", + "mews/purifier": "^3.3" }, "require-dev": { "facade/ignition": "^2.5", diff --git a/composer.lock b/composer.lock index 2720737..951be74 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "00fb9cec28ced09a6f6ede716acd4237", + "content-hash": "c6cfdc6c682ed3ffca2b8da4da0b304a", "packages": [ { "name": "asm89/stack-cors", @@ -890,6 +890,60 @@ }, "time": "2019-12-30T22:54:17+00:00" }, + { + "name": "ezyang/htmlpurifier", + "version": "v4.13.0", + "source": { + "type": "git", + "url": "https://github.com/ezyang/htmlpurifier.git", + "reference": "08e27c97e4c6ed02f37c5b2b20488046c8d90d75" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/08e27c97e4c6ed02f37c5b2b20488046c8d90d75", + "reference": "08e27c97e4c6ed02f37c5b2b20488046c8d90d75", + "shasum": "" + }, + "require": { + "php": ">=5.2" + }, + "require-dev": { + "simpletest/simpletest": "dev-master#72de02a7b80c6bb8864ef9bf66d41d2f58f826bd" + }, + "type": "library", + "autoload": { + "psr-0": { + "HTMLPurifier": "library/" + }, + "files": [ + "library/HTMLPurifier.composer.php" + ], + "exclude-from-classmap": [ + "/library/HTMLPurifier/Language/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com" + } + ], + "description": "Standards compliant HTML filter written in PHP", + "homepage": "http://htmlpurifier.org/", + "keywords": [ + "html" + ], + "support": { + "issues": "https://github.com/ezyang/htmlpurifier/issues", + "source": "https://github.com/ezyang/htmlpurifier/tree/master" + }, + "time": "2020-06-29T00:56:53+00:00" + }, { "name": "facade/flare-client-php", "version": "1.8.1", @@ -2230,6 +2284,87 @@ ], "time": "2021-01-18T20:58:21+00:00" }, + { + "name": "mews/purifier", + "version": "3.3.5", + "source": { + "type": "git", + "url": "https://github.com/mewebstudio/Purifier.git", + "reference": "53f2be3b94cf8940d23970f0aeb907ce8c9760f7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mewebstudio/Purifier/zipball/53f2be3b94cf8940d23970f0aeb907ce8c9760f7", + "reference": "53f2be3b94cf8940d23970f0aeb907ce8c9760f7", + "shasum": "" + }, + "require": { + "ezyang/htmlpurifier": "4.13.*", + "illuminate/config": "^5.8|^6.0|^7.0|^8.0", + "illuminate/filesystem": "^5.8|^6.0|^7.0|^8.0", + "illuminate/support": "^5.8|^6.0|^7.0|^8.0", + "php": "^7.2|^8.0" + }, + "require-dev": { + "graham-campbell/testbench": "^3.2|^5.5.1", + "mockery/mockery": "^1.3.3", + "phpunit/phpunit": "^8.0|^9.0" + }, + "suggest": { + "laravel/framework": "To test the Laravel bindings", + "laravel/lumen-framework": "To test the Lumen bindings" + }, + "type": "package", + "extra": { + "laravel": { + "providers": [ + "Mews\\Purifier\\PurifierServiceProvider" + ], + "aliases": { + "Purifier": "Mews\\Purifier\\Facades\\Purifier" + } + } + }, + "autoload": { + "psr-4": { + "Mews\\Purifier\\": "src/" + }, + "files": [ + "src/helpers.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Muharrem ERİN", + "email": "me@mewebstudio.com", + "homepage": "https://github.com/mewebstudio", + "role": "Developer" + } + ], + "description": "Laravel 5/6/7 HtmlPurifier Package", + "homepage": "https://github.com/mewebstudio/purifier", + "keywords": [ + "Purifier", + "htmlpurifier", + "laravel5 HtmlPurifier", + "laravel5 Purifier", + "laravel5 Security", + "laravel6 HtmlPurifier", + "laravel6 Purifier", + "laravel6 Security", + "security", + "xss" + ], + "support": { + "issues": "https://github.com/mewebstudio/Purifier/issues", + "source": "https://github.com/mewebstudio/Purifier/tree/3.3.5" + }, + "time": "2021-05-17T00:17:01+00:00" + }, { "name": "monolog/monolog", "version": "2.3.2", diff --git a/config/purifier.php b/config/purifier.php new file mode 100644 index 0000000..25d357f --- /dev/null +++ b/config/purifier.php @@ -0,0 +1,108 @@ +set('Core.Encoding', $this->config->get('purifier.encoding')); + * $config->set('Cache.SerializerPath', $this->config->get('purifier.cachePath')); + * if ( ! $this->config->get('purifier.finalize')) { + * $config->autoFinalize = false; + * } + * $config->loadArray($this->getConfig()); + * + * You must NOT delete the default settings + * anything in settings should be compacted with params that needed to instance HTMLPurifier_Config. + * + * @link http://htmlpurifier.org/live/configdoc/plain.html + */ + +// phpcs:disable Generic.Files.LineLength.TooLong +return [ + 'encoding' => 'UTF-8', + 'finalize' => true, + 'cachePath' => storage_path('app/purifier'), + 'cacheFileMode' => 0755, + 'settings' => [ + 'default' => [ + 'HTML.Doctype' => 'HTML 4.01 Transitional', + 'HTML.Allowed' => 'h1,h2,h3,h4,h5,h6,div,b,strong,i,em,u,a[href|title],ul,ol,li,p[style],br,span[style],img[width|height|alt|src]', + 'CSS.AllowedProperties' => 'font,font-size,font-weight,font-style,font-family,text-decoration,padding-left,color,background-color,text-align', + 'AutoFormat.AutoParagraph' => false, + 'AutoFormat.RemoveEmpty' => false, + 'AutoFormat.RemoveEmpty.RemoveNbsp' => false, + ], + 'test' => [ + 'Attr.EnableID' => 'true', + ], + "youtube" => [ + "HTML.SafeIframe" => 'true', + "URI.SafeIframeRegexp" => "%^(http://|https://|//)(www.youtube.com/embed/|player.vimeo.com/video/)%", + ], + 'custom_definition' => [ + 'id' => 'html5-definitions', + 'rev' => 1, + 'debug' => false, + 'elements' => [ + // http://developers.whatwg.org/sections.html + ['section', 'Block', 'Flow', 'Common'], + ['nav', 'Block', 'Flow', 'Common'], + ['article', 'Block', 'Flow', 'Common'], + ['aside', 'Block', 'Flow', 'Common'], + ['header', 'Block', 'Flow', 'Common'], + ['footer', 'Block', 'Flow', 'Common'], + + // Content model actually excludes several tags, not modelled here + ['address', 'Block', 'Flow', 'Common'], + ['hgroup', 'Block', 'Required: h1 | h2 | h3 | h4 | h5 | h6', 'Common'], + + // http://developers.whatwg.org/grouping-content.html + ['figure', 'Block', 'Optional: (figcaption, Flow) | (Flow, figcaption) | Flow', 'Common'], + ['figcaption', 'Inline', 'Flow', 'Common'], + + // http://developers.whatwg.org/the-video-element.html#the-video-element + ['video', 'Block', 'Optional: (source, Flow) | (Flow, source) | Flow', 'Common', [ + 'src' => 'URI', + 'type' => 'Text', + 'width' => 'Length', + 'height' => 'Length', + 'poster' => 'URI', + 'preload' => 'Enum#auto,metadata,none', + 'controls' => 'Bool', + ]], + ['source', 'Block', 'Flow', 'Common', [ + 'src' => 'URI', + 'type' => 'Text', + ]], + + // http://developers.whatwg.org/text-level-semantics.html + ['s', 'Inline', 'Inline', 'Common'], + ['var', 'Inline', 'Inline', 'Common'], + ['sub', 'Inline', 'Inline', 'Common'], + ['sup', 'Inline', 'Inline', 'Common'], + ['mark', 'Inline', 'Inline', 'Common'], + ['wbr', 'Inline', 'Empty', 'Core'], + + // http://developers.whatwg.org/edits.html + ['ins', 'Block', 'Flow', 'Common', ['cite' => 'URI', 'datetime' => 'CDATA']], + ['del', 'Block', 'Flow', 'Common', ['cite' => 'URI', 'datetime' => 'CDATA']], + ], + 'attributes' => [ + ['iframe', 'allowfullscreen', 'Bool'], + ['table', 'height', 'Text'], + ['td', 'border', 'Text'], + ['th', 'border', 'Text'], + ['tr', 'width', 'Text'], + ['tr', 'height', 'Text'], + ['tr', 'border', 'Text'], + ], + ], + 'custom_attributes' => [ + ['a', 'target', 'Enum#_blank,_self,_target,_top'], + ], + 'custom_elements' => [ + ['u', 'Inline', 'Inline', 'Common'], + ], + ], + +]; diff --git a/resources/views/ticket/show.blade.php b/resources/views/ticket/show.blade.php index 6b562e9..dbeba5e 100644 --- a/resources/views/ticket/show.blade.php +++ b/resources/views/ticket/show.blade.php @@ -96,7 +96,7 @@ @foreach ($messages as $message) @if ($message->user_id === null)
- {!! nl2br(e($message->message)) !!} - Le {{ \Carbon\Carbon::parse($message->created_at)->format('d/m/Y à H:i')}} + {!! nl2br(clean($message->message)) !!} - Le {{ \Carbon\Carbon::parse($message->created_at)->format('d/m/Y à H:i')}} (Message système)
@else