diff --git a/app/Services/SecurityMonitor.php b/app/Services/SecurityMonitor.php index 20a2b7e..20b23ce 100644 --- a/app/Services/SecurityMonitor.php +++ b/app/Services/SecurityMonitor.php @@ -5,6 +5,7 @@ namespace App\Services; use App\Models\SecurityAttempt; use Illuminate\Http\Request; use Illuminate\Support\Facades\Log; +use Illuminate\Support\Str; use Throwable; class SecurityMonitor @@ -103,23 +104,6 @@ class SecurityMonitor return false; } - public function getAttemptsFromIp(string $ip, int $hours = 24): int - { - try { - return SecurityAttempt::query() - ->fromIp($ip) - ->recent($hours) - ->count(); - } catch (Throwable) { - return 0; - } - } - - public function isIpSuspicious(string $ip, int $threshold = 10, int $hours = 24): bool - { - return $this->getAttemptsFromIp($ip, $hours) >= $threshold; - } - private function extractComponentName(Request $request): ?string { try { @@ -224,14 +208,6 @@ class SecurityMonitor private function truncate(?string $value, int $length): ?string { - if ($value === null) { - return null; - } - - if (strlen($value) <= $length) { - return $value; - } - - return substr($value, 0, $length - 3).'...'; + return $value === null ? null : Str::limit($value, $length - 3); } } diff --git a/composer.json b/composer.json index 72424d7..0df5c81 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,6 @@ "php": "^8.3", "akuechler/laravel-geoly": "^1.0", "archtechx/enums": "^1.1", - "calebporzio/sushi": "^2.5", "laravel/framework": "^13.0", "laravel/nightwatch": "^1.22", "laravel/reverb": "^1.0", @@ -21,11 +20,9 @@ "livewire/livewire": "^4.0", "livewire/volt": "^1.0", "openspout/openspout": "^5.0", - "power-components/livewire-powergrid": "^6.7", "pusher/pusher-php-server": "^7.2.2", "ralphjsmit/laravel-seo": "^1.7", "sentry/sentry-laravel": "^4.9", - "simplesoftwareio/simple-qrcode": "^4.2", "spatie/image": "^3.7", "spatie/laravel-backup": "^10.0", "spatie/laravel-ciphersweet": "^1.6", diff --git a/composer.lock b/composer.lock index 10588db..a748f28 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": "095f8204681ac28f647e13614de92c7d", + "content-hash": "c17c932d5926ab29b7fc71839f5b066b", "packages": [ { "name": "akuechler/laravel-geoly", @@ -117,60 +117,6 @@ }, "time": "2025-06-06T23:15:09+00:00" }, - { - "name": "bacon/bacon-qr-code", - "version": "2.0.8", - "source": { - "type": "git", - "url": "https://github.com/Bacon/BaconQrCode.git", - "reference": "8674e51bb65af933a5ffaf1c308a660387c35c22" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/8674e51bb65af933a5ffaf1c308a660387c35c22", - "reference": "8674e51bb65af933a5ffaf1c308a660387c35c22", - "shasum": "" - }, - "require": { - "dasprid/enum": "^1.0.3", - "ext-iconv": "*", - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "phly/keep-a-changelog": "^2.1", - "phpunit/phpunit": "^7 | ^8 | ^9", - "spatie/phpunit-snapshot-assertions": "^4.2.9", - "squizlabs/php_codesniffer": "^3.4" - }, - "suggest": { - "ext-imagick": "to generate QR code images" - }, - "type": "library", - "autoload": { - "psr-4": { - "BaconQrCode\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-2-Clause" - ], - "authors": [ - { - "name": "Ben Scholzen 'DASPRiD'", - "email": "mail@dasprids.de", - "homepage": "https://dasprids.de/", - "role": "Developer" - } - ], - "description": "BaconQrCode is a QR code generator for PHP.", - "homepage": "https://github.com/Bacon/BaconQrCode", - "support": { - "issues": "https://github.com/Bacon/BaconQrCode/issues", - "source": "https://github.com/Bacon/BaconQrCode/tree/2.0.8" - }, - "time": "2022-12-07T17:46:57+00:00" - }, { "name": "bitwasp/bech32", "version": "v0.0.1", @@ -276,60 +222,6 @@ ], "time": "2026-06-14T18:21:03+00:00" }, - { - "name": "calebporzio/sushi", - "version": "v2.5.4", - "source": { - "type": "git", - "url": "https://github.com/calebporzio/sushi.git", - "reference": "ef71a031f78a80b0ed82ce51fc5b648c01145281" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/calebporzio/sushi/zipball/ef71a031f78a80b0ed82ce51fc5b648c01145281", - "reference": "ef71a031f78a80b0ed82ce51fc5b648c01145281", - "shasum": "" - }, - "require": { - "ext-pdo_sqlite": "*", - "ext-sqlite3": "*", - "illuminate/database": "^5.8 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0 || ^13.0", - "illuminate/support": "^5.8 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0 || ^13.0", - "php": "^7.1.3|^8.0" - }, - "require-dev": { - "doctrine/dbal": "^2.9 || ^3.1.4", - "orchestra/testbench": "3.8.* || 3.9.* || ^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0 || ^11.0", - "phpunit/phpunit": "^7.5 || ^8.4 || ^9.0 || ^10.0 || ^11.0 || ^12.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "Sushi\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Caleb Porzio", - "email": "calebporzio@gmail.com" - } - ], - "description": "Eloquent's missing \"array\" driver.", - "support": { - "source": "https://github.com/calebporzio/sushi/tree/v2.5.4" - }, - "funding": [ - { - "url": "https://github.com/calebporzio", - "type": "github" - } - ], - "time": "2026-02-21T02:53:22+00:00" - }, { "name": "carbonphp/carbon-doctrine-types", "version": "3.2.0", @@ -606,56 +498,6 @@ ], "time": "2025-08-20T19:15:30+00:00" }, - { - "name": "dasprid/enum", - "version": "1.0.7", - "source": { - "type": "git", - "url": "https://github.com/DASPRiD/Enum.git", - "reference": "b5874fa9ed0043116c72162ec7f4fb50e02e7cce" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/DASPRiD/Enum/zipball/b5874fa9ed0043116c72162ec7f4fb50e02e7cce", - "reference": "b5874fa9ed0043116c72162ec7f4fb50e02e7cce", - "shasum": "" - }, - "require": { - "php": ">=7.1 <9.0" - }, - "require-dev": { - "phpunit/phpunit": "^7 || ^8 || ^9 || ^10 || ^11", - "squizlabs/php_codesniffer": "*" - }, - "type": "library", - "autoload": { - "psr-4": { - "DASPRiD\\Enum\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-2-Clause" - ], - "authors": [ - { - "name": "Ben Scholzen 'DASPRiD'", - "email": "mail@dasprids.de", - "homepage": "https://dasprids.de/", - "role": "Developer" - } - ], - "description": "PHP 7.1 enum implementation", - "keywords": [ - "enum", - "map" - ], - "support": { - "issues": "https://github.com/DASPRiD/Enum/issues", - "source": "https://github.com/DASPRiD/Enum/tree/1.0.7" - }, - "time": "2025-09-16T12:23:56+00:00" - }, { "name": "dflydev/dot-access-data", "version": "v3.0.3", @@ -4928,84 +4770,6 @@ }, "time": "2026-06-22T14:53:45+00:00" }, - { - "name": "power-components/livewire-powergrid", - "version": "v6.10.3", - "source": { - "type": "git", - "url": "https://github.com/Power-Components/livewire-powergrid.git", - "reference": "77557ae0d59b32715c73ebcfc0c3ba3612d44d37" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Power-Components/livewire-powergrid/zipball/77557ae0d59b32715c73ebcfc0c3ba3612d44d37", - "reference": "77557ae0d59b32715c73ebcfc0c3ba3612d44d37", - "shasum": "" - }, - "require": { - "laravel/prompts": "*", - "livewire/livewire": "^3.7|^4.0", - "php": "^8.2" - }, - "require-dev": { - "composer/composer": "^2.8", - "laradumps/laradumps": "^4.6", - "larastan/larastan": "^2.0|^3.0", - "laravel/pint": "^1.26", - "laravel/scout": "^10.11.3", - "openspout/openspout": "^4.24.5|^5.0", - "orchestra/testbench": "^9.4|^10.0", - "pestphp/pest": "^3.0|^4.0" - }, - "suggest": { - "openspout/openspout": "Required to export XLS and CSV" - }, - "type": "library", - "extra": { - "laravel": { - "providers": [ - "PowerComponents\\LivewirePowerGrid\\Providers\\PowerGridServiceProvider" - ] - } - }, - "autoload": { - "files": [ - "src/functions.php" - ], - "psr-4": { - "PowerComponents\\LivewirePowerGrid\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Luan Freitas", - "email": "luanfreitas10@protonmail.com", - "role": "Developer" - }, - { - "name": "DanSysAnalyst", - "email": "daniel@sysanalyst.eu", - "role": "Developer" - } - ], - "description": "PowerGrid generates Advanced Datatables using Laravel Livewire.", - "homepage": "https://github.com/power-components/livewire-powergrid", - "support": { - "issues": "https://github.com/Power-Components/livewire-powergrid/issues", - "source": "https://github.com/Power-Components/livewire-powergrid/tree/v6.10.3" - }, - "funding": [ - { - "url": "https://github.com/luanfreitasdev", - "type": "github" - } - ], - "time": "2026-05-23T13:11:25+00:00" - }, { "name": "psr/clock", "version": "1.0.0", @@ -6681,74 +6445,6 @@ ], "time": "2026-06-11T13:22:14+00:00" }, - { - "name": "simplesoftwareio/simple-qrcode", - "version": "4.2.0", - "source": { - "type": "git", - "url": "https://github.com/SimpleSoftwareIO/simple-qrcode.git", - "reference": "916db7948ca6772d54bb617259c768c9cdc8d537" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/SimpleSoftwareIO/simple-qrcode/zipball/916db7948ca6772d54bb617259c768c9cdc8d537", - "reference": "916db7948ca6772d54bb617259c768c9cdc8d537", - "shasum": "" - }, - "require": { - "bacon/bacon-qr-code": "^2.0", - "ext-gd": "*", - "php": ">=7.2|^8.0" - }, - "require-dev": { - "mockery/mockery": "~1", - "phpunit/phpunit": "~9" - }, - "suggest": { - "ext-imagick": "Allows the generation of PNG QrCodes.", - "illuminate/support": "Allows for use within Laravel." - }, - "type": "library", - "extra": { - "laravel": { - "aliases": { - "QrCode": "SimpleSoftwareIO\\QrCode\\Facades\\QrCode" - }, - "providers": [ - "SimpleSoftwareIO\\QrCode\\QrCodeServiceProvider" - ] - } - }, - "autoload": { - "psr-4": { - "SimpleSoftwareIO\\QrCode\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Simple Software LLC", - "email": "support@simplesoftware.io" - } - ], - "description": "Simple QrCode is a QR code generator made for Laravel.", - "homepage": "https://www.simplesoftware.io/#/docs/simple-qrcode", - "keywords": [ - "Simple", - "generator", - "laravel", - "qrcode", - "wrapper" - ], - "support": { - "issues": "https://github.com/SimpleSoftwareIO/simple-qrcode/issues", - "source": "https://github.com/SimpleSoftwareIO/simple-qrcode/tree/4.2.0" - }, - "time": "2021-02-08T20:43:55+00:00" - }, { "name": "simplito/bigint-wrapper-php", "version": "1.0.0", diff --git a/config/livewire-powergrid.php b/config/livewire-powergrid.php deleted file mode 100644 index 40251f8..0000000 --- a/config/livewire-powergrid.php +++ /dev/null @@ -1,160 +0,0 @@ - Tailwind::class, - // 'theme' => \PowerComponents\LivewirePowerGrid\Themes\Bootstrap5::class, - - /* - |-------------------------------------------------------------------------- - | Plugins - |-------------------------------------------------------------------------- - | - | Plugins used: flatpickr.js to datepicker. - | - */ - - 'plugins' => [ - /* - * https://flatpickr.js.org - */ - 'flatpickr' => [ - 'locales' => [ - 'de_DE' => [ - 'locale' => 'de', - 'dateFormat' => 'd.m.Y H:i', - 'enableTime' => true, - 'time_24hr' => true, - ], - ], - ], - - 'select' => [ - 'default' => 'tom', - - /* - * TomSelect Options - * https://tom-select.js.org - */ - 'tom' => [ - 'plugins' => [ - 'clear_button' => [ - 'title' => 'Remove all selected options', - ], - ], - ], - - /* - * Slim Select options - * https://slimselectjs.com/ - */ - 'slim' => [ - 'settings' => [ - 'alwaysOpen' => false, - ], - ], - ], - ], - - /* - |-------------------------------------------------------------------------- - | Filters - |-------------------------------------------------------------------------- - | - | PowerGrid supports inline and outside filters. - | 'inline': Filters data inside the table. - | 'outside': Filters data outside the table. - | 'null' - | - */ - - 'filter' => 'outside', - - /* - |-------------------------------------------------------------------------- - | Persisting - |-------------------------------------------------------------------------- - | - | PowerGrid supports persisting of the filters, columns and sorting. - | 'session': persist in the session. - | 'cache': persist with cache. - | 'cookies': persist with cookies (default). - | - */ - - 'persist_driver' => 'cookies', - - /* - |-------------------------------------------------------------------------- - | Cache - |-------------------------------------------------------------------------- - | - | Cache is enabled by default to improve search performance when using collections. - | When enabled, data is reloaded whenever the page is refreshed or a field is updated. - | - */ - - 'cached_data' => true, - - /* - |-------------------------------------------------------------------------- - | New Release Notification - |-------------------------------------------------------------------------- - | - | PowerGrid can verify if a new release is available when you create a new PowerGrid Table. - | - | This feature depends on composer/composer. - | To install, run: `composer require composer/composer --dev` - | - */ - - 'check_version' => false, - - /* - |-------------------------------------------------------------------------- - | Exportable class - |-------------------------------------------------------------------------- - | - | - */ - - 'exportable' => [ - 'default' => 'openspout_v5', - 'openspout_v5' => [ - 'xlsx' => ExportToXLS::class, - 'csv' => ExportToCsv::class, - ], - 'openspout_v4' => [ - 'xlsx' => PowerComponents\LivewirePowerGrid\Components\Exports\OpenSpout\v4\ExportToXLS::class, - 'csv' => PowerComponents\LivewirePowerGrid\Components\Exports\OpenSpout\v4\ExportToCsv::class, - ], - ], - - /* - |-------------------------------------------------------------------------- - | Auto-Discover Models - |-------------------------------------------------------------------------- - | - | PowerGrid will search for Models in the directories listed below. - | These Models be listed as options when you run the - | "artisan powergrid:create" command. - | - */ - - 'auto_discover_models_paths' => [ - app_path('Models'), - ], -]; diff --git a/package.json b/package.json index ebbf72c..6a988a5 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,7 @@ "postcss": "^8.4.41", "pusher-js": "^8.4.0", "tailwindcss": "^4.1.18", - "vite": "^8.0.0", - "webln": "^0.3.2" + "vite": "^8.0.0" }, "dependencies": { "@tailwindcss/vite": "^4.1.18", diff --git a/resources/css/app.css b/resources/css/app.css index 9af377e..ec49739 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -18,7 +18,6 @@ ----------------------------------------- */ @import "tailwindcss"; @import "../../vendor/livewire/flux/dist/flux.css"; -@import '../../vendor/power-components/livewire-powergrid/resources/css/tailwind4.css'; @import "./theme.css"; @import "./base.css"; @import "./utilities.css"; @@ -32,8 +31,6 @@ ----------------------------------------- */ @source "../views/**/*.blade.php"; @source "../js/**/*.js"; -@source '../../vendor/power-components/livewire-powergrid/src/Themes/Tailwind.php'; -@source '../../vendor/power-components/livewire-powergrid/resources/views/**/*.php'; @source "../../vendor/livewire/flux/dist/**/*.blade.php"; /* ---------------------------------------- diff --git a/resources/js/bootstrap.js b/resources/js/bootstrap.js index be9b50c..e2712dc 100644 --- a/resources/js/bootstrap.js +++ b/resources/js/bootstrap.js @@ -1,7 +1,5 @@ // import './echo'; -import './../../vendor/power-components/livewire-powergrid/dist/powergrid' - import flatpickr from 'flatpickr'; import 'flatpickr/dist/flatpickr.min.css'; diff --git a/tests/Feature/SecurityMonitorTest.php b/tests/Feature/SecurityMonitorTest.php index 727dd02..e0f96f3 100644 --- a/tests/Feature/SecurityMonitorTest.php +++ b/tests/Feature/SecurityMonitorTest.php @@ -89,45 +89,6 @@ it('never throws exceptions itself', function () { expect(true)->toBeTrue(); }); -it('tracks attempts from same IP', function () { - $exception = new CannotUpdateLockedPropertyException('test'); - - $request = Request::create('/livewire/update', 'POST', [ - 'components' => [ - ['snapshot' => '{}', 'updates' => []], - ], - ], server: ['REMOTE_ADDR' => '192.168.1.100']); - - $request->setRouteResolver(fn () => null); - - // Record multiple attempts - $this->monitor->recordFromException($exception, $request); - $this->monitor->recordFromException($exception, $request); - $this->monitor->recordFromException($exception, $request); - - expect($this->monitor->getAttemptsFromIp('192.168.1.100'))->toBe(3); -}); - -it('identifies suspicious IPs', function () { - $exception = new CannotUpdateLockedPropertyException('test'); - - $request = Request::create('/livewire/update', 'POST', [ - 'components' => [ - ['snapshot' => '{}', 'updates' => []], - ], - ], server: ['REMOTE_ADDR' => '10.0.0.1']); - - $request->setRouteResolver(fn () => null); - - // Record 10 attempts (threshold) - for ($i = 0; $i < 10; $i++) { - $this->monitor->recordFromException($exception, $request); - } - - expect($this->monitor->isIpSuspicious('10.0.0.1', threshold: 10))->toBeTrue() - ->and($this->monitor->isIpSuspicious('10.0.0.2', threshold: 10))->toBeFalse(); -}); - it('truncates long values', function () { $exception = new CannotUpdateLockedPropertyException('test'); diff --git a/yarn.lock b/yarn.lock index f1b123b..a260331 100644 --- a/yarn.lock +++ b/yarn.lock @@ -500,25 +500,6 @@ dependencies: tslib "^2.4.0" -"@types/chrome@^0.0.74": - version "0.0.74" - resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.74.tgz#f69827c48fcf7fecc90c96089807661749a5a5e3" - integrity sha512-hzosS5CkQcIKCgxcsV2AzbJ36KNxG/Db2YEN/erEu7Boprg+KpMDLBQqKFmSo+JkQMGqRcicUyqCowJpuT+C6A== - dependencies: - "@types/filesystem" "*" - -"@types/filesystem@*": - version "0.0.36" - resolved "https://registry.yarnpkg.com/@types/filesystem/-/filesystem-0.0.36.tgz#7227c2d76bfed1b21819db310816c7821d303857" - integrity sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA== - dependencies: - "@types/filewriter" "*" - -"@types/filewriter@*": - version "0.0.33" - resolved "https://registry.yarnpkg.com/@types/filewriter/-/filewriter-0.0.33.tgz#d9d611db9d9cd99ae4e458de420eeb64ad604ea8" - integrity sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g== - "@types/hast@^3.0.0", "@types/hast@^3.0.4": version "3.0.4" resolved "https://registry.yarnpkg.com/@types/hast/-/hast-3.0.4.tgz#1d6b39993b82cea6ad783945b0508c25903e15aa" @@ -1312,13 +1293,6 @@ vite@^8.0.0: optionalDependencies: fsevents "~2.3.3" -webln@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/webln/-/webln-0.3.2.tgz#bbadf52916666b6059e3661ef5ab73a76b7cd0f4" - integrity sha512-YYT83aOCLup2AmqvJdKtdeBTaZpjC6/JDMe8o6x1kbTYWwiwrtWHyO//PAsPixF3jwFsAkj5DmiceB6w/QSe7Q== - dependencies: - "@types/chrome" "^0.0.74" - wrap-ansi@^9.0.0: version "9.0.2" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-9.0.2.tgz#956832dea9494306e6d209eb871643bb873d7c98"