71 lines
1.8 KiB
Python
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
|