44 Commits
Author SHA1 Message Date
kor-elf 3c04377604 Merge pull request 'Версия 0.9.0' (#7) from develop into main
Reviewed-on: #7
2026-10-23 23:59:08 +05:00
kor-elf ab2c173ceb Updated docker-compose-prod_docker-hub.yml to switch image sources from Docker Hub to MDHub and added environment variables, volumes, and services for better configuration and scalability. 2026-10-23 23:53:06 +05:00
kor-elf 76262c8190 Removed unused third-party SCSS imports from app.scss. 2026-10-23 22:41:55 +05:00
kor-elf 0f9dda9bdb Removed unused JS imports from app.js. 2026-10-23 22:41:48 +05:00
kor-elf d99b5dbf74 Added SCSS base structure for Volt Admin, including components, mixins, functions, and layout styling. 2026-10-23 22:41:17 +05:00
kor-elf 0279807def Removed unused $info variable in CaptchaVerificationInformation.php. 2026-10-23 20:48:06 +05:00
kor-elf 0cc1901720 Removed __destruct method from Image contract. 2026-10-23 20:43:22 +05:00
kor-elf f7810819e6 Removed redundant imagedestroy calls in Image.php. 2026-10-23 20:41:38 +05:00
kor-elf e1fe94f920 Added @throws CaptchaException annotation to createImageFromPathToFile method in Image.php. 2026-10-23 20:35:47 +05:00
kor-elf 62dcd6c0b9 Added @throws CaptchaException annotation to insertBackground method in Image.php. 2026-10-23 20:34:58 +05:00
kor-elf 643776336e Added ext-fileinfo to Composer dependencies. 2026-10-23 20:34:49 +05:00
kor-elf 4b21b75ded Added ext-gd to Composer dependencies. 2026-10-23 20:34:05 +05:00
kor-elf a2b37d99c4 Refactored Docker Compose: updated service names, adjusted build contexts and targets, added missing environment variables, and updated volumes for consistency across development and production. 2026-10-23 20:32:18 +05:00
kor-elf cf55fa3ac9 Refactored index.php: simplified bootstrapping, replaced kernel handling with handleRequest, and removed redundant comments. 2026-10-23 20:32:05 +05:00
kor-elf 6234b9b5fc Refactored artisan script: simplified bootstrapping, replaced kernel handling with handleCommand, and removed redundant comments. 2026-10-23 20:31:58 +05:00
kor-elf 253cfebbef Updated Vite configuration: defined globalThis, adjusted optimizeDeps, and enabled eager loading with query params for import.meta.glob. 2026-10-23 20:31:51 +05:00
kor-elf 646f3ee21a Updated npm dependencies and scripts: bumped package versions, added new optional dependencies, adjusted configuration, and set schema and module type in package.json. 2026-10-23 20:31:42 +05:00
kor-elf 5b66e715ab Updated Composer dependencies and scripts: bumped package versions, added new Composer scripts, and adjusted configuration settings. 2026-10-23 20:31:26 +05:00
kor-elf f300a566f0 Refactored Docker setup: replaced NGINX Unit with PHP-FPM and NGINX, simplified configurations, and removed redundant files. 2026-10-22 21:40:22 +05:00
kor-elf 995b34ead5 Fixed UNIT_SOURCE. 2024-06-12 00:44:14 +05:00
kor-elf d55c24cfe0 Merge pull request 'Версия 0.8.2' (#6) from develop into main
Reviewed-on: #6
2024-06-11 23:34:32 +05:00
kor-elf e2b9e60b36 Updated to korelf/service-captcha:0.8.2. 2024-06-11 23:19:32 +05:00
kor-elf 47ef821c0f Added environment UNIT_SOURCE as an example. 2024-06-11 23:02:48 +05:00
kor-elf 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
kor-elf af053b4d53 Добавил к Redis Volumes. 2024-06-11 22:42:58 +05:00
kor-elf de69776bc8 Added php artisan storage:link. 2024-06-11 22:42:10 +05:00
kor-elf cce94cd210 Added autocomplete="off" attribute to input password. 2024-06-11 22:39:15 +05:00
kor-elf ed6a036d8d Deleted sweetalert2. 2024-06-11 22:34:55 +05:00
kor-elf 3871670c91 Removed extra code. 2024-06-11 22:30:56 +05:00
kor-elf 0e93b2e780 Fixed .dockerignore. 2024-05-19 21:01:26 +05:00
kor-elf 1b5f805195 Captcha update to 0.8.1. 2024-04-28 20:00:01 +05:00
kor-elf 748d05f8fc Merge pull request 'Версия 0.8.1' (#5) from develop into main
Reviewed-on: #5
2024-04-28 19:54:56 +05:00
kor-elf b662a85572 Fixed the use of the UNIT_SOURCE parameter for Nginx Unit. 2024-04-28 19:48:20 +05:00
kor-elf 4368aec1b1 Merge pull request 'Версия 0.8.0' (#4) from develop into main
Reviewed-on: #4
2024-04-28 14:26:46 +05:00
kor-elf bd91cdef0c BROADCAST_DRIVER changed to reverb. 2024-04-28 13:13:27 +05:00
kor-elf 1532cecedc For demo mode, I hid the display of IP and UserAgent. 2024-04-28 02:12:09 +05:00
kor-elf 5703015874 Revived the dashboard. 2024-04-28 01:26:30 +05:00
kor-elf 4bc170ed00 Added final to UsersController. 2024-04-26 20:36:32 +05:00
kor-elf 20ed4860da Added the ability to enable captcha when logging in. 2024-04-25 23:45:07 +05:00
kor-elf e059f09e2f Updated Laravel to 11. 2024-04-25 20:58:52 +05:00
kor-elf 8794b8af4e I returned the LICENSE.md file back. 2024-04-25 20:07:13 +05:00
kor-elf 85e181e51c Changed the project structure. 2024-04-25 19:56:34 +05:00
kor-elf 3f21276ec5 Merge pull request 'Update README.md.' (#3) from develop into main
Reviewed-on: #3
2023-12-13 23:28:38 +06:00
kor-elf 01153867b3 Update README.md.
Fixed link to JavaScript GUI repository.
2023-12-13 23:27:45 +06:00
484 changed files with 16057 additions and 7201 deletions

No files matched your search

+9 -68
View File
@@ -1,68 +1,9 @@
APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost
APP_FORCE_HTTPS=false
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=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}"
DOCKER_WEB_PORT=8080
DOCKER_WEBSOCKET_PORT=8081
DOCKER_DB_PORT=3306
MYSQL_ROOT_PASSWORD=root_pass
DB_DATABASE=captcha
DB_USERNAME=captcha
DB_PASSWORD=captcha_pass
UID=1000
GID=1000
+4 -17
View File
@@ -1,19 +1,6 @@
/.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
Homestead.json
/.vagrant
.phpunit.result.cache
+1 -1
View File
@@ -1,6 +1,6 @@
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:
+5 -3
View File
@@ -2,9 +2,11 @@
Захотелось написать свой независимый сервис защиты от роботов. Сервис каптча написан на фреймворке 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
@@ -23,10 +25,10 @@ Email: demo@tut-site.net
https://captcha-admin-demo.tut-site.net/api-docs/
## 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
+15
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
@@ -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');
}
}
-35
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();
}
}
File renamed without changes.
+92
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}"
File renamed without changes.
+19
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
@@ -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);
}
}
@@ -13,5 +13,4 @@ interface Image
public function addText(string $text, int $x, int $y, float $size, float $angle, string $hexColor, string $fontName): Coordinators;
public function addLine(int $x1, int $y1, int $x2, int $y2, string $hexColor): self;
public function encode(): string;
public function __destruct();
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -24,6 +24,9 @@ final class Image implements ImageContract
return imagesy($this->image);
}
/**
* @throws CaptchaException
*/
public function insertBackground(string $pathToFile): ImageContract
{
list($backgroundWidth, $backgroundHeight) = getimagesize($pathToFile);
@@ -40,7 +43,6 @@ final class Image implements ImageContract
src_width: $backgroundWidth,
src_height: $backgroundHeight
);
imagedestroy($background);
return $this;
}
@@ -101,10 +103,9 @@ final class Image implements ImageContract
);
}
public function __destruct() {
imagedestroy($this->image);
}
/**
* @throws CaptchaException
*/
private function createImageFromPathToFile(string $pathToFile): \GdImage
{
return match (mime_content_type($pathToFile)) {
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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;
}
}
File renamed without changes.
File renamed without changes.
@@ -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);
}
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -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');
}
}
File renamed without changes.
File renamed without changes.
@@ -19,7 +19,9 @@ final class AuthController extends Controller
public function login(): View
{
return view('public/login');
return view('public/login', [
'captcha' => config('app.captcha', false)
]);
}
public function authorization(AuthorizationRequest $request): RedirectResponse
@@ -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));
}
}
@@ -11,7 +11,7 @@ use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
class UsersController extends Controller
final class UsersController extends Controller
{
public function __construct(
private readonly UserService $userService
@@ -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));
}
}
File renamed without changes.
Loaded 100 of 484 files, more files were not shown because too many files have changed in this diff. Show more