Форматирование всего серверного кода по стандартам (black)

This commit is contained in:
parent e61ffd793c
commit 06a5a758a3
28 changed files with 611 additions and 305 deletions

View file

@ -8,6 +8,7 @@ class Protocol(str, Enum):
"""
Enum для сетевых протоколов UFW.
"""
TCP = "tcp"
UDP = "udp"
BOTH = "both"
@ -21,12 +22,13 @@ class Protocol(str, Enum):
class Action(str, Enum):
"""
Enum для действий UFW.
Attributes:
ALLOW: Разрешить трафик
DENY: Запретить трафик без уведомления
REJECT: Запретить трафик с уведомлением отправителю
"""
ALLOW = "allow"
DENY = "deny"
REJECT = "reject"
@ -35,17 +37,19 @@ class Action(str, Enum):
class Direction(str, Enum):
"""
Enum для направления трафика UFW.
Attributes:
IN: Входящий трафик
OUT: Исходящий трафик
"""
IN = "in"
OUT = "out"
class UFWRule(BaseModel):
"""Модель правила UFW"""
action: Action
direction: Direction
from_ip: str
@ -58,13 +62,13 @@ class UFWRule(BaseModel):
def validate_port(cls, v):
"""
Проверяет корректность порта или диапазона портов.
Args:
v: Порт (число) или диапазон портов (строка вида "3000:3999")
Returns:
Union[int, str]: Валидированное значение порта
Raises:
ValueError: Если порт или диапазон портов некорректен
"""
@ -74,14 +78,18 @@ class UFWRule(BaseModel):
return v
elif isinstance(v, str):
try:
start, end = map(int, v.split(':'))
start, end = map(int, v.split(":"))
if not (1 <= start <= end <= 65535):
raise ValueError
return v
except (ValueError, TypeError):
raise ValueError(f"Некорректный диапазон портов: {v}. Формат: start:end, где 1 <= start <= end <= 65535")
raise ValueError(
f"Некорректный диапазон портов: {v}. Формат: start:end, где 1 <= start <= end <= 65535"
)
else:
raise ValueError(f"Порт должен быть числом или строкой с диапазоном, получено: {type(v)}")
raise ValueError(
f"Порт должен быть числом или строкой с диапазоном, получено: {type(v)}"
)
@validator("from_ip", "to_ip")
def validate_ip(cls, v):
@ -98,14 +106,18 @@ class UFWRule(BaseModel):
"""Проверяет совместимость версий IP адресов"""
if "from_ip" not in values:
return v
# Определяем версии IP
from_ip = ipaddress.ip_network(values["from_ip"], strict=False)
to_ip = ipaddress.ip_network(v, strict=False)
if isinstance(from_ip, ipaddress.IPv6Network) != isinstance(to_ip, ipaddress.IPv6Network):
raise ValueError("Несовместимые версии IP: нельзя смешивать IPv4 и IPv6 в одном правиле")
if isinstance(from_ip, ipaddress.IPv6Network) != isinstance(
to_ip, ipaddress.IPv6Network
):
raise ValueError(
"Несовместимые версии IP: нельзя смешивать IPv4 и IPv6 в одном правиле"
)
return v
@validator("action", pre=True)
@ -125,44 +137,44 @@ class UFWRule(BaseModel):
def to_ufw_command(self) -> str:
"""Преобразует правило в команду UFW."""
cmd_parts = ["ufw"]
# Добавляем действие
cmd_parts.append(self.action.value)
# Добавляем направление
cmd_parts.append(self.direction.value)
# Добавляем from с IP
cmd_parts.extend(["from", self.from_ip])
# Добавляем to с IP
cmd_parts.extend(["to", self.to_ip])
# Добавляем порт и протокол
port_str = str(self.port) # Работает как с числами, так и с диапазонами
cmd_parts.extend(["port", port_str])
# Добавляем протокол
proto = self.protocol.value
if proto == "both":
cmd_parts.append("proto tcp/udp")
else:
cmd_parts.extend(["proto", proto])
# Добавляем комментарий если есть
if self.comment:
cmd_parts.extend(["comment", f"'{self.comment}'"])
return " ".join(cmd_parts)
@classmethod
def from_ufw_output(cls, line: str) -> "UFWRule":
"""
Создает экземпляр UFWRule из строки вывода команды 'ufw status numbered'.
Args:
line: Строка вывода UFW (например, "[1] 80/tcp ALLOW IN 192.168.1.0/24 # Web Server")
Returns:
UFWRule: Новый экземпляр правила
"""
@ -180,47 +192,53 @@ class UFWRule(BaseModel):
(?:\#\s*(?P<comment>.*?))?
\s*$
"""
match = re.match(pattern, line, re.VERBOSE | re.IGNORECASE)
if not match:
raise ValueError(f"Невозможно разобрать строку правила UFW: {line}")
groups = match.groupdict()
# Преобразуем протокол в enum
proto_str = groups['protocol'].lower()
protocol = Protocol.BOTH if proto_str == "tcp/udp" else \
Protocol.UDP if proto_str == "udp" else Protocol.TCP
proto_str = groups["protocol"].lower()
protocol = (
Protocol.BOTH
if proto_str == "tcp/udp"
else Protocol.UDP if proto_str == "udp" else Protocol.TCP
)
# Преобразуем действие в enum (игнорируем регистр)
action_str = groups['action'].lower()
action = Action.ALLOW if action_str == "allow" else \
Action.DENY if action_str == "deny" else Action.REJECT
action_str = groups["action"].lower()
action = (
Action.ALLOW
if action_str == "allow"
else Action.DENY if action_str == "deny" else Action.REJECT
)
# Преобразуем направление в enum
direction_str = groups['direction'].lower()
direction_str = groups["direction"].lower()
direction = Direction.IN if direction_str == "in" else Direction.OUT
# Обрабатываем IP адреса
from_ip = groups['from_ip'].strip()
from_ip = groups["from_ip"].strip()
if from_ip.lower() == "anywhere":
from_ip = "0.0.0.0/0"
# Для исходящих правил меняем местами from и to
to_ip = "0.0.0.0/0" # По умолчанию anywhere
# Обрабатываем порт
port = groups['port']
if ':' in port:
port = groups["port"]
if ":" in port:
# Оставляем как строку для диапазона
port = port.strip()
else:
# Преобразуем в число для одиночного порта
port = int(port)
# Обрабатываем комментарий
comment = groups.get('comment', '').strip() if groups.get('comment') else None
comment = groups.get("comment", "").strip() if groups.get("comment") else None
return cls(
action=action,
direction=direction,
@ -228,22 +246,23 @@ class UFWRule(BaseModel):
to_ip=to_ip,
port=port,
protocol=protocol,
comment=comment
comment=comment,
)
class UFWRulesResponse(BaseModel):
"""
Модель для представления списка правил UFW.
Attributes:
enabled: Включен ли UFW
rules: Список правил UFW
total_rules: Общее количество правил
"""
enabled: bool = Field(..., description="Включен ли UFW")
rules: List[UFWRule] = Field(default_factory=list, description="Список правил UFW")
@property
def total_rules(self) -> int:
"""Возвращает общее количество правил."""
@ -253,11 +272,12 @@ class UFWRulesResponse(BaseModel):
class UFWStatus(BaseModel):
"""
Модель для представления статуса UFW.
Attributes:
enabled: Включен ли UFW
message: Сообщение о статусе
last_checked: Время последней проверки статуса
"""
enabled: bool = Field(..., description="Включен ли UFW")
message: str = Field(..., description="Сообщение о статусе")