ldc-web-admin-secure-laravel/src/Options.php
2026-06-22 12:39:37 +02:00

149 lines
4.6 KiB
PHP

<?php
declare(strict_types=1);
namespace Uwil\LaravelAdminSecure;
use Dxw\CIDR\IPv4Range;
use Dxw\CIDR\IPv6Range;
use Illuminate\Support\Facades\Cache;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Uwil\LaravelAdminSecure\Exceptions\AdminSecureException;
/**
* Configuration
*/
final class Options
{
/** @var array<string, mixed> The configuration options. */
private $options;
/** @var \Symfony\Component\OptionsResolver\OptionsResolver The options resolver. */
private $resolver;
/** @var string The cache key where to store config cidr list. */
private static string $cache_config_key = 'uwil_ip_cidr_config_list';
/**
* Class constructor.
*
* @param array<string, mixed> $options The configuration options.
*/
public function __construct(array $options = [])
{
$this->resolver = new OptionsResolver();
$this->configureOptions($this->resolver);
$this->options = $this->resolver->resolve($options);
}
/**
* Get cidr list.
*
* @return array<\Dxw\CIDR\IPv4Range|\Dxw\CIDR\IPv6Range>
*/
public function getCidrList(): array
{
return $this->options['cidrList'];
}
/**
* Get cidr project allowed list.
*
* @return array<\Dxw\CIDR\IPv4Range|\Dxw\CIDR\IPv6Range>
*/
public function getCidrAllowedList(): array
{
return $this->options['cidrProjectAllowedList'];
}
/**
* Configures the options of the client.
*
* @param \Symfony\Component\OptionsResolver\OptionsResolver $resolver The resolver for the options.
*/
private function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'cidrList' => [],
'cidrProjectAllowedList' => [],
]);
$resolver->setNormalizer('cidrList', $this->normalizeCidrList(...));
$resolver->setNormalizer('cidrProjectAllowedList', $this->normalizeCidrProjectList(...));
}
/**
* Normalise Cidr list for cidrList option.
*
* @return array<\Dxw\CIDR\IPv4Range|\Dxw\CIDR\IPv6Range>
*
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
*/
private function normalizeCidrList(
\Symfony\Component\OptionsResolver\Options $options,
?string $value
): array {
// phpcs:enable
return $this->doNormalizeCidrList($value, 'cidrList');
}
/**
* Normalise Cidr list for cidrProjectAllowedList option.
*
* @return array<\Dxw\CIDR\IPv4Range|\Dxw\CIDR\IPv6Range>
*
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundBeforeLastUsed
*/
private function normalizeCidrProjectList(
\Symfony\Component\OptionsResolver\Options $options,
?string $value
): array {
// phpcs:enable
return $this->doNormalizeCidrList($value, 'cidrProjectAllowedList');
}
/**
* Normalize CIDR list with specific cache key.
*
* @return array<\Dxw\CIDR\IPv4Range|\Dxw\CIDR\IPv6Range>
*/
private function doNormalizeCidrList(?string $value, string $optionName): array
{
$cacheConfigKey = self::$cache_config_key . '_' . $optionName;
$allowed_cidr_config_list = collect(explode(',', strval($value)))->filter();
$allowed_cidr_config_list_hash = \md5($allowed_cidr_config_list->implode(','));
/** @var array{list: array<\Dxw\CIDR\IPv4Range|\Dxw\CIDR\IPv6Range>, hash: string}|null $cached */
$cached = Cache::get($cacheConfigKey);
// Flush cache if config hash changed
if ($cached === null || $cached['hash'] !== $allowed_cidr_config_list_hash) {
Cache::forget($cacheConfigKey);
/** @var array<\Dxw\CIDR\IPv4Range|\Dxw\CIDR\IPv6Range> $allowed_cidr_list */
$allowed_cidr_list = $allowed_cidr_config_list
->map(function (string $cidr) {
$ip_range = ! IPv4Range::Make($cidr)->isErr() ? IPv4Range::Make($cidr) : IPv6Range::Make($cidr);
if ($ip_range->isErr()) {
throw new AdminSecureException(\trans(
'CIDR LIST not valid (ipv4 or ipv6 cidr) :cidr',
['cidr' => $cidr]
));
}
return $ip_range->unwrap();
})->all();
Cache::forever($cacheConfigKey, [
'list' => $allowed_cidr_list,
'hash' => $allowed_cidr_config_list_hash,
]);
return $allowed_cidr_list;
}
return $cached['list'];
}
}