Changed the project structure.

This commit is contained in:
2024-04-25 19:56:34 +05:00
parent 01153867b3
commit 85e181e51c
392 changed files with 362 additions and 316 deletions

View File

@@ -0,0 +1,21 @@
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews -Indexes
</IfModule>
RewriteEngine On
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
# Send Requests To Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

View File

@@ -0,0 +1,5 @@
/*
* Copyright (C) 2023 Leonid Nikitin (kor-elf)
* https://git.kor-elf.net/kor-elf/service-captcha-gui/src/branch/main/LICENSE.md
*/
!function(e){let t=e.querySelectorAll("div.captcha-service-kor-elf");function n(e){e.style.display="none"}function c(t,n,c,o,i){let r=t.querySelector("div.window-captcha__content__body");if(r.querySelectorAll(".loading").length>0)return null;r.innerHTML='<div class="loading"></div>',fetch(n+"/api/v1/captcha",{headers:{"Content-Type":"application/json",Accept:"application/json","public-token":c}}).then(e=>e.json()).then(function(t){let l=t.image_body.width,d=t.image_body.height;r.innerHTML=`<form method="post"><div class="window-captcha__content__body__head"><img src="${t.image_head.base64}" width="100%"></div><p>Выберите значение в том порядке, на котором на картинке выше:</p><div class="window-captcha__content__body__coordinator"><img src="${t.image_body.base64}" width="100%" /></div><input type="hidden" name="captcha_key" class="captcha_key" value="${t.captcha_key}" /><button type="button" class="window-captcha__content__body__button">Я не робот!</button></form>`;let s=r.querySelector("div.window-captcha__content__body__coordinator"),p=s.querySelector("img");p.addEventListener("click",function(t){let n=e.createElement("div");n.style.left=t.offsetX/p.width*100+"%",n.style.top=t.offsetY/p.height*100+"%",n.classList.add("pointer");let c=t.offsetX*(l/p.width),a=t.offsetY*(d/p.height),o=s.querySelectorAll(".pointer").length+1;n.innerHTML=`<span class="pounter__number">${o}</span><input type="hidden" class="x" name="pointer[][x]" value="${Math.round(c)}" /><input type="hidden" class="y" name="pointer[][y]" value="${Math.round(a)}" />`,n.addEventListener("click",function(){n.remove(),s.querySelectorAll(".pointer").forEach(function(e,t){e.querySelector("span.pounter__number").textContent=t+1})}),s.appendChild(n)}),r.querySelector(".window-captcha__content__body__button").addEventListener("click",function(){(function t(n,c,o,i,r){let l=n.querySelector("button.window-captcha__content__body__button");if(l.querySelectorAll(".loading").length>0)return null;let d=e.createElement("span");d.classList.add("loading"),l.appendChild(d);let s={captcha_key:n.querySelector(".captcha_key").value,verification:[]};n.querySelectorAll(".pointer").forEach(function(e){s.verification.push({x:e.querySelector(".x").value,y:e.querySelector(".y").value})}),fetch(c+"/api/v1/captcha",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json","public-token":o},body:JSON.stringify(s)}).then(e=>{if(429===e.status){a("Вы превысили количество попыток. Обновите каптчу.",l);return}return e.json()}).then(function(t){if(void 0!==t.errors){let n="";for(let c in t.errors)n+=t.errors[c]+"<br>";""===n&&(n=t.message),a(n,l);return}if(void 0===t.captcha_key){a("Произошла ошибка!",l);return}i.querySelector("button.button-open-window-captcha").remove();let o=e.createElement("div");o.innerHTML=`<span class="captcha-verified">Ура!!! Проверку прошли!</span>`,i.appendChild(o),i.querySelector(".window-captcha").remove();let d=e.createElement("input");d.name=r.getAttribute("data-captcha-verified-name"),d.value=t.captcha_key,d.type="hidden",r.appendChild(d)}).catch(e=>{a("Произошла ошибка!",l)}).finally(function(){d.remove()})})(r,n,c,o,i)})}).catch(e=>{r.innerHTML=`<div class="window-captcha__content__body__error">Произошла ошибка, сервис с каптчей не ответил. Попробуйте ещё раз!</div>`})}function a(t,n){let c=e.createElement("div");c.classList.add("error-message"),c.innerHTML=t,n.before(c),setTimeout(function(){c.remove()},3e3)}t.forEach(function(t){let a=t.attachShadow({mode:"closed"}),o=e.createElement("button"),i=e.createElement("link"),r=t.getAttribute("data-domain"),l=t.getAttribute("data-token"),d=t.getAttribute("data-static-path"),s=null;i.rel="stylesheet",i.type="text/css",i.href=d+"/style.css",a.appendChild(i),o.textContent="Я не робот!",o.type="button",o.classList.add("button-open-window-captcha"),a.appendChild(o),o.addEventListener("click",function(){null===s&&(s=function t(a,o,i,r){let l=e.createElement("div");return l.classList.add("window-captcha"),l.innerHTML=`<div class="window-captcha__content"><div class="window-captcha__content__header">Я не робот! <button type="button" class="window-captcha__reload"></button><button type="button" class="window-captcha__close">X</button></div><div class="window-captcha__content__body"></div></div>`,a.appendChild(l),l.addEventListener("click",function(e){if(e.target!==l)return null;n(l)}),l.querySelector("button.window-captcha__close").addEventListener("click",function(){n(l)}),l.querySelector("button.window-captcha__reload").addEventListener("click",function(){c(l,o,i,a,r)}),l}(a,r,l,t)),s.style.display="block",c(s,r,l,a,t)})})}(document);

View File

@@ -0,0 +1,5 @@
/*
* Copyright (C) 2023 Leonid Nikitin (kor-elf)
* https://git.kor-elf.net/kor-elf/service-captcha-gui/src/branch/main/LICENSE.md
*/
.button-open-window-captcha:hover,.window-captcha__close:hover,.window-captcha__content__body__button:hover{opacity:.8}.captcha-verified{background:#1d8100;border:1px solid #ddd;border-radius:90px;padding:10px 20px;color:#000;font-size:18px;font-weight:700;font-family:serif;display:inline-block;vertical-align:top}.button-open-window-captcha,.window-captcha__content__body__button{background:#68aaff;border:1px solid #ddd;border-radius:90px;padding:10px 20px;cursor:pointer;color:#000;font-size:18px;font-weight:700;font-family:serif}.window-captcha__content__body__button{border-radius:0;width:100%;padding:20px 0;border:0;position:relative}.window-captcha__content__body__button .loading{background:rgba(255,255,255,.48)}.window-captcha{background:rgba(0,0,0,.48);position:fixed;left:0;top:0;width:100%;height:100%;overflow:auto;display:none}.window-captcha__close{background:#961b1b;position:absolute;top:0;right:0;padding:15px;font-size:20px;font-weight:700;font-family:serif;color:#fff;border:0;cursor:pointer}.window-captcha__content{background:#fff;border-radius:3px;margin:20px auto;max-width:600px;box-shadow:3px 3px 10px rgba(0,0,0,.33)}.window-captcha__content__header{position:relative;font-size:20px;font-weight:700;color:#000;font-family:serif;padding:14px 40px 7px 20px;border-bottom:2px solid #ccc}.window-captcha__content__body .error-message,.window-captcha__content__body__error{color:#961b1b;font-size:16px;font-weight:700;padding:20px}.window-captcha__reload{background:url('images/refresh.png') center center no-repeat;width:32px;height:32px;border:1px solid #ddd;border-radius:90px;cursor:pointer;vertical-align:middle;margin-left:10px}.window-captcha__content__reload:hover{background-color:rgba(0,0,0,.15)}.window-captcha__content__body{min-height:400px;position:relative}.window-captcha__content__body .loading{position:absolute;left:0;top:0;width:100%;height:100%;display:flex;justify-content:center;align-items:center}.window-captcha__content__body .loading:before{width:40px;height:40px;border:4px solid #ddd;border-top:4px solid #2e93e6;border-radius:50%;animation:.8s linear infinite sp-anime;display:flex;justify-content:center;align-items:center;content:' '}.window-captcha__content__body p{font-size:20px;font-weight:700;padding:5px 20px;font-family:serif}.window-captcha__content__body__coordinator{cursor:pointer;position:relative}.window-captcha__content__body__coordinator .pointer{background:#fff;position:absolute;border-radius:90px;border:1px solid #961b1b;width:30px;height:30px;margin:-15px 0 0 -15px;display:flex;align-items:center;justify-content:center;font-weight:700;font-family:serif;font-size:16px}.window-captcha__content__body__coordinator .pointer:hover span{font-size:0}.window-captcha__content__body__coordinator .pointer:hover span:after{content:"X";font-size:16px;color:#961b1b}.window-captcha__content__body__error{border:1px solid #961b1b;margin:20px}@keyframes sp-anime{100%{transform:rotate(360deg)}}

View File

View File

@@ -0,0 +1,55 @@
<?php
use Illuminate\Contracts\Http\Kernel;
use Illuminate\Http\Request;
define('LARAVEL_START', microtime(true));
/*
|--------------------------------------------------------------------------
| Check If The Application Is Under Maintenance
|--------------------------------------------------------------------------
|
| If the application is in maintenance / demo mode via the "down" command
| we will load this file so that any pre-rendered content can be shown
| instead of starting the framework, which could cause an exception.
|
*/
if (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {
require $maintenance;
}
/*
|--------------------------------------------------------------------------
| Register The Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader for
| this application. We just need to utilize it! We'll simply require it
| into the script here so we don't need to manually load our classes.
|
*/
require __DIR__.'/../vendor/autoload.php';
/*
|--------------------------------------------------------------------------
| Run The Application
|--------------------------------------------------------------------------
|
| Once we have the application, we can handle the incoming request using
| the application's HTTP kernel. Then, we will send the response back
| to this client's browser, allowing them to enjoy our application.
|
*/
$app = require_once __DIR__.'/../bootstrap/app.php';
$kernel = $app->make(Kernel::class);
$response = $kernel->handle(
$request = Request::capture()
)->send();
$kernel->terminate($request, $response);

View File

@@ -0,0 +1,2 @@
User-agent: *
Disallow:

View File

@@ -0,0 +1,260 @@
{
"openapi": "3.0.3",
"info": {
"title": "Captcha service - API",
"description": "API Documentation.",
"version": "1.0.0"
},
"tags": [
{
"name": "captcha",
"description": "Operations about captcha"
}
],
"paths": {
"/api/v1/captcha": {
"get": {
"tags": [
"captcha"
],
"summary": "Captcha generation",
"description": "",
"operationId": "captchaGeneration",
"parameters": [
{
"name": "public-token",
"in": "header",
"description": "Public token for captcha generation",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "successful operation",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Captcha"
}
}
}
}
},
"403": {
"description": "Invalid public token value"
}
}
},
"post": {
"tags": [
"captcha"
],
"summary": "Checking captcha",
"description": "",
"operationId": "captchaChecking",
"parameters": [
{
"name": "public-token",
"in": "header",
"description": "Public token for captcha generation",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/CaptchaChecking"
}
}
}
}
},
"responses": {
"200": {
"description": "successful operation",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/CaptchaVerification"
}
}
}
}
},
"403": {
"description": "Invalid public token value"
}
}
}
},
"/api/v1/captcha/{captcha_key}": {
"post": {
"tags": [
"captcha"
],
"summary": "Verification Information",
"description": "",
"operationId": "CaptchaKeyInfo",
"parameters": [
{
"name": "private-token",
"in": "header",
"description": "Private token for captcha verification",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "captcha_key",
"in": "path",
"description": "The key that we received when generating the captcha",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/GetCaptchaKeyInfo"
}
}
}
}
},
"responses": {
"200": {
"description": "successful operation",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/CaptchaKeyInfo"
}
}
}
}
},
"403": {
"description": "Invalid private token value"
},
"404": {
"description": "Captcha key not found"
}
}
}
}
},
"components": {
"schemas": {
"Captcha": {
"type": "object",
"properties": {
"image_head": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Image",
}
},
"image_body": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Image"
}
},
"captcha_key": {
"type": "string"
}
},
"required": [
"image_head", "image_body", "captcha_key"
]
},
"Image": {
"type": "object",
"properties": {
"base64": {
"type": "string",
"format": "byte"
},
"width": {
"type": "integer"
},
"height": {
"type": "integer"
}
},
"required": [
"base64", "width", "height"
]
},
"CaptchaVerification": {
"type": "object",
"properties": {
"captcha_key": {
"type": "string"
}
},
"required": [
"captcha_key"
]
},
"CaptchaChecking": {
"type": "object",
"properties": {
"captcha_key": {
"type": "string"
},
"verification": {
"type": "array",
"example": [{"x": 10, "y": 20}, {"x": 30, "y": 30}, {"x": 60, "y": 50}]
}
},
"required": [
"captcha_key", "verification"
]
},
"CaptchaKeyInfo": {
"type": "object",
"properties": {
"status": {
"type": "boolean"
},
"message": {
"type": "string"
}
},
"required": [
"status", "message"
]
},
"GetCaptchaKeyInfo": {
"type": "object",
"properties": {
"user_agent": {
"type": "string"
}
}
}
}
}
}