Skip to content

Commit

Permalink
Better input validator for names and tags
Browse files Browse the repository at this point in the history
  • Loading branch information
jschlyter committed Jan 13, 2025
1 parent 4f87a88 commit 06bc9e9
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 8 deletions.
13 changes: 9 additions & 4 deletions nodeman/models.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import re
from datetime import datetime, timezone
from enum import StrEnum
from typing import Self
from typing import Annotated, Self

from cryptography.x509 import load_pem_x509_certificates
from pydantic import BaseModel, Field, field_validator
from pydantic import BaseModel, Field, StringConstraints, field_validator
from pydantic.types import AwareDatetime

from .db_models import TapirNode
Expand All @@ -12,6 +13,10 @@

MAX_REQUEST_AGE = 300

DOMAIN_NAME_RE = re.compile(r"^(?=.{1,255}$)(?!-)[A-Za-z0-9\-]{1,63}(\.[A-Za-z0-9\-]{1,63})*\.?(?<!-)$")

NodeTag = Annotated[str, StringConstraints(pattern=r"^[A-Za-z0-9/\-\.]{1,100}$")]


class PublicKeyFormat(StrEnum):
PEM = "application/x-pem-file"
Expand All @@ -27,8 +32,8 @@ def from_accept(cls, accept: str | None) -> Self:


class NodeCreateRequest(BaseModel):
name: str | None = Field(title="Node name", default=None)
tags: list[str] | None = Field(title="Node tags", default=None)
name: str | None = Field(title="Node name", json_schema_extra={"format": "hostname"}, default=None)
tags: list[NodeTag] | None = Field(title="Node tags", max_length=100, default=None)


class NodeRequest(BaseModel):
Expand Down
3 changes: 2 additions & 1 deletion nodeman/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from .db_models import TapirCertificate, TapirNode, TapirNodeEnrollment
from .jose import PublicEC, PublicOKP, PublicRSA
from .models import (
DOMAIN_NAME_RE,
EnrollmentRequest,
NodeBootstrapInformation,
NodeCertificate,
Expand Down Expand Up @@ -144,7 +145,7 @@ async def create_node(

if name is None:
node = TapirNode.create_next_node(domain=domain)
elif name.endswith(f".{domain}"):
elif name.endswith(f".{domain}") and DOMAIN_NAME_RE.match(name):
logging.debug("Explicit node name %s requested", name, extra={"nodename": name})
node = TapirNode(name=name, domain=domain).save()
else:
Expand Down
Loading

0 comments on commit 06bc9e9

Please sign in to comment.