freescout-help-desk / freescout

FreeScout — Free self-hosted help desk & shared mailbox (Zendesk / Help Scout alternative)
https://freescout.net
GNU Affero General Public License v3.0
3.04k stars 497 forks source link

Large message body issue #3057

Closed radarsymphony closed 1 year ago

radarsymphony commented 1 year ago

Summary

We are experiencing an issue related to purifying html when pasting it into the body of message. When we paste an image into a google doc, and then copy the image out of the doc and paste it into the message body, the conversation appears "blank" or empty when viewed in the inbox. (see logs below)

System Specs

PHP version: 8.2 FreeScout version: 1.8.77

Steps to Replicate

  1. Open up a blank google doc.
  2. Expand the section below, Right-click on the puppy photo and select Copy Image (firefox).
    Example Image

image

Source http://inspirationseek.com/wp-content/uploads/2016/02/Cute-Dog-Photography.jpg

  1. Paste the photo into the google doc.
  2. Add one "new line return" after image.
  3. Go open up a new conversation in Freescout instance.
  4. Go back to the google doc with the image and Right-click and select Copy
  5. Paste image into the new conversation body.
  6. Add recipient and subject and send.
  7. Click on the Mine view in sidebar.
  8. Locate pending conversation and open it.
  9. Message should appear "blank" or empty.

Current Behavior

When some content types are pasted into the Freescout conversation body and sent, Freescout returns a strip_tags(): Passing null to parameter #1 ($string) of type string is deprecated error in the Send Logs. The message usually sends. However, on several occasions the message lands in the job queue and after a few days does return an error to the original sender (see screenshots below). In these cases, the message does not send. (We are still working to understand circumstances that cause the message to fail entirely.)

Additional aspects of behavior

Additional actions that may lead to error

The following seem to cause the error. We are still investigating to better identify the consistent steps to replicate.

Expected Behavior

Pasted content is successfully purified and able to be displayed in the Freescout conversation view. If the message is undeliverable, the original sender/inbox is notified.

Screenshots & Logs

Blank message

image

Send Logs screenshot

image

Example of message that failed to send

image

Full stack trace

freescout/laravel.log ``` [2023-05-29 16:57:04] production.ERROR: strip_tags(): Passing null to parameter #1 ($string) of type string is deprecated (View: /www/html/resources/views/emails/customer/reply_fancy_text.blade.php) {"exception":"[object] (ErrorException(code: 0): strip_tags(): Passing null to parameter #1 ($string) of type string is deprecated (View: /www/html/resources/views/emails/customer/reply_fancy_text.blade.php) at /www/html/vendor/html2text/html2text/src/Html2Text.php:371, ErrorException(code: 0): strip_tags(): Passing null to parameter #1 ($string) of type string is deprecated at /www/html/vendor/html2text/html2text/src/Html2Text.php:371) [stacktrace] #0 /www/html/vendor/laravel/framework/src/Illuminate/View/Engines/PhpEngine.php(45): Illuminate\\View\\Engines\\CompilerEngine->handleViewException(Object(ErrorException), 0) #1 /www/html/vendor/laravel/framework/src/Illuminate/View/Engines/CompilerEngine.php(59): Illuminate\\View\\Engines\\PhpEngine->evaluatePath('/data/storage/f...', Array) #2 /www/html/overrides/laravel/framework/src/Illuminate/View/View.php(137): Illuminate\\View\\Engines\\CompilerEngine->get('/www/html/resou...', Array) #3 /www/html/overrides/laravel/framework/src/Illuminate/View/View.php(120): Illuminate\\View\\View->getContents() #4 /www/html/overrides/laravel/framework/src/Illuminate/View/View.php(85): Illuminate\\View\\View->renderContents() #5 /www/html/vendor/laravel/framework/src/Illuminate/Mail/Mailer.php(328): Illuminate\\View\\View->render() #6 /www/html/vendor/laravel/framework/src/Illuminate/Mail/Mailer.php(307): Illuminate\\Mail\\Mailer->renderView('emails/customer...', Array) #7 /www/html/vendor/laravel/framework/src/Illuminate/Mail/Mailer.php(218): Illuminate\\Mail\\Mailer->addContent(Object(Illuminate\\Mail\\Message), 'emails/customer...', 'emails/customer...', NULL, Array) #8 /www/html/vendor/laravel/framework/src/Illuminate/Mail/Mailable.php(119): Illuminate\\Mail\\Mailer->send('emails/customer...', Array, Object(Closure)) #9 /www/html/vendor/laravel/framework/src/Illuminate/Mail/Mailer.php(250): Illuminate\\Mail\\Mailable->send(Object(Illuminate\\Mail\\Mailer)) #10 /www/html/vendor/laravel/framework/src/Illuminate/Mail/Mailer.php(205): Illuminate\\Mail\\Mailer->sendMailable(Object(App\\Mail\\ReplyToCustomer)) #11 /www/html/vendor/laravel/framework/src/Illuminate/Mail/PendingMail.php(99): Illuminate\\Mail\\Mailer->send(Object(App\\Mail\\ReplyToCustomer)) #12 /www/html/app/Jobs/SendReplyToCustomer.php(240): Illuminate\\Mail\\PendingMail->send(Object(App\\Mail\\ReplyToCustomer)) #13 [internal function]: App\\Jobs\\SendReplyToCustomer->handle() #14 /www/html/overrides/laravel/framework/src/Illuminate/Container/BoundMethod.php(28): call_user_func_array(Array, Array) #15 /www/html/overrides/laravel/framework/src/Illuminate/Container/BoundMethod.php(87): Illuminate\\Container\\BoundMethod::Illuminate\\Container\\{closure}() #16 /www/html/overrides/laravel/framework/src/Illuminate/Container/BoundMethod.php(27): Illuminate\\Container\\BoundMethod::callBoundMethod(Object(Illuminate\\Foundation\\Application), Array, Object(Closure)) #17 /www/html/overrides/laravel/framework/src/Illuminate/Container/Container.php(549): Illuminate\\Container\\BoundMethod::call(Object(Illuminate\\Foundation\\Application), Array, Array, NULL) #18 /www/html/vendor/laravel/framework/src/Illuminate/Bus/Dispatcher.php(94): Illuminate\\Container\\Container->call(Array) #19 /www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(114): Illuminate\\Bus\\Dispatcher->Illuminate\\Bus\\{closure}(Object(App\\Jobs\\SendReplyToCustomer)) #20 /www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(102): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(App\\Jobs\\SendReplyToCustomer)) #21 /www/html/vendor/laravel/framework/src/Illuminate/Bus/Dispatcher.php(98): Illuminate\\Pipeline\\Pipeline->then(Object(Closure)) #22 /www/html/vendor/laravel/framework/src/Illuminate/Queue/CallQueuedHandler.php(48): Illuminate\\Bus\\Dispatcher->dispatchNow(Object(App\\Jobs\\SendReplyToCustomer), false) #23 /www/html/vendor/laravel/framework/src/Illuminate/Queue/Jobs/Job.php(76): Illuminate\\Queue\\CallQueuedHandler->call(Object(Illuminate\\Queue\\Jobs\\DatabaseJob), Array) #24 /www/html/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(320): Illuminate\\Queue\\Jobs\\Job->fire() #25 /www/html/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(270): Illuminate\\Queue\\Worker->process('database', Object(Illuminate\\Queue\\Jobs\\DatabaseJob), Object(Illuminate\\Queue\\WorkerOptions)) #26 /www/html/vendor/laravel/framework/src/Illuminate/Queue/Worker.php(114): Illuminate\\Queue\\Worker->runJob(Object(Illuminate\\Queue\\Jobs\\DatabaseJob), 'database', Object(Illuminate\\Queue\\WorkerOptions)) #27 /www/html/vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(100): Illuminate\\Queue\\Worker->daemon('database', 'emails,default,...', Object(Illuminate\\Queue\\WorkerOptions)) #28 /www/html/vendor/laravel/framework/src/Illuminate/Queue/Console/WorkCommand.php(84): Illuminate\\Queue\\Console\\WorkCommand->runWorker('database', 'emails,default,...') #29 [internal function]: Illuminate\\Queue\\Console\\WorkCommand->handle() #30 /www/html/overrides/laravel/framework/src/Illuminate/Container/BoundMethod.php(28): call_user_func_array(Array, Array) #31 /www/html/overrides/laravel/framework/src/Illuminate/Container/BoundMethod.php(87): Illuminate\\Container\\BoundMethod::Illuminate\\Container\\{closure}() #32 /www/html/overrides/laravel/framework/src/Illuminate/Container/BoundMethod.php(27): Illuminate\\Container\\BoundMethod::callBoundMethod(Object(Illuminate\\Foundation\\Application), Array, Object(Closure)) #33 /www/html/overrides/laravel/framework/src/Illuminate/Container/Container.php(549): Illuminate\\Container\\BoundMethod::call(Object(Illuminate\\Foundation\\Application), Array, Array, NULL) #34 /www/html/vendor/laravel/framework/src/Illuminate/Console/Command.php(183): Illuminate\\Container\\Container->call(Array) #35 /www/html/vendor/symfony/console/Command/Command.php(255): Illuminate\\Console\\Command->execute(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Illuminate\\Console\\OutputStyle)) #36 /www/html/vendor/laravel/framework/src/Illuminate/Console/Command.php(169): Symfony\\Component\\Console\\Command\\Command->run(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Illuminate\\Console\\OutputStyle)) #37 /www/html/vendor/symfony/console/Application.php(992): Illuminate\\Console\\Command->run(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput)) #38 /www/html/vendor/symfony/console/Application.php(255): Symfony\\Component\\Console\\Application->doRunCommand(Object(Illuminate\\Queue\\Console\\WorkCommand), Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput)) #39 /www/html/vendor/symfony/console/Application.php(148): Symfony\\Component\\Console\\Application->doRun(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput)) #40 /www/html/vendor/laravel/framework/src/Illuminate/Console/Application.php(88): Symfony\\Component\\Console\\Application->run(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput)) #41 /www/html/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(121): Illuminate\\Console\\Application->run(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput)) #42 /www/html/artisan(60): Illuminate\\Foundation\\Console\\Kernel->handle(Object(Symfony\\Component\\Console\\Input\\ArgvInput), Object(Symfony\\Component\\Console\\Output\\ConsoleOutput)) #43 {main} "} ```

Potential Solutions

Source code files referenced:

Similar issue regarding a deprecation of passing null to parameter of type string: https://github.com/freescout-helpdesk/freescout/issues/3020

This user suggested adding a null check before calling the function. The current line 371:

        $text = strip_tags($text);

Modified line:

        $text = (!is_null($text) && strip_tags($text));

That being said, I don't know php very well and this seems like only half the solution. I haven't been able to identify why this $text parameter is null to begin with.

I'll add addition details as I identify them. The main concern right now is that the blank conversation is disconcerting for some users who think the message hasn't sent and the strip_tags error in the Send Log is also displayed when messages fail to send.

Please let me know what additional information I can provide to help with troubleshooting.

radarsymphony commented 1 year ago

Persistent Google HTML

Inspecting the Original of the messages that look "blank" shows that they still retain html from the google docs (e.g., span elements, google-specific ids, etc).

image

HTML of body with image that caused Blank Message

<div><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;" id="docs-internal-guid-4f7ccf59-7fff-1a4a-0a27-1bd0845d5de7"><span style="border:none;display:inline-block;overflow:hidden;width:624px;height:391px;"><img src="data:image/png;base64, ...

HTML of body with image that did not cause error/issue

<p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;" id="docs-internal-guid-ffdc140a-7fff-50ec-4779-4462f17bc2a9"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;"><span style="border:none;display:inline-block;overflow:hidden;width:474px;height:411px;"><img src="data:image/png;base64, ...
freescout-helpdesk commented 1 year ago

HTML of body with image that caused Blank Message

Could you please attach full HTML.

radarsymphony commented 1 year ago

For sure! Attached to this comment you should find the full html for the blank email (4.2MiB) which contained an image and no text.

20230530_freescout-blank-email.txt

radarsymphony commented 1 year ago

I also tested on Freescout v1.8.78 with php8.1. I was able to replicate with that setup too.

freescout-helpdesk commented 1 year ago

Fixed in the master branch. It should work with new messages.

radarsymphony commented 1 year ago

I was able to test the changes in master on a development instance and they have resolved the "blank conversation" issue I was seeing. Thank you for the quick work on this.