Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions chatwoot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Chatwoot Widget (by Boy132)

Adds a Chatwoot live chat widget to all panels for real-time customer support.

## Features

- Chatwoot live chat integration
- Configurable through plugin settings

## Credits

Original Tawk.to widget by Boy132. Edited by Philip E to work with Chatwoot.
6 changes: 6 additions & 0 deletions chatwoot/config/chatwoot.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php

return [
'base_url' => env('CHATWOOT_BASE_URL'),
'website_token' => env('CHATWOOT_WEBSITE_TOKEN'),
];
15 changes: 15 additions & 0 deletions chatwoot/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"id": "chatwoot",
"name": "Chatwoot",
"author": "Boy132 (edited by Philip E)",
"version": "1.0.0",
"description": "Adds a Chatwoot widget to all panels",
"category": "plugin",
"url": "https://github.com/pelican-dev/plugins/tree/main/chatwoot",
"update_url": null,
"namespace": "Boy132\\Chatwoot",
"class": "ChatwootPlugin",
"panels": null,
"panel_version": null,
"composer_packages": null
}
47 changes: 47 additions & 0 deletions chatwoot/src/ChatwootPlugin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

namespace Boy132\Chatwoot;

use App\Contracts\Plugins\HasPluginSettings;
use App\Traits\EnvironmentWriterTrait;
use Filament\Contracts\Plugin;
use Filament\Forms\Components\TextInput;
use Filament\Notifications\Notification;
use Filament\Panel;

class ChatwootPlugin implements HasPluginSettings, Plugin {
use EnvironmentWriterTrait;

public function getId(): string {
return 'chatwoot';
}

public function register(Panel $panel): void {}

public function boot(Panel $panel): void {}

public function getSettingsForm(): array {
return [
TextInput::make('base_url')
->label('Base URL')
->required()
->default(fn () => config('chatwoot.base_url')),
TextInput::make('website_token')
->label('Website Token')
->required()
->default(fn () => config('chatwoot.website_token')),
];
}

public function saveSettings(array $data): void {
$this->writeToEnvironment([
'CHATWOOT_BASE_URL' => $data['base_url'],
'CHATWOOT_WEBSITE_TOKEN' => $data['website_token'],
]);

Notification::make()
->title('Settings saved')
->success()
->send();
}
Comment on lines +12 to +46
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix Pint style: opening braces on their own line for class and all methods.

The Lint pipeline is failing (class_definition, braces_position, single_class_elements). Move every { on the class/method signature lines to the next line.

🎨 Proposed fix
-class ChatwootPlugin implements HasPluginSettings, Plugin {
+class ChatwootPlugin implements HasPluginSettings, Plugin
+{
     use EnvironmentWriterTrait;

-    public function getId(): string {
+    public function getId(): string
+    {
         return 'chatwoot';
     }

     public function register(Panel $panel): void {}

     public function boot(Panel $panel): void {}

-    public function getSettingsForm(): array {
+    public function getSettingsForm(): array
+    {
         return [
             ...
         ];
     }

-    public function saveSettings(array $data): void {
+    public function saveSettings(array $data): void
+    {
         $this->writeToEnvironment([
             ...
         ]);
         ...
     }
 }
🧰 Tools
🪛 PHPMD (2.15.0)

[warning] 19-19: Avoid unused parameters such as '$panel'. (undefined)

(UnusedFormalParameter)


[warning] 21-21: Avoid unused parameters such as '$panel'. (undefined)

(UnusedFormalParameter)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@chatwoot/src/ChatwootPlugin.php` around lines 12 - 46, The class and method
opening braces must be moved to their own lines to satisfy Pint rules: update
the ChatwootPlugin class declaration and every method signature (getId,
register, boot, getSettingsForm, saveSettings) so the "{" is on the next line
(e.g., change "class ChatwootPlugin implements HasPluginSettings, Plugin {" to
have the "{" on a new line, and do the same for each function declaration).
Ensure all method-level braces and the class-level brace follow this style
consistently to resolve class_definition, braces_position, and
single_class_elements lint errors.

}
44 changes: 44 additions & 0 deletions chatwoot/src/Providers/ChatwootPluginProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

namespace Boy132\Chatwoot\Providers;

use Filament\Support\Facades\FilamentView;
use Filament\View\PanelsRenderHook;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;

class ChatwootPluginProvider extends ServiceProvider {
public function boot(): void {
Comment on lines +10 to +11
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix Pint style: opening braces must be on their own line.

The Lint pipeline is failing (class_definition, brace). PSR-12/Pint requires class and method opening braces on the next line.

🎨 Proposed fix
-class ChatwootPluginProvider extends ServiceProvider {
-    public function boot(): void {
+class ChatwootPluginProvider extends ServiceProvider
+{
+    public function boot(): void
+    {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
class ChatwootPluginProvider extends ServiceProvider {
public function boot(): void {
class ChatwootPluginProvider extends ServiceProvider
{
public function boot(): void
{
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@chatwoot/src/Providers/ChatwootPluginProvider.php` around lines 10 - 11, The
class and method opening braces are on the same line which violates PSR-12/Pint;
update the class ChatwootPluginProvider and its method boot() so each opening
brace is placed on the following line (i.e., put the "{" for class
ChatwootPluginProvider on its own line and likewise put the "{" for public
function boot() on the next line) to satisfy the class_definition and brace lint
rules.

$baseUrl = config('chatwoot.base_url');
$websiteToken = config('chatwoot.website_token');

if ($baseUrl && $websiteToken) {
FilamentView::registerRenderHook(
PanelsRenderHook::STYLES_BEFORE,
fn () => Blade::render(<<<'HTML'
<!--Start of Chatwoot Script-->
<script type="text/javascript">
(function(d,t) {
var BASE_URL="{{ $baseUrl }}";
var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
g.src=BASE_URL+"/packs/js/sdk.js";
g.defer = true;
g.async = true;
s.parentNode.insertBefore(g,s);
g.onload=function(){
window.chatwootSDK.run({
websiteToken: '{{ $websiteToken }}',
baseUrl: BASE_URL
})
}
})(document,"script");
</script>
<!--End of Chatwoot Script-->
HTML, [
'baseUrl' => $baseUrl,
'websiteToken' => $websiteToken,
])
Comment on lines +18 to +40
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Laravel Blade Js::from helper for safely embedding PHP values into JavaScript

💡 Result:

The Laravel Blade Js::from helper, part of Illuminate\Support\Js, safely embeds PHP values into JavaScript by converting them to properly escaped JavaScript expressions. It handles objects and arrays by base64-encoding JSON and wrapping in JSON.parse(atob('...')), strings with single quotes and escapes, and other types via json_encode. Use it in Blade templates as {{ Js::from($value) }} or {{ \Illuminate\Support\Js::from($value) }}. Example: <script> var app = {{ Js::from($array) }}; </script> This ensures safe inclusion within HTML attributes or scripts, preventing XSS from unescaped JSON. Recent Laravel versions (e.g., 13.x) include a Js facade alias for convenience. There's also an undocumented @js($value) Blade directive that wraps Js::from. Official docs confirm: "The from method accepts the same arguments as PHP's json_encode function; however, it will ensure that the resulting JSON has been properly escaped for inclusion within HTML quotes." Only use with existing variables, not complex expressions.

Citations:


JS-escape interpolated values in the injected <script>.

{{ $websiteToken }} and {{ $baseUrl }} are HTML-escaped by Blade, but they're rendered inside JavaScript string literals. Values containing ', \, newline, or </script> can break out of the JS context and execute arbitrary code. Use Illuminate\Support\Js::from() (or the @js directive) to safely serialize these values for JavaScript.

🔒 Proposed fix using Js::from()
                 <script type="text/javascript">
                     (function(d,t) {
-                        var BASE_URL="{{ $baseUrl }}";
+                        var BASE_URL={!! \Illuminate\Support\Js::from($baseUrl) !!};
                         var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
-                        g.src=BASE_URL+"/packs/js/sdk.js";
+                        g.src=BASE_URL.replace(/\/$/, "")+"/packs/js/sdk.js";
                         g.defer = true;
                         g.async = true;
                         s.parentNode.insertBefore(g,s);
                         g.onload=function(){
                             window.chatwootSDK.run({
-                                websiteToken: '{{ $websiteToken }}',
+                                websiteToken: {!! \Illuminate\Support\Js::from($websiteToken) !!},
                                 baseUrl: BASE_URL
                             })
                         }
                     })(document,"script");
                 </script>
             HTML, [
-                    'baseUrl' => $baseUrl,
-                    'websiteToken' => $websiteToken,
+                    'baseUrlJs' => \Illuminate\Support\Js::from($baseUrl),
+                    'websiteTokenJs' => \Illuminate\Support\Js::from($websiteToken),
                 ])

(The replace(/\/$/, "") also defends against a trailing slash in the base URL yielding …//packs/js/sdk.js.)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@chatwoot/src/Providers/ChatwootPluginProvider.php` around lines 18 - 40, The
injected script currently interpolates Blade-escaped strings directly into JS
string literals causing possible JS injection; update the Blade::render call to
serialize the values with Illuminate\Support\Js::from() (or the `@js` directive)
so baseUrl and websiteToken are safely JS-encoded before being used in the
script where window.chatwootSDK.run is called; also normalize baseUrl to remove
a trailing slash (so the computed g.src = baseUrl + "/packs/js/sdk.js" never
produces a double slash) and reference the serialized values (Js::from($baseUrl)
and Js::from($websiteToken)) instead of raw {{ $baseUrl }} / {{ $websiteToken }}
inside the Blade::render template.

);
}
}
}
Loading