Files
PrimAITE/src/primaite/utils/validation/port.py
2024-09-25 16:28:22 +01:00

71 lines
1.8 KiB
Python

# © Crown-owned copyright 2024, Defence Science and Technology Laboratory UK
# Define a custom port validator
from typing import Any
from pydantic import BeforeValidator, TypeAdapter, ValidationError
from typing_extensions import Annotated, Final
PORT_LOOKUP: dict[str, int] = dict(
UNUSED=-1,
NONE=0,
WOL=9,
FTP_DATA=20,
FTP=21,
SSH=22,
SMTP=25,
DNS=53,
HTTP=80,
POP3=110,
SFTP=115,
NTP=123,
IMAP=143,
SNMP=161,
SNMP_TRAP=162,
ARP=219,
LDAP=389,
HTTPS=443,
SMB=445,
IPP=631,
SQL_SERVER=1433,
MYSQL=3306,
RDP=3389,
RTP=5004,
RTP_ALT=5005,
DNS_ALT=5353,
HTTP_ALT=8080,
HTTPS_ALT=8443,
POSTGRES_SERVER=5432,
)
"""
Lookup table used for compatibility with PrimAITE <= 3.3. Configs with named ports names are converted
to port integers at runtime.
"""
def port_validator(v: Any) -> int:
"""
Validate that Ports are chosen from the list of supported Ports.
The protocol list is dynamic because plugins are able to extend it, therefore it is necessary to use this custom
validator instead of being able to specify a union of string literals.
"""
if isinstance(v, str) and v in PORT_LOOKUP:
v = PORT_LOOKUP[v]
if isinstance(v, int) and (0 <= v <= 65535):
return v
raise ValueError(f"{v} is not a valid Port. It must be an integer in the range [0,65535] or ")
Port: Final[Annotated] = Annotated[int, BeforeValidator(port_validator)]
"""Validates that network ports lie in the appropriate range of [0,65535]."""
_PortTypeAdapter = TypeAdapter(Port)
def is_valid_port(v: Any) -> bool:
"""Convenience method to return true if the value matches the schema, and false otherwise."""
try:
_PortTypeAdapter.validate_python(v)
return True
except ValidationError:
return False