* Security policy management * Minimum password-length policy * Mixed-case, number, and symbol requirements * Password expiry and history settings * MFA requirement policy * Failed-login and lockout settings * Session idle-time policy * Single-session policy * Automatic successful-login recording * Automatic failed-login recording * Automatic logout recording * Authentication history * IP allow and deny rules * IPv4 CIDR support * Administration and login rule scopes * Trusted-device storage and revocation * Security middleware registration * Administration navigation * Security permissions * Module registration and tests
25 lines
1.1 KiB
PHP
25 lines
1.1 KiB
PHP
<?php
|
|
namespace Modules\Security\Services;
|
|
use Modules\Security\Models\IpRule;
|
|
final class IpRuleService
|
|
{
|
|
public function isBlocked(string $ip, string $scope='admin'): bool
|
|
{
|
|
$column=$scope==='login'?'applies_to_login':'applies_to_admin';
|
|
$rules=IpRule::query()->where('is_active',true)->where($column,true)->get();
|
|
$allow=$rules->where('type','allow');
|
|
if ($allow->isNotEmpty() && !$allow->contains(fn(IpRule $rule)=>$this->matches($ip,$rule->address))) return true;
|
|
return $rules->where('type','deny')->contains(fn(IpRule $rule)=>$this->matches($ip,$rule->address));
|
|
}
|
|
private function matches(string $ip,string $rule): bool
|
|
{
|
|
if ($ip===$rule) return true;
|
|
if (!str_contains($rule,'/')) return false;
|
|
[$subnet,$bits]=explode('/',$rule,2); $bits=(int)$bits;
|
|
if (filter_var($ip,FILTER_VALIDATE_IP,FILTER_FLAG_IPV4) && filter_var($subnet,FILTER_VALIDATE_IP,FILTER_FLAG_IPV4)) {
|
|
$mask=-1 << (32-$bits); return (ip2long($ip)&$mask)===(ip2long($subnet)&$mask);
|
|
}
|
|
return false;
|
|
}
|
|
}
|