diff --git a/.env.example b/.env.example
index bbe856a..3189c76 100644
--- a/.env.example
+++ b/.env.example
@@ -1,4 +1,5 @@
DOCKER_NGINX_PORT=8080
+DOCKER_WEBSOCKET_PORT=8081
DOCKER_DB_PORT=3306
MYSQL_ROOT_PASSWORD=root_pass
DB_DATABASE=captcha
diff --git a/app/application/.env.example b/app/application/.env.example
index 78bdd22..278c1d2 100644
--- a/app/application/.env.example
+++ b/app/application/.env.example
@@ -72,3 +72,21 @@ VITE_PUSHER_HOST="${PUSHER_HOST}"
VITE_PUSHER_PORT="${PUSHER_PORT}"
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
+
+REVERB_APP_ID=
+REVERB_APP_KEY=
+REVERB_APP_SECRET=
+REVERB_HOST="reverb"
+REVERB_PORT=9000
+REVERB_SCHEME=http
+# * or localhost.com or localhost.com, localhost.net
+REVERB_ALLOWED_ORIGINS="*"
+
+REVERB_HOST_CLIENT="localhost"
+REVERB_PORT_CLIENT=8081
+REVERB_SCHEME_CLIENT=http
+
+VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
+VITE_REVERB_HOST="${REVERB_HOST}"
+VITE_REVERB_PORT="${REVERB_PORT}"
+VITE_REVERB_SCHEME="${REVERB_SCHEME}"
diff --git a/app/application/app/Broadcasting/CreatedCaptchaLog.php b/app/application/app/Broadcasting/CreatedCaptchaLog.php
new file mode 100644
index 0000000..fa8f7ec
--- /dev/null
+++ b/app/application/app/Broadcasting/CreatedCaptchaLog.php
@@ -0,0 +1,17 @@
+can('viewAny', CaptchaToken::class);
+ }
+}
diff --git a/app/application/app/Dto/Repository/CaptchaLogRepository/QuantityByDays.php b/app/application/app/Dto/Repository/CaptchaLogRepository/QuantityByDays.php
new file mode 100644
index 0000000..27fd89a
--- /dev/null
+++ b/app/application/app/Dto/Repository/CaptchaLogRepository/QuantityByDays.php
@@ -0,0 +1,38 @@
+days[$day])) {
+ $this->days[$day] = [];
+ }
+ $this->days[$day][$type->value] = $count;
+ }
+
+ /**
+ * @param string $day ("Y-m-d")
+ * @return array
+ */
+ public function getDay(string $day): array
+ {
+ return $this->days[$day] ?? [];
+ }
+
+ public function getDays(): array
+ {
+ return $this->days;
+ }
+}
diff --git a/app/application/app/Enums/CaptchaLogType.php b/app/application/app/Enums/CaptchaLogType.php
index 8d9147d..3e4c678 100644
--- a/app/application/app/Enums/CaptchaLogType.php
+++ b/app/application/app/Enums/CaptchaLogType.php
@@ -8,4 +8,9 @@ enum CaptchaLogType: int
case Error = 2;
case Verified = 3;
case ReadVerified = 4;
+
+ public function getTitle(): string
+ {
+ return __('captcha_log_type.' . $this->name);
+ }
}
diff --git a/app/application/app/Events/CreatedCaptchaLog.php b/app/application/app/Events/CreatedCaptchaLog.php
new file mode 100644
index 0000000..3a99380
--- /dev/null
+++ b/app/application/app/Events/CreatedCaptchaLog.php
@@ -0,0 +1,47 @@
+chartCaptchaActivity = [
+ 'date' => $captchaLog->created_at->format('Y-m-d'),
+ 'meta' => $captchaLog->type->getTitle(),
+ 'type' => $captchaLog->type->value,
+ ];
+ $link = '';
+ $title = '';
+ if ($captchaLog->captcha && $captchaLog->captcha->captchaToken) {
+ $link = route('captcha-tokens.edit', ['captcha_token' => $captchaLog->captcha->captcha_token_id], false);
+ $title = $captchaLog->captcha->captchaToken->title;
+ }
+ $this->captchaLog = [
+ 'created_at' => $captchaLog->created_at->format("d.m.Y H:i:s"),
+ 'link' => $link,
+ 'title' => $title,
+ 'type' => $captchaLog->type->getTitle(),
+ 'ip' => $captchaLog->ip,
+ 'user_agent' => $captchaLog->user_agent,
+ 'referer' => $captchaLog->referer,
+ ];
+ }
+
+ public function broadcastOn(): Channel
+ {
+ return new PrivateChannel('chart-captcha-activity');
+ }
+}
diff --git a/app/application/app/Http/Controllers/Private/DashboardController.php b/app/application/app/Http/Controllers/Private/DashboardController.php
index 8d1cade..508a25c 100644
--- a/app/application/app/Http/Controllers/Private/DashboardController.php
+++ b/app/application/app/Http/Controllers/Private/DashboardController.php
@@ -2,12 +2,42 @@
namespace App\Http\Controllers\Private;
+use App\Http\Resources\Private\Dashboard\ChartCaptchaActivity;
+use App\Services\Private\DashboardService;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+use Illuminate\Support\Carbon;
use Illuminate\View\View;
final class DashboardController extends Controller
{
- public function index(): View
+ public function __construct(
+ private readonly DashboardService $dashboardService,
+ ) { }
+
+ public function index(Request $request): View
{
- return view('private/dashboard/index');
+ $user = $request->user();
+ $limit = 30;
+ $with = ['captcha', 'captcha.captchaToken'];
+ $result = $this->dashboardService->captchaLog($user, $limit, $with);
+ if ($result->isError()) {
+ $this->errors($result);
+ }
+
+ return view('private/dashboard/index', $result->getData());
+ }
+
+ public function chartCaptchaActivity(Request $request): JsonResponse
+ {
+ $user = $request->user();
+ $from = Carbon::now()->subDays(7);
+ $to = Carbon::now();
+ $result = $this->dashboardService->chartCaptchaActivity($user, $from, $to);
+ if (!$result->isSuccess()) {
+ return response()->json($result->getData())->setStatusCode($result->getCode());
+ }
+
+ return response()->json(new ChartCaptchaActivity($result));
}
}
diff --git a/app/application/app/Http/Controllers/Private/WebsocketsController.php b/app/application/app/Http/Controllers/Private/WebsocketsController.php
new file mode 100644
index 0000000..d49e825
--- /dev/null
+++ b/app/application/app/Http/Controllers/Private/WebsocketsController.php
@@ -0,0 +1,24 @@
+websocketService->settings();
+ if (!$result->isSuccess()) {
+ return response()->json($result->getData())->setStatusCode($result->getCode());
+ }
+
+ return response()->json(new Setting($result));
+ }
+}
diff --git a/app/application/app/Http/Resources/Private/Dashboard/ChartCaptchaActivity.php b/app/application/app/Http/Resources/Private/Dashboard/ChartCaptchaActivity.php
new file mode 100644
index 0000000..b4f6969
--- /dev/null
+++ b/app/application/app/Http/Resources/Private/Dashboard/ChartCaptchaActivity.php
@@ -0,0 +1,53 @@
+resource->getFrom()->diff($this->resource->getTo())->stepBy('day');
+ $days = [];
+ $values = [];
+ $types = [];
+ foreach (CaptchaLogType::cases() as $type) {
+ $values[$type->value] = [];
+ $types[$type->value] = [
+ 'meta' => $type->getTitle(),
+ 'value' => 0,
+ ];
+ }
+ foreach ($period as $item) {
+ $day = $item->format('Y-m-d');
+ $days[] = $day;
+ $quantity = $this->resource->getQuantityByDays()->getDay($day);
+ foreach (CaptchaLogType::cases() as $type) {
+ $values[$type->value][] = [
+ 'meta' => $type->getTitle(),
+ 'value' => $quantity[$type->value] ?? 0,
+ ];
+ }
+ }
+
+ return [
+ 'days' => $days,
+ 'values' => $values,
+ 'types' => $types,
+ ];
+ }
+}
diff --git a/app/application/app/Http/Resources/Private/Websockets/Setting.php b/app/application/app/Http/Resources/Private/Websockets/Setting.php
new file mode 100644
index 0000000..1050164
--- /dev/null
+++ b/app/application/app/Http/Resources/Private/Websockets/Setting.php
@@ -0,0 +1,31 @@
+ $this->resource->getKey(),
+ 'wsHost' => $this->resource->getWsHost(),
+ 'wsPort' => $this->resource->getWsPort(),
+ 'wssPort' => $this->resource->getWssPort(),
+ 'forceTLS' => $this->resource->isForceTLS(),
+ ];
+ }
+}
diff --git a/app/application/app/Models/Captcha.php b/app/application/app/Models/Captcha.php
index 37ed7a9..f173e4b 100644
--- a/app/application/app/Models/Captcha.php
+++ b/app/application/app/Models/Captcha.php
@@ -4,6 +4,7 @@
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
final class Captcha extends Model
@@ -34,4 +35,9 @@ public function captchaLogs(): HasMany
{
return $this->hasMany(CaptchaLog::class);
}
+
+ public function captchaToken(): BelongsTo
+ {
+ return $this->belongsTo(CaptchaToken::class);
+ }
}
diff --git a/app/application/app/Models/CaptchaLog.php b/app/application/app/Models/CaptchaLog.php
index ce5df82..86cd5bb 100644
--- a/app/application/app/Models/CaptchaLog.php
+++ b/app/application/app/Models/CaptchaLog.php
@@ -6,6 +6,7 @@
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
final class CaptchaLog extends Model
{
@@ -44,4 +45,9 @@ public function scopeLatest(Builder $query): Builder
{
return $query->orderBy('created_at', 'desc');
}
+
+ public function captcha(): BelongsTo
+ {
+ return $this->belongsTo(Captcha::class);
+ }
}
diff --git a/app/application/app/Repositories/CaptchaLogRepository.php b/app/application/app/Repositories/CaptchaLogRepository.php
index a778315..cc5d03e 100644
--- a/app/application/app/Repositories/CaptchaLogRepository.php
+++ b/app/application/app/Repositories/CaptchaLogRepository.php
@@ -2,13 +2,30 @@
namespace App\Repositories;
+use App\Dto\Repository\CaptchaLogRepository\QuantityByDays;
use App\Enums\CaptchaLogType;
use App\Models\CaptchaLog;
+use App\Services\Search\CreateSearchInstanceCommand;
+use App\Services\Search\Search;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
+use Illuminate\Support\Carbon;
final class CaptchaLogRepository
{
+ public function __construct(
+ private CreateSearchInstanceCommand $createSearchInstanceCommand,
+ ) { }
+
+ public function getCaptchaLogs(array $with = []): Search
+ {
+ $query = CaptchaLog::query()
+ ->with($with)
+ ->latest();
+
+ return $this->createSearchInstanceCommand->execute($query);
+ }
+
public function countByType(CaptchaLogType $type, ?int $captchaId = null): int
{
return CaptchaLog::query()
@@ -32,4 +49,22 @@ public function getCaptchaLogsByTypes(array $types, ?int $captchaId = null, ?int
->latest()
->get();
}
+
+ public function countByDays(Carbon $from, Carbon $to): QuantityByDays
+ {
+ $count = CaptchaLog::query()
+ ->selectRaw('DATE_FORMAT(created_at, \'%Y-%m-%d\') AS date, type, COUNT(id) AS count')
+ ->where('created_at', '>=', $from)
+ ->where('created_at', '<=', $to)
+ ->groupBy('date', 'type')
+ ->orderBy('date', 'asc')
+ ->get();
+
+ $quantity = new QuantityByDays();
+ foreach ($count as $item) {
+ $quantity->add($item->date, $item->type, $item->count);
+ }
+
+ return $quantity;
+ }
}
diff --git a/app/application/app/ServiceResults/Private/Dashboard/ChartCaptchaActivity.php b/app/application/app/ServiceResults/Private/Dashboard/ChartCaptchaActivity.php
new file mode 100644
index 0000000..6015d57
--- /dev/null
+++ b/app/application/app/ServiceResults/Private/Dashboard/ChartCaptchaActivity.php
@@ -0,0 +1,31 @@
+from;
+ }
+
+ public function getTo(): Carbon
+ {
+ return $this->to;
+ }
+
+ public function getQuantityByDays(): QuantityByDays
+ {
+ return $this->quantityByDays;
+ }
+}
diff --git a/app/application/app/ServiceResults/Private/Websocket/Setting.php b/app/application/app/ServiceResults/Private/Websocket/Setting.php
new file mode 100644
index 0000000..bb21eea
--- /dev/null
+++ b/app/application/app/ServiceResults/Private/Websocket/Setting.php
@@ -0,0 +1,41 @@
+key;
+ }
+
+ public function getWsHost(): string
+ {
+ return $this->wsHost;
+ }
+
+ public function getWsPort(): int
+ {
+ return $this->wsPort;
+ }
+
+ public function getWssPort(): int
+ {
+ return $this->wssPort;
+ }
+
+ public function isForceTLS(): bool
+ {
+ return $this->forceTLS;
+ }
+}
diff --git a/app/application/app/Services/CaptchaLog/CaptchaLogHandler.php b/app/application/app/Services/CaptchaLog/CaptchaLogHandler.php
index bba2f51..871cc7a 100644
--- a/app/application/app/Services/CaptchaLog/CaptchaLogHandler.php
+++ b/app/application/app/Services/CaptchaLog/CaptchaLogHandler.php
@@ -4,6 +4,7 @@
use App\Dto\HttpUserData;
use App\Enums\CaptchaLogType;
+use App\Events\CreatedCaptchaLog;
use App\Models\Captcha;
use App\Models\CaptchaLog;
use Illuminate\Support\Str;
@@ -22,12 +23,16 @@ public function handleStore(int $captchaId, CaptchaLogType $captchaLogType, Http
$referer = Str::limit($referer, 10000, '');
}
- return CaptchaLog::create([
+ $captchaLog = CaptchaLog::create([
'captcha_id' => $captchaId,
'type' => $captchaLogType,
'ip' => $httpUserData->getClientIp(),
'user_agent' => $userAgent,
'referer' => $referer,
]);
+
+ CreatedCaptchaLog::dispatch($captchaLog);
+
+ return $captchaLog;
}
}
diff --git a/app/application/app/Services/Private/DashboardService.php b/app/application/app/Services/Private/DashboardService.php
new file mode 100644
index 0000000..d43ce26
--- /dev/null
+++ b/app/application/app/Services/Private/DashboardService.php
@@ -0,0 +1,54 @@
+cannot('viewAny', CaptchaToken::class)) {
+ return $this->result([
+ 'items' => collect([]),
+ 'user' => $user,
+ ]);
+ }
+
+ return $this->result([
+ 'items' => $this->captchaLogRepository->getCaptchaLogs($with)->get($limit),
+ 'user' => $user,
+ ]);
+ }
+
+ public function chartCaptchaActivity(User $user, Carbon $from, Carbon $to): ServiceResultError | ChartCaptchaActivity
+ {
+ if ($user->cannot('viewAny', CaptchaToken::class)) {
+ return $this->errFobidden(__('Access is denied'));
+ }
+
+ if ($to < $from) {
+ return $this->errValidate(__('From cannot be greater than To'));
+ }
+
+ $quantity = $this->captchaLogRepository->countByDays($from, $to);
+
+ return new ChartCaptchaActivity(
+ from: $from,
+ to: $to,
+ quantityByDays: $quantity,
+ );
+ }
+}
diff --git a/app/application/app/Services/Private/WebsocketService.php b/app/application/app/Services/Private/WebsocketService.php
new file mode 100644
index 0000000..e82fea5
--- /dev/null
+++ b/app/application/app/Services/Private/WebsocketService.php
@@ -0,0 +1,24 @@
+=5.3"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "Clue\\Redis\\Protocol": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@lueck.tv"
+ }
+ ],
+ "description": "A streaming redis wire protocol parser and serializer implementation in PHP",
+ "homepage": "https://github.com/clue/php-redis-protocol",
+ "keywords": [
+ "parser",
+ "protocol",
+ "redis",
+ "serializer",
+ "streaming"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/php-redis-protocol/issues",
+ "source": "https://github.com/clue/php-redis-protocol/tree/v0.3.1"
+ },
+ "time": "2017-06-06T16:07:10+00:00"
+ },
+ {
+ "name": "clue/redis-react",
+ "version": "v2.7.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/clue/reactphp-redis.git",
+ "reference": "2283690f249e8d93342dd63b5285732d2654e077"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/clue/reactphp-redis/zipball/2283690f249e8d93342dd63b5285732d2654e077",
+ "reference": "2283690f249e8d93342dd63b5285732d2654e077",
+ "shasum": ""
+ },
+ "require": {
+ "clue/redis-protocol": "0.3.*",
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3",
+ "react/event-loop": "^1.2",
+ "react/promise": "^3 || ^2.0 || ^1.1",
+ "react/promise-timer": "^1.9",
+ "react/socket": "^1.12"
+ },
+ "require-dev": {
+ "clue/block-react": "^1.5",
+ "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Clue\\React\\Redis\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "description": "Async Redis client implementation, built on top of ReactPHP.",
+ "homepage": "https://github.com/clue/reactphp-redis",
+ "keywords": [
+ "async",
+ "client",
+ "database",
+ "reactphp",
+ "redis"
+ ],
+ "support": {
+ "issues": "https://github.com/clue/reactphp-redis/issues",
+ "source": "https://github.com/clue/reactphp-redis/tree/v2.7.0"
+ },
+ "funding": [
+ {
+ "url": "https://clue.engineering/support",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/clue",
+ "type": "github"
+ }
+ ],
+ "time": "2024-01-05T15:54:20+00:00"
+ },
{
"name": "dflydev/dot-access-data",
"version": "v3.0.2",
@@ -501,6 +617,53 @@
],
"time": "2023-10-06T06:47:41+00:00"
},
+ {
+ "name": "evenement/evenement",
+ "version": "v3.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/igorw/evenement.git",
+ "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/igorw/evenement/zipball/0a16b0d71ab13284339abb99d9d2bd813640efbc",
+ "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9 || ^6"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Evenement\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Igor Wiedler",
+ "email": "igor@wiedler.ch"
+ }
+ ],
+ "description": "Événement is a very simple event dispatching library for PHP",
+ "keywords": [
+ "event-dispatcher",
+ "event-emitter"
+ ],
+ "support": {
+ "issues": "https://github.com/igorw/evenement/issues",
+ "source": "https://github.com/igorw/evenement/tree/v3.0.2"
+ },
+ "time": "2023-08-08T05:53:35+00:00"
+ },
{
"name": "fruitcake/php-cors",
"version": "v1.3.0",
@@ -1357,6 +1520,88 @@
},
"time": "2024-04-18T00:45:25+00:00"
},
+ {
+ "name": "laravel/reverb",
+ "version": "v1.0.0-beta9",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/laravel/reverb.git",
+ "reference": "46d768c88755ba17224c3f3dcdddf24b0e4fe4f8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/laravel/reverb/zipball/46d768c88755ba17224c3f3dcdddf24b0e4fe4f8",
+ "reference": "46d768c88755ba17224c3f3dcdddf24b0e4fe4f8",
+ "shasum": ""
+ },
+ "require": {
+ "clue/redis-react": "^2.6",
+ "guzzlehttp/psr7": "^2.6",
+ "illuminate/console": "^10.47|^11.0",
+ "illuminate/contracts": "^10.47|^11.0",
+ "illuminate/http": "^10.47|^11.0",
+ "illuminate/support": "^10.47|^11.0",
+ "laravel/prompts": "^0.1.15",
+ "php": "^8.2",
+ "pusher/pusher-php-server": "^7.2",
+ "ratchet/rfc6455": "^0.3.1",
+ "react/promise-timer": "^1.10",
+ "react/socket": "^1.14",
+ "symfony/console": "^6.0|^7.0",
+ "symfony/http-foundation": "^6.3|^7.0"
+ },
+ "require-dev": {
+ "orchestra/testbench": "^8.0|^9.0",
+ "pestphp/pest": "^2.0",
+ "phpstan/phpstan": "^1.10",
+ "ratchet/pawl": "^0.4.1",
+ "react/async": "^4.0",
+ "react/http": "^1.9"
+ },
+ "type": "library",
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Laravel\\Reverb\\ApplicationManagerServiceProvider",
+ "Laravel\\Reverb\\ReverbServiceProvider"
+ ],
+ "aliases": {
+ "Output": "Laravel\\Reverb\\Output"
+ }
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Laravel\\Reverb\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Taylor Otwell",
+ "email": "taylor@laravel.com"
+ },
+ {
+ "name": "Joe Dixon",
+ "email": "joe@laravel.com"
+ }
+ ],
+ "description": "Laravel Reverb provides a real-time WebSocket communication backend for Laravel applications.",
+ "keywords": [
+ "WebSockets",
+ "laravel",
+ "real-time",
+ "websocket"
+ ],
+ "support": {
+ "issues": "https://github.com/laravel/reverb/issues",
+ "source": "https://github.com/laravel/reverb/tree/v1.0.0-beta9"
+ },
+ "time": "2024-04-25T07:20:24+00:00"
+ },
{
"name": "laravel/sanctum",
"version": "v4.0.2",
@@ -2441,6 +2686,142 @@
],
"time": "2024-03-06T16:17:14+00:00"
},
+ {
+ "name": "paragonie/random_compat",
+ "version": "v9.99.100",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/paragonie/random_compat.git",
+ "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a",
+ "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">= 7"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "4.*|5.*",
+ "vimeo/psalm": "^1"
+ },
+ "suggest": {
+ "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
+ },
+ "type": "library",
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Paragon Initiative Enterprises",
+ "email": "security@paragonie.com",
+ "homepage": "https://paragonie.com"
+ }
+ ],
+ "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
+ "keywords": [
+ "csprng",
+ "polyfill",
+ "pseudorandom",
+ "random"
+ ],
+ "support": {
+ "email": "info@paragonie.com",
+ "issues": "https://github.com/paragonie/random_compat/issues",
+ "source": "https://github.com/paragonie/random_compat"
+ },
+ "time": "2020-10-15T08:29:30+00:00"
+ },
+ {
+ "name": "paragonie/sodium_compat",
+ "version": "v1.21.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/paragonie/sodium_compat.git",
+ "reference": "bb312875dcdd20680419564fe42ba1d9564b9e37"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/bb312875dcdd20680419564fe42ba1d9564b9e37",
+ "reference": "bb312875dcdd20680419564fe42ba1d9564b9e37",
+ "shasum": ""
+ },
+ "require": {
+ "paragonie/random_compat": ">=1",
+ "php": "^5.2.4|^5.3|^5.4|^5.5|^5.6|^7|^8"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^3|^4|^5|^6|^7|^8|^9"
+ },
+ "suggest": {
+ "ext-libsodium": "PHP < 7.0: Better performance, password hashing (Argon2i), secure memory management (memzero), and better security.",
+ "ext-sodium": "PHP >= 7.0: Better performance, password hashing (Argon2i), secure memory management (memzero), and better security."
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "autoload.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "ISC"
+ ],
+ "authors": [
+ {
+ "name": "Paragon Initiative Enterprises",
+ "email": "security@paragonie.com"
+ },
+ {
+ "name": "Frank Denis",
+ "email": "jedisct1@pureftpd.org"
+ }
+ ],
+ "description": "Pure PHP implementation of libsodium; uses the PHP extension if it exists",
+ "keywords": [
+ "Authentication",
+ "BLAKE2b",
+ "ChaCha20",
+ "ChaCha20-Poly1305",
+ "Chapoly",
+ "Curve25519",
+ "Ed25519",
+ "EdDSA",
+ "Edwards-curve Digital Signature Algorithm",
+ "Elliptic Curve Diffie-Hellman",
+ "Poly1305",
+ "Pure-PHP cryptography",
+ "RFC 7748",
+ "RFC 8032",
+ "Salpoly",
+ "Salsa20",
+ "X25519",
+ "XChaCha20-Poly1305",
+ "XSalsa20-Poly1305",
+ "Xchacha20",
+ "Xsalsa20",
+ "aead",
+ "cryptography",
+ "ecdh",
+ "elliptic curve",
+ "elliptic curve cryptography",
+ "encryption",
+ "libsodium",
+ "php",
+ "public-key cryptography",
+ "secret-key cryptography",
+ "side-channel resistant"
+ ],
+ "support": {
+ "issues": "https://github.com/paragonie/sodium_compat/issues",
+ "source": "https://github.com/paragonie/sodium_compat/tree/v1.21.1"
+ },
+ "time": "2024-04-22T22:05:04+00:00"
+ },
{
"name": "phpoption/phpoption",
"version": "1.9.2",
@@ -3007,6 +3388,67 @@
},
"time": "2024-04-02T15:57:53+00:00"
},
+ {
+ "name": "pusher/pusher-php-server",
+ "version": "7.2.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/pusher/pusher-http-php.git",
+ "reference": "de2f72296808f9cafa6a4462b15a768ff130cddb"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/pusher/pusher-http-php/zipball/de2f72296808f9cafa6a4462b15a768ff130cddb",
+ "reference": "de2f72296808f9cafa6a4462b15a768ff130cddb",
+ "shasum": ""
+ },
+ "require": {
+ "ext-curl": "*",
+ "ext-json": "*",
+ "guzzlehttp/guzzle": "^7.2",
+ "paragonie/sodium_compat": "^1.6",
+ "php": "^7.3|^8.0",
+ "psr/log": "^1.0|^2.0|^3.0"
+ },
+ "require-dev": {
+ "overtrue/phplint": "^2.3",
+ "phpunit/phpunit": "^9.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Pusher\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Library for interacting with the Pusher REST API",
+ "keywords": [
+ "events",
+ "messaging",
+ "php-pusher-server",
+ "publish",
+ "push",
+ "pusher",
+ "real time",
+ "real-time",
+ "realtime",
+ "rest",
+ "trigger"
+ ],
+ "support": {
+ "issues": "https://github.com/pusher/pusher-http-php/issues",
+ "source": "https://github.com/pusher/pusher-http-php/tree/7.2.4"
+ },
+ "time": "2023-12-15T10:58:53+00:00"
+ },
{
"name": "ralouphie/getallheaders",
"version": "3.0.3",
@@ -3232,6 +3674,593 @@
],
"time": "2023-11-08T05:53:05+00:00"
},
+ {
+ "name": "ratchet/rfc6455",
+ "version": "v0.3.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/ratchetphp/RFC6455.git",
+ "reference": "7c964514e93456a52a99a20fcfa0de242a43ccdb"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/ratchetphp/RFC6455/zipball/7c964514e93456a52a99a20fcfa0de242a43ccdb",
+ "reference": "7c964514e93456a52a99a20fcfa0de242a43ccdb",
+ "shasum": ""
+ },
+ "require": {
+ "guzzlehttp/psr7": "^2 || ^1.7",
+ "php": ">=5.4.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^5.7",
+ "react/socket": "^1.3"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Ratchet\\RFC6455\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "role": "Developer"
+ },
+ {
+ "name": "Matt Bonneau",
+ "role": "Developer"
+ }
+ ],
+ "description": "RFC6455 WebSocket protocol handler",
+ "homepage": "http://socketo.me",
+ "keywords": [
+ "WebSockets",
+ "rfc6455",
+ "websocket"
+ ],
+ "support": {
+ "chat": "https://gitter.im/reactphp/reactphp",
+ "issues": "https://github.com/ratchetphp/RFC6455/issues",
+ "source": "https://github.com/ratchetphp/RFC6455/tree/v0.3.1"
+ },
+ "time": "2021-12-09T23:20:49+00:00"
+ },
+ {
+ "name": "react/cache",
+ "version": "v1.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/cache.git",
+ "reference": "d47c472b64aa5608225f47965a484b75c7817d5b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/cache/zipball/d47c472b64aa5608225f47965a484b75c7817d5b",
+ "reference": "d47c472b64aa5608225f47965a484b75c7817d5b",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0",
+ "react/promise": "^3.0 || ^2.0 || ^1.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\Cache\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Async, Promise-based cache interface for ReactPHP",
+ "keywords": [
+ "cache",
+ "caching",
+ "promise",
+ "reactphp"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/cache/issues",
+ "source": "https://github.com/reactphp/cache/tree/v1.2.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2022-11-30T15:59:55+00:00"
+ },
+ {
+ "name": "react/dns",
+ "version": "v1.12.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/dns.git",
+ "reference": "c134600642fa615b46b41237ef243daa65bb64ec"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/dns/zipball/c134600642fa615b46b41237ef243daa65bb64ec",
+ "reference": "c134600642fa615b46b41237ef243daa65bb64ec",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0",
+ "react/cache": "^1.0 || ^0.6 || ^0.5",
+ "react/event-loop": "^1.2",
+ "react/promise": "^3.0 || ^2.7 || ^1.2.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
+ "react/async": "^4 || ^3 || ^2",
+ "react/promise-timer": "^1.9"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\Dns\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Async DNS resolver for ReactPHP",
+ "keywords": [
+ "async",
+ "dns",
+ "dns-resolver",
+ "reactphp"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/dns/issues",
+ "source": "https://github.com/reactphp/dns/tree/v1.12.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2023-11-29T12:41:06+00:00"
+ },
+ {
+ "name": "react/event-loop",
+ "version": "v1.5.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/event-loop.git",
+ "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/event-loop/zipball/bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354",
+ "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
+ },
+ "suggest": {
+ "ext-pcntl": "For signal handling support when using the StreamSelectLoop"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\EventLoop\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.",
+ "keywords": [
+ "asynchronous",
+ "event-loop"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/event-loop/issues",
+ "source": "https://github.com/reactphp/event-loop/tree/v1.5.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2023-11-13T13:48:05+00:00"
+ },
+ {
+ "name": "react/promise",
+ "version": "v3.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/promise.git",
+ "reference": "e563d55d1641de1dea9f5e84f3cccc66d2bfe02c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/promise/zipball/e563d55d1641de1dea9f5e84f3cccc66d2bfe02c",
+ "reference": "e563d55d1641de1dea9f5e84f3cccc66d2bfe02c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1.0"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "1.10.39 || 1.4.10",
+ "phpunit/phpunit": "^9.6 || ^7.5"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/functions_include.php"
+ ],
+ "psr-4": {
+ "React\\Promise\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "A lightweight implementation of CommonJS Promises/A for PHP",
+ "keywords": [
+ "promise",
+ "promises"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/promise/issues",
+ "source": "https://github.com/reactphp/promise/tree/v3.1.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2023-11-16T16:21:57+00:00"
+ },
+ {
+ "name": "react/promise-timer",
+ "version": "v1.10.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/promise-timer.git",
+ "reference": "4cb85c1c2125390748e3908120bb82feb99fe766"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/promise-timer/zipball/4cb85c1c2125390748e3908120bb82feb99fe766",
+ "reference": "4cb85c1c2125390748e3908120bb82feb99fe766",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/event-loop": "^1.2",
+ "react/promise": "^3.0 || ^2.7.0 || ^1.2.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/functions_include.php"
+ ],
+ "psr-4": {
+ "React\\Promise\\Timer\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "A trivial implementation of timeouts for Promises, built on top of ReactPHP.",
+ "homepage": "https://github.com/reactphp/promise-timer",
+ "keywords": [
+ "async",
+ "event-loop",
+ "promise",
+ "reactphp",
+ "timeout",
+ "timer"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/promise-timer/issues",
+ "source": "https://github.com/reactphp/promise-timer/tree/v1.10.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2023-07-20T15:40:28+00:00"
+ },
+ {
+ "name": "react/socket",
+ "version": "v1.15.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/socket.git",
+ "reference": "216d3aec0b87f04a40ca04f481e6af01bdd1d038"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/socket/zipball/216d3aec0b87f04a40ca04f481e6af01bdd1d038",
+ "reference": "216d3aec0b87f04a40ca04f481e6af01bdd1d038",
+ "shasum": ""
+ },
+ "require": {
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3.0",
+ "react/dns": "^1.11",
+ "react/event-loop": "^1.2",
+ "react/promise": "^3 || ^2.6 || ^1.2.1",
+ "react/stream": "^1.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
+ "react/async": "^4 || ^3 || ^2",
+ "react/promise-stream": "^1.4",
+ "react/promise-timer": "^1.10"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\Socket\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP",
+ "keywords": [
+ "Connection",
+ "Socket",
+ "async",
+ "reactphp",
+ "stream"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/socket/issues",
+ "source": "https://github.com/reactphp/socket/tree/v1.15.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2023-12-15T11:02:10+00:00"
+ },
+ {
+ "name": "react/stream",
+ "version": "v1.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/reactphp/stream.git",
+ "reference": "6fbc9672905c7d5a885f2da2fc696f65840f4a66"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/reactphp/stream/zipball/6fbc9672905c7d5a885f2da2fc696f65840f4a66",
+ "reference": "6fbc9672905c7d5a885f2da2fc696f65840f4a66",
+ "shasum": ""
+ },
+ "require": {
+ "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+ "php": ">=5.3.8",
+ "react/event-loop": "^1.2"
+ },
+ "require-dev": {
+ "clue/stream-filter": "~1.2",
+ "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "React\\Stream\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering",
+ "homepage": "https://clue.engineering/"
+ },
+ {
+ "name": "Cees-Jan Kiewiet",
+ "email": "reactphp@ceesjankiewiet.nl",
+ "homepage": "https://wyrihaximus.net/"
+ },
+ {
+ "name": "Jan Sorgalla",
+ "email": "jsorgalla@gmail.com",
+ "homepage": "https://sorgalla.com/"
+ },
+ {
+ "name": "Chris Boden",
+ "email": "cboden@gmail.com",
+ "homepage": "https://cboden.dev/"
+ }
+ ],
+ "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP",
+ "keywords": [
+ "event-driven",
+ "io",
+ "non-blocking",
+ "pipe",
+ "reactphp",
+ "readable",
+ "stream",
+ "writable"
+ ],
+ "support": {
+ "issues": "https://github.com/reactphp/stream/issues",
+ "source": "https://github.com/reactphp/stream/tree/v1.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://opencollective.com/reactphp",
+ "type": "open_collective"
+ }
+ ],
+ "time": "2023-06-16T10:52:11+00:00"
+ },
{
"name": "symfony/clock",
"version": "v7.0.5",
@@ -9069,7 +10098,9 @@
],
"aliases": [],
"minimum-stability": "stable",
- "stability-flags": [],
+ "stability-flags": {
+ "laravel/reverb": 10
+ },
"prefer-stable": true,
"prefer-lowest": false,
"platform": {
diff --git a/app/application/config/app.php b/app/application/config/app.php
index c9dcca0..4d51dad 100644
--- a/app/application/config/app.php
+++ b/app/application/config/app.php
@@ -215,7 +215,7 @@
*/
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
- // App\Providers\BroadcastServiceProvider::class,
+ App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
diff --git a/app/application/config/reverb.php b/app/application/config/reverb.php
new file mode 100644
index 0000000..bb00f80
--- /dev/null
+++ b/app/application/config/reverb.php
@@ -0,0 +1,97 @@
+ env('REVERB_SERVER', 'reverb'),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Reverb Servers
+ |--------------------------------------------------------------------------
+ |
+ | Here you may define details for each of the supported Reverb servers.
+ | Each server has its own configuration options that are defined in
+ | the array below. You should ensure all the options are present.
+ |
+ */
+
+ 'servers' => [
+
+ 'reverb' => [
+ 'host' => env('REVERB_SERVER_HOST', '0.0.0.0'),
+ 'port' => env('REVERB_SERVER_PORT', 8080),
+ 'hostname' => env('REVERB_HOST'),
+ 'options' => [
+ 'tls' => [],
+ ],
+ 'max_request_size' => env('REVERB_MAX_REQUEST_SIZE', 10_000),
+ 'scaling' => [
+ 'enabled' => env('REVERB_SCALING_ENABLED', false),
+ 'channel' => env('REVERB_SCALING_CHANNEL', 'reverb'),
+ 'server' => [
+ 'url' => env('REDIS_URL'),
+ 'host' => env('REDIS_HOST', '127.0.0.1'),
+ 'port' => env('REDIS_PORT', '6379'),
+ 'username' => env('REDIS_USERNAME'),
+ 'password' => env('REDIS_PASSWORD'),
+ 'database' => env('REDIS_DB', '0'),
+ ],
+ ],
+ 'pulse_ingest_interval' => env('REVERB_PULSE_INGEST_INTERVAL', 15),
+ 'telescope_ingest_interval' => env('REVERB_TELESCOPE_INGEST_INTERVAL', 15),
+ ],
+
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Reverb Applications
+ |--------------------------------------------------------------------------
+ |
+ | Here you may define how Reverb applications are managed. If you choose
+ | to use the "config" provider, you may define an array of apps which
+ | your server will support, including their connection credentials.
+ |
+ */
+
+ 'apps' => [
+
+ 'provider' => 'config',
+
+ 'apps' => [
+ [
+ 'key' => env('REVERB_APP_KEY'),
+ 'secret' => env('REVERB_APP_SECRET'),
+ 'app_id' => env('REVERB_APP_ID'),
+ 'options' => [
+ 'host' => env('REVERB_HOST'),
+ 'port' => env('REVERB_PORT', 443),
+ 'scheme' => env('REVERB_SCHEME', 'https'),
+ 'useTLS' => env('REVERB_SCHEME', 'https') === 'https',
+ ],
+ 'allowed_origins' => explode(',', env('REVERB_ALLOWED_ORIGINS', '*')),
+ 'ping_interval' => env('REVERB_APP_PING_INTERVAL', 60),
+ 'max_message_size' => env('REVERB_APP_MAX_MESSAGE_SIZE', 10_000),
+ 'options_for_client' => [
+ 'host' => env('REVERB_HOST_CLIENT'),
+ 'port' => env('REVERB_PORT_CLIENT', 443),
+ 'scheme' => env('REVERB_SCHEME_CLIENT', 'https'),
+ 'useTLS' => env('REVERB_SCHEME_CLIENT', 'https') === 'https',
+ ],
+ ],
+ ],
+
+ ],
+
+];
diff --git a/app/application/lang/en.json b/app/application/lang/en.json
index b1013aa..f90d423 100644
--- a/app/application/lang/en.json
+++ b/app/application/lang/en.json
@@ -73,5 +73,6 @@
"The time for captcha verification has passed": "The time for captcha verification has passed.",
"Captcha does not pass verification": "Captcha does not pass verification.",
"Add code to the site": "Add code to the site",
- "Demo Mode": "!!! Demo Mode !!!"
+ "Demo Mode": "!!! Demo Mode !!!",
+ "From cannot be greater than To": "From cannot be greater than To."
}
diff --git a/app/application/lang/en/captcha_log_type.php b/app/application/lang/en/captcha_log_type.php
new file mode 100644
index 0000000..81d7e20
--- /dev/null
+++ b/app/application/lang/en/captcha_log_type.php
@@ -0,0 +1,7 @@
+ 'Creating a captcha',
+ 'Error' => 'Error in captcha validation',
+ 'Verified' => 'Successfully verified',
+ 'ReadVerified' => 'Completed captcha verification',
+];
diff --git a/app/application/lang/ru.json b/app/application/lang/ru.json
index 04d4e89..b4be525 100644
--- a/app/application/lang/ru.json
+++ b/app/application/lang/ru.json
@@ -73,5 +73,6 @@
"The time for captcha verification has passed": "Время верификации капчи прошло.",
"Captcha does not pass verification": "Капча не проходит проверку.",
"Add code to the site": "Добавьте код на сайт",
- "Demo Mode": "!!! Включён демо режим !!!"
+ "Demo Mode": "!!! Включён демо режим !!!",
+ "From cannot be greater than To": "From не может быть больше To."
}
diff --git a/app/application/lang/ru/captcha_log_type.php b/app/application/lang/ru/captcha_log_type.php
new file mode 100644
index 0000000..c8718ae
--- /dev/null
+++ b/app/application/lang/ru/captcha_log_type.php
@@ -0,0 +1,7 @@
+ 'Создание капчи',
+ 'Error' => 'Ошибка в валидации капчи',
+ 'Verified' => 'Успешно проверено',
+ 'ReadVerified' => 'Завершена проверка капчи',
+];
diff --git a/app/application/package-lock.json b/app/application/package-lock.json
index 02fc257..7ebded0 100644
--- a/app/application/package-lock.json
+++ b/app/application/package-lock.json
@@ -21,7 +21,9 @@
},
"devDependencies": {
"axios": "^1.1.2",
+ "laravel-echo": "^1.16.1",
"laravel-vite-plugin": "^0.7.2",
+ "pusher-js": "^8.4.0-rc2",
"sass-loader": "^13.3.2",
"vite": "^4.0.0"
}
@@ -1251,6 +1253,15 @@
"dev": true,
"peer": true
},
+ "node_modules/laravel-echo": {
+ "version": "1.16.1",
+ "resolved": "https://registry.npmjs.org/laravel-echo/-/laravel-echo-1.16.1.tgz",
+ "integrity": "sha512-++Ylb6M3ariC9Rk5WE5gZjj6wcEV5kvLF8b+geJ5/rRIfdoOA+eG6b9qJPrarMD9rY28Apx+l3eelIrCc2skVg==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/laravel-vite-plugin": {
"version": "0.7.8",
"resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-0.7.8.tgz",
@@ -1436,6 +1447,15 @@
"node": ">=6"
}
},
+ "node_modules/pusher-js": {
+ "version": "8.4.0-rc2",
+ "resolved": "https://registry.npmjs.org/pusher-js/-/pusher-js-8.4.0-rc2.tgz",
+ "integrity": "sha512-d87GjOEEl9QgO5BWmViSqW0LOzPvybvX6WA9zLUstNdB57jVJuR27zHkRnrav2a3+zAMlHbP2Og8wug+rG8T+g==",
+ "dev": true,
+ "dependencies": {
+ "tweetnacl": "^1.0.3"
+ }
+ },
"node_modules/randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -1723,6 +1743,12 @@
"node": ">=8.0"
}
},
+ "node_modules/tweetnacl": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
+ "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==",
+ "dev": true
+ },
"node_modules/update-browserslist-db": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz",
@@ -2755,6 +2781,12 @@
"dev": true,
"peer": true
},
+ "laravel-echo": {
+ "version": "1.16.1",
+ "resolved": "https://registry.npmjs.org/laravel-echo/-/laravel-echo-1.16.1.tgz",
+ "integrity": "sha512-++Ylb6M3ariC9Rk5WE5gZjj6wcEV5kvLF8b+geJ5/rRIfdoOA+eG6b9qJPrarMD9rY28Apx+l3eelIrCc2skVg==",
+ "dev": true
+ },
"laravel-vite-plugin": {
"version": "0.7.8",
"resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-0.7.8.tgz",
@@ -2883,6 +2915,15 @@
"dev": true,
"peer": true
},
+ "pusher-js": {
+ "version": "8.4.0-rc2",
+ "resolved": "https://registry.npmjs.org/pusher-js/-/pusher-js-8.4.0-rc2.tgz",
+ "integrity": "sha512-d87GjOEEl9QgO5BWmViSqW0LOzPvybvX6WA9zLUstNdB57jVJuR27zHkRnrav2a3+zAMlHbP2Og8wug+rG8T+g==",
+ "dev": true,
+ "requires": {
+ "tweetnacl": "^1.0.3"
+ }
+ },
"randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -3056,6 +3097,12 @@
"is-number": "^7.0.0"
}
},
+ "tweetnacl": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
+ "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==",
+ "dev": true
+ },
"update-browserslist-db": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz",
diff --git a/app/application/package.json b/app/application/package.json
index 612ecc5..c446ebb 100644
--- a/app/application/package.json
+++ b/app/application/package.json
@@ -21,7 +21,9 @@
},
"devDependencies": {
"axios": "^1.1.2",
+ "laravel-echo": "^1.16.1",
"laravel-vite-plugin": "^0.7.2",
+ "pusher-js": "^8.4.0-rc2",
"sass-loader": "^13.3.2",
"vite": "^4.0.0"
}
diff --git a/app/application/resources/views/private/dashboard/index.blade.php b/app/application/resources/views/private/dashboard/index.blade.php
index 057ac8b..7624168 100644
--- a/app/application/resources/views/private/dashboard/index.blade.php
+++ b/app/application/resources/views/private/dashboard/index.blade.php
@@ -1,5 +1,40 @@
@section('meta_title', __('sections.Dashboard'))
@section('h1', __('sections.Dashboard'))
{{ $item->type->getTitle() }} IP: {{ $item->ip }} User Agent: {{ $item->user_agent }} referer: {{ $item->referer }}
+
+
+
+
+
+
+ @foreach($items as $item)
+ {{ __('validation.attributes.date') }}
+ Capctha
+
+
+
+ @endforeach
+
+ {{ $item->created_at->timezone(\App\Helpers\Helpers::getUserTimeZone())->format("d.m.Y H:i:s") }}
+
+ @if($item->captcha && $item->captcha->captchaToken)
+ {{ $item->captcha->captchaToken->title }}
+ @endif
+
+
+
+
${e.captchaLog.type}
+IP: ${e.captchaLog.ip}
+User Agent: ${e.captchaLog.user_agent}
+referer: ${e.captchaLog.referer}
+