diff --git a/omicron/ssg/output/output.py b/omicron/ssg/output/output.py index 7346406..f29d0fe 100644 --- a/omicron/ssg/output/output.py +++ b/omicron/ssg/output/output.py @@ -9,6 +9,10 @@ else: Site = "omicron.ssg.site.Site" # for runtime checking with beartype +def is_normalized(path: Path) -> bool: + return ".." not in path.parts + + class OutputError(RuntimeError): pass @@ -16,7 +20,12 @@ class OutputError(RuntimeError): class Output(ABC): def __init__(self, site: Site, destination: Path): self._site_ref = weakref.ref(site) + if destination.is_absolute(): + raise OutputError("destination path must be relative") + if not is_normalized(destination): + raise OutputError("destination path must be normalized") self.destination = destination + url = site.base_dir + "/" + destination.as_posix() url = url.removesuffix("/index.html") or "/" self.url = url diff --git a/omicron/ssg/output/symlink.py b/omicron/ssg/output/symlink.py index 0b8bde6..7f5d5aa 100644 --- a/omicron/ssg/output/symlink.py +++ b/omicron/ssg/output/symlink.py @@ -1,7 +1,7 @@ import logging import os from typing import TYPE_CHECKING -from omicron.ssg.output.output import Output, OutputError +from omicron.ssg.output.output import Output, OutputError, is_normalized from pathlib import Path log = logging.getLogger(__name__) @@ -15,13 +15,9 @@ else: class Symlink(Output): def __init__(self, site: Site, link: Path, target: Path): if target.is_absolute(): - raise ValueError("Symlinks must be relative") - if ( - not (site.output_path / target) - .resolve() - .is_relative_to(site.output_path.resolve()) - ): - raise ValueError("Symlink target escapes the output directory") + raise OutputError("Symlinks target must be relative") + if not is_normalized(target): + raise OutputError("Symlinks target must be normalized") super().__init__(site, link) self.target = target