fix: resolve per-torrent qb save paths
This commit is contained in:
@@ -23,6 +23,9 @@ class NormalizedResource:
|
||||
files: tuple[resource_pb2.TorrentFile, ...]
|
||||
metainfo: Metainfo
|
||||
metainfo_bytes: bytes = b""
|
||||
# qBittorrent's API-visible save path is intentionally local-only. It
|
||||
# must never become part of inventory or placement protocol messages.
|
||||
save_path: PurePosixPath | None = None
|
||||
|
||||
|
||||
def build_content_tree(
|
||||
@@ -137,6 +140,7 @@ def normalize_resource(
|
||||
character not in "0123456789abcdef" for character in qb_torrent_id
|
||||
):
|
||||
raise ResourceError("torrent hash is invalid")
|
||||
save_path = _save_path(torrent.get("save_path"))
|
||||
summary = resource_pb2.ResourceSummary(
|
||||
qb_torrent_id=qb_torrent_id,
|
||||
display_name=_string(torrent.get("name"), "torrent name"),
|
||||
@@ -172,7 +176,9 @@ def normalize_resource(
|
||||
revision_data, sort_keys=True, separators=(",", ":"),
|
||||
).encode("utf-8")).hexdigest()
|
||||
summary.observed_at.FromDatetime(observed_at)
|
||||
return NormalizedResource(summary, tuple(files), metainfo, metainfo_bytes)
|
||||
return NormalizedResource(
|
||||
summary, tuple(files), metainfo, metainfo_bytes, save_path
|
||||
)
|
||||
|
||||
|
||||
def _set_selection(target: Any, indices: list[int]) -> None:
|
||||
@@ -217,6 +223,20 @@ def _path(value: Any) -> str:
|
||||
return candidate.as_posix()
|
||||
|
||||
|
||||
def _save_path(value: Any) -> PurePosixPath:
|
||||
"""Validate qBittorrent's API-visible per-torrent content root."""
|
||||
|
||||
path = _string(value, "torrent save path")
|
||||
candidate = PurePosixPath(path)
|
||||
if (
|
||||
not candidate.is_absolute()
|
||||
or ".." in candidate.parts
|
||||
or "." in candidate.parts
|
||||
):
|
||||
raise ResourceError("qBittorrent torrent save path is unsafe")
|
||||
return candidate
|
||||
|
||||
|
||||
def _integer(value: Any, name: str) -> int:
|
||||
if isinstance(value, bool) or not isinstance(value, int) or value < 0:
|
||||
raise ResourceError(f"{name} is invalid")
|
||||
|
||||
Reference in New Issue
Block a user