frontend: tighten extraFiles target type to strMatching regex
damocles suggested using lib.types.strMatching for the target option itself rather than relying solely on the post-hoc assertion. Pattern: `^[A-Za-z0-9_][A-Za-z0-9_./-]*$` — first char alphanumeric/_, then alphanumerics + _ + . + / + - allowed (so nested layouts like "games/bitburner" still work). This rejects at type-check time: - leading `/` (absolute paths) - leading `.` (so `..` as a full string blocked, also `./foo`) - leading `-` (would parse as flag by some tools) - spaces, control chars, weird unicode The existing assertion stays — it catches mid-path `..` segments (`foo/../bar`) that the regex can't reject without lookahead. POSIX regex (which nix uses) doesn't support lookahead, so the type-and-assertion split is the cleanest expression. Refs #273.
This commit is contained in:
parent
2951da32e7
commit
65532e8387
1 changed files with 24 additions and 12 deletions
|
|
@ -192,7 +192,15 @@
|
|||
'';
|
||||
};
|
||||
target = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
# First char must be alphanumeric/underscore (rules out
|
||||
# leading `/`, leading `.`, leading `-`); inner chars
|
||||
# include `.` and `/` so nested layouts like
|
||||
# `"games/bitburner"` work. This is the shape check —
|
||||
# the `..`-segment traversal check is the assertion in
|
||||
# `config.assertions` below (regex alone can't reject
|
||||
# mid-path `..` segments without lookahead, which nix
|
||||
# POSIX regex doesn't support).
|
||||
type = lib.types.strMatching "^[A-Za-z0-9_][A-Za-z0-9_./-]*$";
|
||||
default = name;
|
||||
defaultText = lib.literalMD "the attribute name";
|
||||
description = ''
|
||||
|
|
@ -201,6 +209,11 @@
|
|||
the on-disk layout in the merged derivation. Defaults
|
||||
to the attribute name. Use forward slashes for
|
||||
nested layouts (e.g. `"games/bitburner"`).
|
||||
|
||||
Constrained shape: must start with an alphanumeric or
|
||||
`_`, and only contain alphanumerics, `_`, `.`, `/`,
|
||||
`-`. `..` segments are separately rejected at config
|
||||
eval time.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
|
@ -452,21 +465,20 @@
|
|||
message = "hyperhive.icon must point to an .svg file";
|
||||
}
|
||||
# hyperhive.frontend.extraFiles[*].target is concatenated into
|
||||
# $out during the mergedDist build. Reject path traversal
|
||||
# (`..` segments) and absolute paths (leading `/`) — both would
|
||||
# let an entry escape the static dir. agent.nix is operator-
|
||||
# reviewed, so this is belt-and-braces, but it's the kind of
|
||||
# mistake that's easy to make and hard to spot during review.
|
||||
# $out during the mergedDist build. The option's strMatching
|
||||
# type already rejects leading `/`, leading `.`, and the
|
||||
# weirder characters; this assertion catches mid-path `..`
|
||||
# segments (e.g. `foo/../etc/passwd`) that the type's regex
|
||||
# can't easily express without lookahead. agent.nix is
|
||||
# operator-reviewed, so this is belt-and-braces — but it's the
|
||||
# kind of mistake that's easy to make and hard to spot.
|
||||
{
|
||||
assertion = lib.all (
|
||||
entry:
|
||||
!(lib.hasPrefix "/" entry.target)
|
||||
&& !(builtins.any (seg: seg == "..") (lib.splitString "/" entry.target))
|
||||
entry: !(builtins.any (seg: seg == "..") (lib.splitString "/" entry.target))
|
||||
) (lib.attrValues config.hyperhive.frontend.extraFiles);
|
||||
message = ''
|
||||
hyperhive.frontend.extraFiles: `target` must be a relative
|
||||
path inside the static dir — no leading `/`, no `..`
|
||||
segments.
|
||||
hyperhive.frontend.extraFiles: `target` must not contain
|
||||
`..` path segments.
|
||||
'';
|
||||
}
|
||||
];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue