server('HTTP_X_FORWARDED_FOR') ?? request()->getClientIp(); $ip = IPAddress::Make($ip); if ($ip->isErr()) { throw new AdminSecureException(\trans('Client IP not valid ') . $ip->getErr()); } return $ip->unwrap(); } /** * Fetch Ip Adress list from LDC Web * * @return array<\Dxw\CIDR\IPv4Address|\Dxw\CIDR\IPv6Address> * @throws \LDC\WebAdminSecureLaravel\AdminSecureException If Wrong env value. * @throws \Illuminate\Http\Client\RequestException If calling admin secure fails. * @phpcs:disable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber */ public static function fetchIpList(): array { // phpcs:enable $endpoint = config('admin-secure.endpoint'); $key = config('admin-secure.apiKey'); if (!$endpoint or !\filter_var($endpoint, \FILTER_VALIDATE_URL)) { throw new AdminSecureException('LDC_WEB_API_ENDPOINT is required in .env to ba a valid url.'); } if (!$key) { throw new AdminSecureException('LDC_WEB_API_KEY is required in .env .'); } $response = Http::get($endpoint, ['token' => $key])->throw(); $adresses = self::parseAdresses($response); Log::info(\sprintf('ADMINSECURE : Fetched %d ip(s) from LDC WEB', \count($adresses))); return $adresses; } /** * Fetch Ip Adress list from LDC Web * * @return array<\Dxw\CIDR\IPv4Range|\Dxw\CIDR\IPv6Range> * @throws \LDC\WebAdminSecureLaravel\AdminSecureException If Wrong env value. * @phpcs:disable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber */ public static function fetchConfigAllowedCidrList(): array { $allowed_cidr_config_list = \collect(config('admin-secure.cidrManualAllowedList'))->filter(); $allowed_cidr_config_list_hash = \md5($allowed_cidr_config_list->implode(',')); $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( 'LDC_WEB_CIDR_MANUAL_ALLOWED_LIST not valid (ipv4 or ipv6 cidr) :cidr', [ 'cidr' => $cidr ] )); } return $ip_range->unwrap(); })->all(); // * Flush cache if hash config hash changed if ($allowed_cidr_config_list_hash !== \collect(Cache::get(self::$cache_config_key))->get('hash')) { Cache::flush(self::$cache_config_key); } /** @var array<\Dxw\CIDR\IPv4Range|\Dxw\CIDR\IPv6Range> $allowed_cidr_list */ return \collect(Cache::rememberForever(self::$cache_config_key, fn () => [ 'list' => $allowed_cidr_list, 'hash' => $allowed_cidr_config_list_hash ]))->get('list'); } /** * Get ip list from cache * * @return array<\Dxw\CIDR\IPv4Address|\Dxw\CIDR\IPv6Address> */ public static function getCacheList(): array { try { $ip_list = Cache::get(self::$cache_key, self::fetchIpList()); self::validateIpList($ip_list); /** @var array<\Dxw\CIDR\IPv4Address|\Dxw\CIDR\IPv6Address> $ip_list */ return $ip_list; } catch (AdminSecureInvalidAdressException) { $ip_list = self::fetchIpList(); self::validateIpList($ip_list); self::setCacheList($ip_list); return $ip_list; } } /** * Set ip list to cache * * @param array<\Dxw\CIDR\IPv4Address|\Dxw\CIDR\IPv6Address> $ip_list * @return void */ public static function setCacheList(array $ip_list): void { self::validateIpList($ip_list); Cache::put(self::$cache_key, $ip_list); } /** * Check if ipV4 is private * * @param \Dxw\CIDR\IPv4Address $ipv4_address * @return boolean */ private static function ipV4IsPrivate(IPv4Address $ipv4_address): bool { return \collect(self::$private_ip_v4_cidr_list) ->concat([self::$private_ip_v4_loopback_cidr]) ->map(fn (string $ipv4_cidr) => IPv4Range::Make($ipv4_cidr)->unwrap()) ->reduce(fn (bool|null $initial, IPv4Range $ipv4_range) => $initial || $ipv4_range->containsAddress($ipv4_address)); } /** * Check if ipV6 is private * * @param \Dxw\CIDR\IPv6Address $ipv6_address * @return boolean */ private static function ipV6IsPrivate(IPv6Address $ipv6_address): bool { return \collect(self::$private_ip_v6_cidr_list) ->concat([self::$private_ip_v6_loopback_cidr]) ->map(fn (string $ipv6_cidr) => IPv6Range::Make($ipv6_cidr)->unwrap()) ->reduce(fn (bool|null $initial, IPv6Range $ipv6_range) => $initial || $ipv6_range->containsAddress($ipv6_address)); } /** * Validate ip list * * @param array $ip_list * @return void * @throws \LDC\WebAdminSecureLaravel\Exceptions\AdminSecureInvalidAdressException If an IP is invalid. */ private static function validateIpList(array $ip_list): void { \collect($ip_list)->each(function ($ip) { if (!\is_object($ip) or !\in_array(\get_class($ip), [IPv4Address::class, IPv6Address::class])) { throw new AdminSecureInvalidAdressException('Invalid adresse ' . \strval(\json_encode($ip))); } }); } /** * Parse adresses * * @param \Illuminate\Http\Client\Response $response * @return array<\Dxw\CIDR\IPAddress> */ private static function parseAdresses(Response $response): array { return \collect($response->json()) ->map(fn (string $ip) => IPAddress::Make($ip)->unwrap())->all(); } }