Compare commits

..

24 Commits
0.7.1 ... main

Author SHA1 Message Date
d55c24cfe0 Merge pull request 'Версия 0.8.2' (#6) from develop into main
Reviewed-on: #6
2024-06-11 23:34:32 +05:00
e2b9e60b36
Updated to korelf/service-captcha:0.8.2. 2024-06-11 23:19:32 +05:00
47ef821c0f
Added environment UNIT_SOURCE as an example. 2024-06-11 23:02:48 +05:00
0f07c8c6ab
Improved queue launch in Docker.
Now it does not die, but in a loop inside it restarts php /var/www/html/artisan queue:work --verbose --sleep=5 --tries=10 --max-time=3600.
2024-06-11 22:44:48 +05:00
af053b4d53
Добавил к Redis Volumes. 2024-06-11 22:42:58 +05:00
de69776bc8
Added php artisan storage:link. 2024-06-11 22:42:10 +05:00
cce94cd210
Added autocomplete="off" attribute to input password. 2024-06-11 22:39:15 +05:00
ed6a036d8d
Deleted sweetalert2. 2024-06-11 22:34:55 +05:00
3871670c91
Removed extra code. 2024-06-11 22:30:56 +05:00
0e93b2e780
Fixed .dockerignore. 2024-05-19 21:01:26 +05:00
1b5f805195
Captcha update to 0.8.1. 2024-04-28 20:00:01 +05:00
748d05f8fc Merge pull request 'Версия 0.8.1' (#5) from develop into main
Reviewed-on: #5
2024-04-28 19:54:56 +05:00
b662a85572
Fixed the use of the UNIT_SOURCE parameter for Nginx Unit. 2024-04-28 19:48:20 +05:00
4368aec1b1 Merge pull request 'Версия 0.8.0' (#4) from develop into main
Reviewed-on: #4
2024-04-28 14:26:46 +05:00
bd91cdef0c
BROADCAST_DRIVER changed to reverb. 2024-04-28 13:13:27 +05:00
1532cecedc
For demo mode, I hid the display of IP and UserAgent. 2024-04-28 02:12:09 +05:00
5703015874
Revived the dashboard. 2024-04-28 01:26:30 +05:00
4bc170ed00
Added final to UsersController. 2024-04-26 20:36:32 +05:00
20ed4860da
Added the ability to enable captcha when logging in. 2024-04-25 23:45:07 +05:00
e059f09e2f
Updated Laravel to 11. 2024-04-25 20:58:52 +05:00
8794b8af4e
I returned the LICENSE.md file back. 2024-04-25 20:07:13 +05:00
85e181e51c
Changed the project structure. 2024-04-25 19:56:34 +05:00
3f21276ec5 Merge pull request 'Update README.md.' (#3) from develop into main
Reviewed-on: #3
2023-12-13 23:28:38 +06:00
01153867b3
Update README.md.
Fixed link to JavaScript GUI repository.
2023-12-13 23:27:45 +06:00
414 changed files with 4128 additions and 1888 deletions

View File

@ -1,68 +1,9 @@
APP_NAME=Laravel DOCKER_NGINX_PORT=8080
APP_ENV=local DOCKER_WEBSOCKET_PORT=8081
APP_KEY= DOCKER_DB_PORT=3306
APP_DEBUG=true MYSQL_ROOT_PASSWORD=root_pass
APP_URL=http://localhost DB_DATABASE=captcha
DB_USERNAME=captcha
APP_FORCE_HTTPS=false DB_PASSWORD=captcha_pass
UID=1000
APP_DEMO_MODE=false GID=1000
APP_DEMO_EMAIL=
APP_DEMO_PASSWORD=
APP_DEFAULT_USER_TIMEZONE=UTC
# Valid languages: ru | en
APP_DEFAULT_LOCALE=ru
LOG_CHANNEL=daily
LOG_DEPRECATIONS_CHANNEL=deprecations
LOG_LEVEL=debug
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=
BROADCAST_DRIVER=log
CACHE_DRIVER=file
FILESYSTEM_DISK=local
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
MEMCACHED_HOST=127.0.0.1
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=smtp
MAIL_HOST=mailpit
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_HOST=
PUSHER_PORT=443
PUSHER_SCHEME=https
PUSHER_APP_CLUSTER=mt1
VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
VITE_PUSHER_HOST="${PUSHER_HOST}"
VITE_PUSHER_PORT="${PUSHER_PORT}"
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

21
.gitignore vendored
View File

@ -1,19 +1,6 @@
/.phpunit.cache
/node_modules
/public/build
/public/hot
/public/storage
/storage/*.key
/vendor
.env .env
.env.backup
.env.production
.phpunit.result.cache
Homestead.json
Homestead.yaml Homestead.yaml
auth.json Homestead.json
npm-debug.log /.vagrant
yarn-error.log .phpunit.result.cache
/.fleet
/.idea
/.vscode

View File

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2023 Leonid Nikitin (kor-elf) Copyright (c) 2023 - 2024 Leonid Nikitin (kor-elf)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

View File

@ -2,9 +2,11 @@
Захотелось написать свой независимый сервис защиты от роботов. Сервис каптча написан на фреймворке Laravel. Вдохновлялся, а так же брал картинки с проекта <a href="https://github.com/wenlng/go-captcha" target="_blank">Go Captcha</a>. Захотелось написать свой независимый сервис защиты от роботов. Сервис каптча написан на фреймворке Laravel. Вдохновлялся, а так же брал картинки с проекта <a href="https://github.com/wenlng/go-captcha" target="_blank">Go Captcha</a>.
[Сайт проекта](https://service-captcha.projects.kor-elf.net/)
## Зависимости ## Зависимости
php 8.2 (модули: redis, gd) php 8.3 (модули: redis, gd)
redis redis
@ -23,10 +25,10 @@ Email: demo@tut-site.net
https://captcha-admin-demo.tut-site.net/api-docs/ https://captcha-admin-demo.tut-site.net/api-docs/
## Javascript клиент для сайта ## Javascript клиент для сайта
https://git.kor-elf.net/kor-elf/captcha-rule-for-laravel https://git.kor-elf.net/kor-elf/service-captcha-gui
## Как проверять со стороны бэкенда ## Как проверять со стороны бэкенда
Для Laravel 10 есть готовый пакет: https://git.kor-elf.net/kor-elf/captcha-rule-for-laravel Для Laravel 10, 11 есть готовый пакет: https://git.kor-elf.net/kor-elf/captcha-rule-for-laravel
Можно установить этот пакет так: composer require kor-elf/captcha-rule-for-laravel Можно установить этот пакет так: composer require kor-elf/captcha-rule-for-laravel

15
app/.dockerignore Normal file
View File

@ -0,0 +1,15 @@
**/.env
**/*.env
**/.env.example
**/storage/app/*
**/storage/debugbar
**/storage/framework/cache/*
**/storage/framework/sessions/*
**/storage/framework/views/*
**/storage/framework/testing/*
**/storage/logs/*
**/vendor/
**/node_modules/
**/public/build/
**/public/storage

View File

@ -1,13 +0,0 @@
<?php declare(strict_types=1);
namespace App\Http\Controllers\Private;
use Illuminate\View\View;
final class DashboardController extends Controller
{
public function index(): View
{
return view('private/dashboard/index');
}
}

View File

@ -1,35 +0,0 @@
<?php declare(strict_types=1);
namespace App\Repositories;
use App\Enums\CaptchaLogType;
use App\Models\CaptchaLog;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
final class CaptchaLogRepository
{
public function countByType(CaptchaLogType $type, ?int $captchaId = null): int
{
return CaptchaLog::query()
->when($captchaId, function (Builder $query, int $captchaId) {
$query->where('captcha_id', $captchaId);
})
->where('type', '=', $type)
->count();
}
public function getCaptchaLogsByTypes(array $types, ?int $captchaId = null, ?int $limit = null): Collection
{
return CaptchaLog::query()
->when($captchaId, function (Builder $query, int $captchaId) {
$query->where('captcha_id', $captchaId);
})
->when($limit, function (Builder $query, int $limit) {
$query->limit($limit);
})
->whereIn('type', $types)
->latest()
->get();
}
}

View File

@ -0,0 +1,92 @@
APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost
APP_FORCE_HTTPS=false
APP_CAPTCHA=false
CAPTCHA_API_DOMAIN=http://your-domain-captcha-or-IP:8081
CAPTCHA_PRIVATE_TOKEN=
CAPTCHA_STATIC_PATH=http://your-domain-captcha-or-IP:8081/captcha
CAPTCHA_PUBLIC_TOKEN=
APP_DEMO_MODE=false
APP_DEMO_EMAIL=
APP_DEMO_PASSWORD=
APP_DEFAULT_USER_TIMEZONE=UTC
# Valid languages: ru | en
APP_DEFAULT_LOCALE=ru
LOG_CHANNEL=daily
LOG_DEPRECATIONS_CHANNEL=deprecations
LOG_LEVEL=debug
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=captcha
DB_USERNAME=captcha
DB_PASSWORD=captcha_pass
BROADCAST_DRIVER=reverb
CACHE_DRIVER=redis
FILESYSTEM_DISK=local
QUEUE_CONNECTION=redis
SESSION_DRIVER=redis
SESSION_LIFETIME=120
MEMCACHED_HOST=127.0.0.1
REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=smtp
MAIL_HOST=mailpit
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_HOST=
PUSHER_PORT=443
PUSHER_SCHEME=https
PUSHER_APP_CLUSTER=mt1
VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
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}"

19
app/application/.gitignore vendored Normal file
View File

@ -0,0 +1,19 @@
/.phpunit.cache
/node_modules
/public/build
/public/hot
/public/storage
/storage/*.key
/vendor
.env
.env.backup
.env.production
.phpunit.result.cache
Homestead.json
Homestead.yaml
auth.json
npm-debug.log
yarn-error.log
/.fleet
/.idea
/.vscode

View File

@ -0,0 +1,17 @@
<?php declare(strict_types=1);
namespace App\Broadcasting;
use App\Models\CaptchaToken;
use App\Models\User;
final readonly class CreatedCaptchaLog
{
/**
* Authenticate the user's access to the channel.
*/
public function join(User $user): bool
{
return $user->can('viewAny', CaptchaToken::class);
}
}

View File

@ -0,0 +1,38 @@
<?php declare(strict_types=1);
namespace App\Dto\Repository\CaptchaLogRepository;
use App\Enums\CaptchaLogType;
final class QuantityByDays
{
private array $days = [];
/**
* @param string $day ("Y-m-d")
* @param CaptchaLogType $type
* @param int $count
* @return void
*/
public function add(string $day, CaptchaLogType $type, int $count): void
{
if (!isset($this->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;
}
}

View File

@ -8,4 +8,9 @@ enum CaptchaLogType: int
case Error = 2; case Error = 2;
case Verified = 3; case Verified = 3;
case ReadVerified = 4; case ReadVerified = 4;
public function getTitle(): string
{
return __('captcha_log_type.' . $this->name);
}
} }

View File

@ -0,0 +1,55 @@
<?php declare(strict_types=1);
namespace App\Events;
use App\Helpers\Helpers;
use App\Models\CaptchaLog;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
final class CreatedCaptchaLog implements ShouldBroadcast
{
use SerializesModels, Dispatchable;
public array $chartCaptchaActivity = [];
public array $captchaLog = [];
public function __construct(CaptchaLog $captchaLog) {
$this->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;
}
$ip = $captchaLog->ip;
$userAgent = $captchaLog->user_agent;
if (Helpers::isDemoMode()) {
$ip = __('Demo Mode');
$userAgent = __('Demo Mode');
}
$this->captchaLog = [
'created_at' => $captchaLog->created_at->format("d.m.Y H:i:s"),
'link' => $link,
'title' => $title,
'type' => $captchaLog->type->getTitle(),
'ip' => $ip,
'user_agent' => $userAgent,
'referer' => $captchaLog->referer,
];
}
public function broadcastOn(): Channel
{
return new PrivateChannel('chart-captcha-activity');
}
}

View File

@ -19,7 +19,9 @@ public function __construct(
public function login(): View public function login(): View
{ {
return view('public/login'); return view('public/login', [
'captcha' => config('app.captcha', false)
]);
} }
public function authorization(AuthorizationRequest $request): RedirectResponse public function authorization(AuthorizationRequest $request): RedirectResponse

View File

@ -0,0 +1,43 @@
<?php declare(strict_types=1);
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 __construct(
private readonly DashboardService $dashboardService,
) { }
public function index(Request $request): View
{
$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));
}
}

View File

@ -11,7 +11,7 @@
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\View\View; use Illuminate\View\View;
class UsersController extends Controller final class UsersController extends Controller
{ {
public function __construct( public function __construct(
private readonly UserService $userService private readonly UserService $userService

View File

@ -0,0 +1,24 @@
<?php declare(strict_types=1);
namespace App\Http\Controllers\Private;
use App\Http\Resources\Private\Websockets\Setting;
use App\Services\Private\WebsocketService;
use Illuminate\Http\JsonResponse;
final class WebsocketsController extends Controller
{
public function __construct(
private readonly WebsocketService $websocketService,
) { }
public function settings(): JsonResponse
{
$result = $this->websocketService->settings();
if (!$result->isSuccess()) {
return response()->json($result->getData())->setStatusCode($result->getCode());
}
return response()->json(new Setting($result));
}
}

Some files were not shown because too many files have changed in this diff Show More