58 lines
1.9 KiB
Python
58 lines
1.9 KiB
Python
from __future__ import annotations
|
|
|
|
import re
|
|
from urllib.parse import urlsplit
|
|
|
|
from packaging.utils import canonicalize_name
|
|
|
|
|
|
SLUG_RE = re.compile(r"^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$")
|
|
DISTRIBUTION_RE = re.compile(r"^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,126}[A-Za-z0-9])?$")
|
|
IMPORT_RE = re.compile(r"^[A-Za-z_][A-Za-z0-9_]{0,127}$")
|
|
SHA256_RE = re.compile(r"^[a-fA-F0-9]{64}$")
|
|
|
|
SELF_IMPORT_NAME = "netbox_plugin_store"
|
|
SELF_DISTRIBUTION_NAME = canonicalize_name("netbox-plugin-store")
|
|
|
|
|
|
class ValidationError(ValueError):
|
|
pass
|
|
|
|
|
|
def validate_slug(value: str) -> str:
|
|
if not isinstance(value, str) or not SLUG_RE.fullmatch(value):
|
|
raise ValidationError("Invalid plugin slug.")
|
|
return value
|
|
|
|
|
|
def validate_distribution_name(value: str) -> str:
|
|
if not isinstance(value, str) or not DISTRIBUTION_RE.fullmatch(value):
|
|
raise ValidationError("Invalid Python distribution name.")
|
|
return value
|
|
|
|
|
|
def validate_import_name(value: str) -> str:
|
|
if not isinstance(value, str) or not IMPORT_RE.fullmatch(value):
|
|
raise ValidationError("Invalid Python import name.")
|
|
return value
|
|
|
|
|
|
def validate_sha256(value: str) -> str:
|
|
if not isinstance(value, str) or not SHA256_RE.fullmatch(value):
|
|
raise ValidationError("Invalid SHA-256 digest.")
|
|
return value.lower()
|
|
|
|
|
|
def ensure_not_self(package_name: str, import_name: str) -> None:
|
|
if canonicalize_name(package_name) == SELF_DISTRIBUTION_NAME or import_name == SELF_IMPORT_NAME:
|
|
raise ValidationError("The Plugin Store cannot manage its own lifecycle.")
|
|
|
|
|
|
def validate_public_url(value: str) -> str:
|
|
parsed = urlsplit(value)
|
|
if parsed.scheme not in {"https", "http"} or not parsed.hostname:
|
|
raise ValidationError("URL must be an absolute HTTP(S) URL.")
|
|
if parsed.username is not None or parsed.password is not None:
|
|
raise ValidationError("URLs containing credentials are not accepted.")
|
|
return value
|