Files
Nexus/server/utils/login_allowlist.py
T

84 lines
2.7 KiB
Python
Raw Normal View History

"""Login IP allowlist helpers (shared by auth API precheck and AuthService.login)."""
from __future__ import annotations
import ipaddress
from server.config import settings
_TRUTHY = frozenset({"true", "1", "yes", "on"})
def is_allowlist_enforced() -> bool:
"""Whether LOGIN_ALLOWLIST_ENABLED is on."""
val = (getattr(settings, "LOGIN_ALLOWLIST_ENABLED", "false") or "false").lower()
return val in _TRUTHY
def get_allowed_login_ips() -> list[str]:
"""Combined subscription + manual IPs from settings."""
sub_ips_raw = (getattr(settings, "LOGIN_SUBSCRIPTION_IPS", "") or "").strip()
manual_ips_raw = (getattr(settings, "LOGIN_MANUAL_IPS", "") or "").strip()
all_ips_raw = ",".join(filter(None, [sub_ips_raw, manual_ips_raw]))
return [ip.strip() for ip in all_ips_raw.split(",") if ip.strip()]
def ip_in_allowlist(client_ip: str, allowed: list[str]) -> bool:
"""Check if client_ip matches any entry in the allowlist."""
try:
client_addr = ipaddress.ip_address(client_ip)
for entry in allowed:
entry = entry.strip()
try:
if "/" in entry:
if client_addr in ipaddress.ip_network(entry, strict=False):
return True
elif client_addr == ipaddress.ip_address(entry):
return True
except ValueError:
if client_ip == entry:
return True
except ValueError:
return client_ip in allowed
return False
def check_login_ip(client_ip: str) -> tuple[bool, bool, str | None]:
"""Evaluate login IP access.
Returns:
(allowlist_enabled, allowed, message)
- allowlist off: (False, True, None)
- allowlist on, empty list: (True, True, None) — nothing to enforce
- allowlist on, IP ok: (True, True, None)
- allowlist on, IP blocked: (True, False, message)
"""
if not is_allowlist_enforced():
return False, True, None
if not client_ip or client_ip in ("", "unknown"):
return True, True, None
allowed_ips = get_allowed_login_ips()
if not allowed_ips:
return True, True, None
if ip_in_allowlist(client_ip, allowed_ips):
return True, True, None
return (
True,
False,
f"当前 IP ({client_ip}) 不在登录白名单中,请检查代理或联系管理员",
)
def is_whitelisted_login_ip(client_ip: str) -> bool:
"""True when allowlist is enforced, non-empty, and client IP matches."""
if not is_allowlist_enforced():
return False
if not client_ip or client_ip in ("", "unknown"):
return False
allowed_ips = get_allowed_login_ips()
return bool(allowed_ips) and ip_in_allowlist(client_ip, allowed_ips)