Compare commits

..

51 commits

Author SHA1 Message Date
K Muller
d07a6b13f1 Merge branch 'trunk' 2026-10-23 13:25:25 +02:00
K Muller
8e5bfbfb03 Merge branch 'develop' into trunk 2026-10-23 13:25:13 +02:00
K Muller
9f46b6cb08 fix: 🐛 error with composer.lock 2026-10-23 11:09:43 +02:00
K Muller
827573c07c Merge branch 'trunk' 2026-10-23 09:26:50 +02:00
K Muller
ebbf947f6e Merge branch 'develop' into trunk 2026-10-23 09:26:35 +02:00
K Muller
cfd7252311 fix: 🐛 resolve conflict + pass in php8.5 for cve patch 2026-10-23 09:11:42 +02:00
K Muller
de92761b82 Merge branch 'develop' into trunk 2026-10-23 09:00:54 +02:00
Karl M'muller
76728fdf13 Merge branch 'issue-21' into 'master'
fix 🐛 error sentry on version 7.3

See merge request ldc-web/projets/qrcollector/qrcollector-back!30
2026-07-29 09:33:33 +00:00
Abdel LAMRANI
e41f3e8a67 fix 🐛 error sentry on version 7.3 2026-07-17 16:46:22 +02:00
K Muller
03883bdc8a Merge branch 'develop' into trunk 2026-06-25 14:26:03 +02:00
K Muller
7219701f4b Merge branch 'develop' into trunk 2026-06-25 11:43:31 +02:00
K Muller
f8d6f74b17 Merge branch 'develop' into trunk 2026-06-18 17:48:31 +02:00
K Muller
25dc69673f Merge branch 'develop' into trunk 2026-06-11 15:39:19 +02:00
Noah Lancien
69e1d855de fix: 🐛 Added handmade admin-secure 2026-05-28 15:03:21 +02:00
K Muller
00be8d0d7f Merge branch 'develop' into trunk 2026-05-21 10:22:49 +02:00
Noah Lancien
366ba81e34 Merge branch 'develop' into trunk 2026-04-23 11:44:12 +02:00
Noah Lancien
e4fe50d0c3 Merge branch 'develop' into trunk 2026-04-23 10:55:03 +02:00
Noah Lancien
c5a963ec54 Merge branch 'develop' into trunk 2026-01-09 10:42:33 +01:00
Vincent BRIDIER
4fe4030f57 Merge branch 'trunk' 2025-11-27 09:53:12 +01:00
Vincent BRIDIER
c3f11e5061 Merge branch 'develop' into trunk 2025-11-27 09:35:37 +01:00
Vincent BRIDIER
b57189277f Merge branch 'trunk' 2025-11-27 09:22:06 +01:00
Vincent BRIDIER
139efff5d7 Merge branch 'develop' into trunk 2025-11-27 09:10:39 +01:00
Noah Lancien
bfb579eb26 Merge branch 'trunk' 2025-02-24 15:58:10 +01:00
Noah Lancien
ae2acc7135 Merge branch 'develop' into trunk 2025-02-24 15:57:30 +01:00
Vincent BRIDIER
0dcc78ff15
Merge branch 'trunk' 2025-02-10 14:28:09 +01:00
Vincent BRIDIER
90540ec61b
Merge branch 'develop' into trunk 2025-02-07 18:48:13 +01:00
Karl Muller
e79789868b Merge branch 'develop' into trunk 2025-02-06 08:46:02 +00:00
Karl Muller
dabe7313d5 Merge branch 'trunk' 2025-01-14 09:06:59 +00:00
Karl Muller
a8a7c09ac2 Merge branch 'develop' into trunk 2025-01-14 09:00:31 +00:00
Karl Muller
57aa99ce10 Merge branch 'develop' into trunk 2025-01-14 08:44:28 +00:00
Thibault Raquet
bf69010694 Merge branch 'trunk' into 'master'
Trunk

See merge request ldc-web/projets/qrcollector/qrcollector-back!14
2024-06-27 10:09:53 +00:00
Thibault Raquet
f412bebed5 Merge branch 'develop' into 'trunk'
Develop

See merge request ldc-web/projets/qrcollector/qrcollector-back!13
2024-06-27 10:09:25 +00:00
Jérémy Munsch
04c702a161
Merge branch 'trunk' 2024-04-26 13:57:07 +02:00
Jérémy Munsch
5e06b6b95e
Merge branch 'develop' into trunk 2024-04-26 13:57:01 +02:00
Jérémy Munsch
48a8252c80
Merge branch 'trunk' 2024-04-25 10:14:49 +02:00
Jérémy Munsch
97c27f8eb6
Merge branch 'develop' into trunk 2024-04-25 10:14:15 +02:00
Vincent BRIDIER
2ad58d625d
Merge branch 'trunk' 2023-12-08 09:10:58 +01:00
Vincent BRIDIER
4865fcd056
Merge branch 'develop' into trunk 2023-12-08 09:10:46 +01:00
Vincent BRIDIER
e325977797
Merge branch 'trunk' 2023-10-06 14:37:29 +02:00
Vincent BRIDIER
f6e109a6ae
Merge branch 'develop' into trunk 2023-10-06 14:30:39 +02:00
Vincent BRIDIER
41f51b1718
Merge branch 'trunk' 2023-10-06 13:02:34 +02:00
Vincent BRIDIER
8c87229c6a
Merge branch 'develop' into trunk 2023-10-06 13:02:26 +02:00
Vincent BRIDIER
a07c896120
Merge branch 'trunk' 2023-09-12 10:14:47 +02:00
Vincent BRIDIER
7023d8317d
Merge branch 'develop' into trunk 2023-09-12 10:04:08 +02:00
Vincent BRIDIER
8c2bad1fa4
Merge branch 'develop' into trunk 2023-05-30 13:52:33 +02:00
Vincent BRIDIER
fd81f00eed
Merge branch 'develop' into trunk 2023-05-30 11:32:00 +02:00
Vincent BRIDIER
0706e6b373
Merge branch 'trunk' 2023-04-17 13:09:32 +02:00
Vincent BRIDIER
9f855df1f8
Merge branch 'trunk' 2023-04-17 11:03:49 +02:00
Vincent BRIDIER
915f843802
Merge branch 'trunk' 2023-03-31 12:08:41 +02:00
Vincent BRIDIER
81472ff5b6
Merge branch 'trunk' 2023-03-30 19:17:03 +02:00
Vincent BRIDIER
808ec716a5
Merge branch 'trunk' 2023-03-29 18:40:50 +02:00
7 changed files with 350 additions and 4 deletions

View file

@ -85,8 +85,8 @@ class StatsController extends Controller
* - total of specific url from a brand
* - total of all urls for each brand
*/
$datasets = match (true) {
!$requestValidated['brand'] => $this->buildDatasets(
if (!$requestValidated['brand']) {
$datasets = $this->buildDatasets(
Brand::all(),
$periodInterval,
$periodEnum,

View file

@ -72,5 +72,6 @@ class Kernel extends HttpKernel
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'htmlsanitize' => \App\Http\Middleware\HtmlSanitizer::class,
'admin-secure' => \App\Http\Middleware\AdminSecureMiddleware::class,
];
}

View file

@ -0,0 +1,49 @@
<?php
namespace App\Http\Middleware;
use App\Lib\AdminSecure;
use Closure;
use Dxw\CIDR\IP;
use Illuminate\Http\Request;
class AdminSecureMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
if (config('app.env') === 'local') {
return $next($request);
}
$client_ip = AdminSecure::fetchClientIp();
$ip_is_allowed = \collect(AdminSecure::getOptions()->getCidrList())
->reduce(function ($initial, $ip_range) use ($client_ip) {
return $initial || IP::contains(
$ip_range,
$client_ip
)->unwrap();
});
$ip_is_allowed_by_config = \collect(AdminSecure::getOptions()->getCidrAllowedList())
->reduce(function ($initial, $ip_range) use ($client_ip) {
return $initial || IP::contains(
$ip_range,
$client_ip
)->unwrap();
});
if ($ip_is_allowed or $ip_is_allowed_by_config or AdminSecure::ipIsPrivate($client_ip)) {
return $next($request);
}
abort(403, \trans('Denied IP'));
}
}

131
app/Lib/AdminSecure.php Normal file
View file

@ -0,0 +1,131 @@
<?php
namespace App\Lib;
use App\Lib\Options;
use Dxw\CIDR\IPAddress;
use Dxw\CIDR\IPv4Address;
use Dxw\CIDR\IPv4Range;
use Dxw\CIDR\IPv6Address;
use Dxw\CIDR\IPv6Range;
abstract class AdminSecure
{
/**
* Private ipV4 CIDR list
*
* @var array
*/
private static $private_ip_v4_cidr_list = [
'10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16'
];
/**
* Private ipV4 CIDR loopback
*
* @var string
*/
private static $private_ip_v4_loopback_cidr = '127.0.0.0/8';
/**
* Private ipV6 CIDR list
*
* @var array
*/
private static $private_ip_v6_cidr_list = [
'fd00::/8'
];
/**
* Private ipV6 CIDR loopback
*
* @var string
*/
private static $private_ip_v6_loopback_cidr = '::1/128';
/**
* Private options
*
* @var \App\Lib\Options|null
*/
private static $options = null;
/**
* Check if ip is private
*
* @param \Dxw\CIDR\IPv4Address|\Dxw\CIDR\IPv6Address $ip_address
* @return boolean
*/
public static function ipIsPrivate($ip_address): bool
{
return \get_class($ip_address) === IPv4Address::class ?
self::ipV4IsPrivate($ip_address) : self::ipV6IsPrivate($ip_address);
}
/**
* Fetch client IP
*
* @return \Dxw\CIDR\IPv4Address|\Dxw\CIDR\IPv6Address
* @throws \Exception If the ip is invalid.
*/
public static function fetchClientIp()
{
// ! REVERSE PROXY HACK.
$ip = request()->server('HTTP_X_FORWARDED_FOR') ?? request()->getClientIp();
$ip = IPAddress::Make($ip);
if ($ip->isErr()) {
throw new \Exception(\trans('Client IP not valid ') . $ip->getErr());
}
return $ip->unwrap();
}
/**
* 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(function (string $ipv4_cidr) {
return IPv4Range::Make($ipv4_cidr)->unwrap();
})
->reduce(function ($initial, IPv4Range $ipv4_range) use ($ipv4_address) {
return $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(function (string $ipv6_cidr) {
return IPv6Range::Make($ipv6_cidr)->unwrap();
})
->reduce(function ($initial, IPv6Range $ipv6_range) use ($ipv6_address) {
return $initial || $ipv6_range->containsAddress($ipv6_address);
});
}
/**
* Get Admin secure options
*
* @return \App\Lib\Options
*/
public static function getOptions(): Options
{
if (!self::$options) {
self::$options = new Options(\config('admin-secure'));
}
return self::$options;
}
}

159
app/Lib/Options.php Normal file
View file

@ -0,0 +1,159 @@
<?php
declare(strict_types=1);
namespace App\Lib;
use Dxw\CIDR\IPv4Range;
use Dxw\CIDR\IPv6Range;
use Illuminate\Support\Facades\Cache;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* Configuration
*/
final class Options
{
/**
* @var array<string, mixed> The configuration options
*/
private $options;
/**
* @var \Symfony\Component\OptionsResolver\OptionsResolver The options resolver
*/
private $resolver;
/**
* The cache key where to store config cidr list.
*
* @var string
*/
private static $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.
* @return void
*/
private function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'cidrList' => [],
'cidrProjectAllowedList' => []
]);
$resolver->setNormalizer('cidrList', \Closure::fromCallable([$this, 'normalizeCidrList']));
$resolver->setNormalizer('cidrProjectAllowedList', \Closure::fromCallable([$this, 'normalizeCidrProjectList']));
}
/**
* Normalise Cidr list for cidrList option
*
* @param \Symfony\Component\OptionsResolver\Options $options
* @param string|null $value
* @return array
* @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
*
* @param \Symfony\Component\OptionsResolver\Options $options
* @param string|null $value
* @return array
* @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.
*
* @param string|null $value
* @param string $optionName
* @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(','));
$allowed_cidr_list = [];
// Flush cache if config hash changed
if ($allowed_cidr_config_list_hash !== \collect(Cache::get($cacheConfigKey))->get('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 \Exception(\trans(
'CIDR LIST not valid (ipv4 or ipv6 cidr) :cidr',
[
'cidr' => $cidr
]
));
}
return $ip_range->unwrap();
})->all();
}
/** @var array<\Dxw\CIDR\IPv4Range|\Dxw\CIDR\IPv6Range> $allowed_cidr_list */
return \collect(Cache::rememberForever($cacheConfigKey, function() use ($allowed_cidr_list, $allowed_cidr_config_list_hash) {
return [
'list' => $allowed_cidr_list,
'hash' => $allowed_cidr_config_list_hash
];
}))->get('list');
}
}

4
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "dfc6b62ebe219dbd2b3a2db68a4922f2",
"content-hash": "d479877b418347bca0a45f46759155b1",
"packages": [
{
"name": "24slides/laravel-saml2",
@ -10514,7 +10514,7 @@
"prefer-stable": true,
"prefer-lowest": false,
"platform": {
"php": "^8.4"
"php": "^8.5"
},
"platform-dev": {},
"plugin-api-version": "2.9.0"

6
config/admin-secure.php Normal file
View file

@ -0,0 +1,6 @@
<?php
return [
'cidrList' => env('UWIL_ADMIN_SECURE_CIDR_LIST'),
'cidrProjectAllowedList' => env('UWIL_ADMIN_SECURE_CIDR_PROJECT_ALLOWED_LIST')
];