mirror of
https://github.com/BillyOutlast/UNIT3D.git
synced 2026-02-04 03:01:20 +01:00
120 lines
3.4 KiB
PHP
120 lines
3.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* NOTICE OF LICENSE.
|
|
*
|
|
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
|
* The details is bundled with this project in the file LICENSE.txt.
|
|
*
|
|
* @project UNIT3D Community Edition
|
|
*
|
|
* @author HDVinnie <hdinnovations@protonmail.com>
|
|
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
|
*/
|
|
|
|
namespace App\Helpers;
|
|
|
|
use Illuminate\Support\Facades\Crypt;
|
|
use Illuminate\Support\Str;
|
|
use Illuminate\Validation\Validator;
|
|
use Exception;
|
|
|
|
class HiddenCaptcha
|
|
{
|
|
/**
|
|
* Set the hidden captcha tags to put in your form.
|
|
*/
|
|
public static function render(string $mustBeEmptyField = '_username'): string
|
|
{
|
|
$ts = time();
|
|
$random = Str::random(16);
|
|
|
|
// Generate the token
|
|
$token = [
|
|
'timestamp' => $ts,
|
|
'session_id' => session()->getId(),
|
|
'ip' => request()->ip(),
|
|
'user_agent' => request()->header('User-Agent'),
|
|
'random_field_name' => $random,
|
|
'must_be_empty' => $mustBeEmptyField,
|
|
];
|
|
|
|
// Encrypt the token
|
|
$token = Crypt::encrypt(serialize($token));
|
|
|
|
return (string) view('partials.captcha', ['mustBeEmptyField' => $mustBeEmptyField, 'ts' => $ts, 'random' => $random, 'token' => $token]);
|
|
}
|
|
|
|
/**
|
|
* Check the hidden captcha values.
|
|
*/
|
|
public static function check(Validator $validator, int $minLimit = 0, int $maxLimit = 1_200): bool
|
|
{
|
|
$formData = $validator->getData();
|
|
|
|
// Check post values
|
|
if (!isset($formData['_captcha']) || !($token = self::getToken($formData['_captcha'])) || !\is_array($token)) {
|
|
return false;
|
|
}
|
|
|
|
// Hidden "must be empty" field check
|
|
if (!\array_key_exists($token['must_be_empty'], $formData) || !empty($formData[$token['must_be_empty']])) {
|
|
return false;
|
|
}
|
|
|
|
// Check time limits
|
|
$now = time();
|
|
|
|
if ($now - $token['timestamp'] < $minLimit || $now - $token['timestamp'] > $maxLimit) {
|
|
return false;
|
|
}
|
|
|
|
// Check the random posted field
|
|
if (empty($formData[$token['random_field_name']])) {
|
|
return false;
|
|
}
|
|
|
|
// Check if the random field value is similar to the token value
|
|
$randomField = $formData[$token['random_field_name']];
|
|
|
|
return ctype_digit((string) $randomField) && $token['timestamp'] == $randomField;
|
|
}
|
|
|
|
/**
|
|
* Get and check the token values.
|
|
*
|
|
* @return bool|array<string, mixed>
|
|
*/
|
|
private static function getToken(string $captcha): bool|array
|
|
{
|
|
// Get the token values
|
|
try {
|
|
$token = Crypt::decrypt($captcha);
|
|
} catch (Exception) {
|
|
return false;
|
|
}
|
|
|
|
$token = @unserialize($token);
|
|
|
|
// Token is null or unserializable
|
|
if (!$token || !\is_array($token)) {
|
|
return false;
|
|
}
|
|
|
|
// Check token values
|
|
if (empty($token['session_id']) ||
|
|
empty($token['ip']) ||
|
|
empty($token['user_agent']) ||
|
|
$token['session_id'] !== session()->getId() ||
|
|
$token['ip'] !== request()->ip() ||
|
|
$token['user_agent'] !== request()->header('User-Agent')
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
return $token;
|
|
}
|
|
}
|