forkbb/app/Core/Secury.php

111 lines
3.3 KiB
PHP
Raw Normal View History

<?php
2020-12-21 10:40:19 +00:00
/**
* This file is part of the ForkBB <https://github.com/forkbb>.
*
* @copyright (c) Visman <mio.visman@yandex.ru, https://github.com/MioVisman>
* @license The MIT License (MIT)
*/
2020-10-14 13:01:43 +00:00
declare(strict_types=1);
namespace ForkBB\Core;
use Normalizer;
2022-12-10 09:53:16 +00:00
use SensitiveParameter;
use RuntimeException;
use UnexpectedValueException;
use InvalidArgumentException;
class Secury
{
2023-04-27 12:36:15 +00:00
public function __construct(protected array $hmac)
{
2020-06-28 05:10:59 +00:00
if (
empty($hmac['salt'])
|| empty($hmac['algo'])
) {
throw new InvalidArgumentException('Algorithm and salt can not be empty');
}
2021-07-18 03:45:28 +00:00
if (! \in_array($hmac['algo'], \hash_hmac_algos(), true)) {
throw new UnexpectedValueException('Algorithm not supported');
}
}
/**
* Обертка для hash_hmac
2017-02-20 14:52:45 +00:00
*/
public function hash(string $data): string
2017-02-20 14:52:45 +00:00
{
2018-03-08 12:39:54 +00:00
return $this->hmac($data, \md5(__DIR__));
2017-02-20 14:52:45 +00:00
}
/**
* Обертка для hash_hmac
*/
2023-04-27 12:36:15 +00:00
public function hmac(string $data, #[SensitiveParameter] string $key): string
{
if (empty($key)) {
throw new InvalidArgumentException('Key can not be empty');
}
2020-07-03 08:28:10 +00:00
2018-03-08 12:39:54 +00:00
return \hash_hmac($this->hmac['algo'], $data, $key . $this->hmac['salt']);
}
/**
* Возвращает случайную строку заданной длины состоящую из символов 0-9 и a-f
*/
public function randomHash(int $len): string
{
2021-02-05 10:20:03 +00:00
return \substr(\bin2hex(\random_bytes(\intdiv($len, 2) + 1)), 0, $len);
}
/**
* Возвращает случайную строку заданной длины состоящую из цифр, латиницы,
* знака минус и символа подчеркивания
*/
public function randomPass(int $len): string
{
$key = \random_bytes($len);
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
$result = '';
for ($i = 0; $i < $len; ++$i) {
2019-11-28 13:25:13 +00:00
$result .= $chars[\ord($key[$i]) % 64];
}
2020-07-03 08:28:10 +00:00
return $result;
}
/**
* For string: Replacing invalid UTF-8 characters and remove control characters
* For other scalar or null: unchanged
*/
2023-04-27 12:36:15 +00:00
public function replInvalidChars(mixed $data): mixed
{
2018-03-08 12:39:54 +00:00
if (\is_array($data)) {
return \array_map([$this, 'replInvalidChars'], $data);
} elseif (\is_string($data)) {
// Replacing invalid UTF-8 characters
// slow, small memory
2022-05-05 09:39:14 +00:00
//$data = mb_convert_encoding($data, 'UTF-8', 'UTF-8');
// fast, large memory
2022-05-05 09:39:14 +00:00
$data = \htmlspecialchars_decode(\htmlspecialchars($data, \ENT_SUBSTITUTE, 'UTF-8'));
// Canonical Decomposition followed by Canonical Composition
$data = Normalizer::normalize($data, Normalizer::FORM_C);
// Remove control characters
return \preg_replace('%(?:[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]|\xC2[\x80-\x9F])%', '', $data);
} elseif (
null === $data
|| \is_scalar($data)
) {
return $data;
} else {
throw new InvalidArgumentException('Unexpected variable type: ' . \gettype($data));
}
}
}