aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/sisudoc/ocda/abstraction/doc_from_artefact.d
diff options
context:
space:
mode:
Diffstat (limited to 'src/sisudoc/ocda/abstraction/doc_from_artefact.d')
-rw-r--r--src/sisudoc/ocda/abstraction/doc_from_artefact.d32
1 files changed, 31 insertions, 1 deletions
diff --git a/src/sisudoc/ocda/abstraction/doc_from_artefact.d b/src/sisudoc/ocda/abstraction/doc_from_artefact.d
index 3a32d25..7cbc73a 100644
--- a/src/sisudoc/ocda/abstraction/doc_from_artefact.d
+++ b/src/sisudoc/ocda/abstraction/doc_from_artefact.d
@@ -86,6 +86,7 @@ template spineDocFromArtefact() {
import sisudoc.ocda.meta.conf_make_meta_structs;
import sisudoc.ocda.meta.doc_matters;
import sisudoc.ocda.io_in.paths_source;
+ import sisudoc.ocda.io_in.carried_names;
import sisudoc.ocda.abstraction.doc_has;
import sisudoc.ocda.abstraction.load;
import sisudoc.ocda.meta.topic_register;
@@ -93,6 +94,7 @@ template spineDocFromArtefact() {
mixin spineDocHasFromAbstraction;
mixin spineAbstractionLoad;
mixin spineTopicRegister;
+ mixin spineCarriedNames;
/+ ↓ a .ssp header key from a field name: the first underscore becomes the
dot that separates the group, so title_main is title.main and
rights_copyright_text is rights.copyright_text. The writer's keys are
@@ -220,6 +222,24 @@ template spineDocFromArtefact() {
mixin spineAbstractionDbRead _dbr;
auto _files = _dbr.dbReadFiles(_artefact, "image");
if (_files.length == 0) { return ""; }
+ /+ ↓ every name checked before anything is created or written.
+ the name comes out of the database and a database can be
+ downloaded, so it is attacker-controlled: it can climb with "..",
+ and chainPath drops everything before an absolute segment, so "/x"
+ would not land under the image directory at all. One bad name means
+ the artefact cannot be trusted for the rest of them, so this
+ refuses the lot rather than skipping one, which is what the zip
+ reader does with a zip.
+ +/
+ foreach (_f; _files) {
+ string _bad = validateCarriedFileName(_f.name);
+ if (_bad.length > 0) {
+ stderr.writeln("WARNING: ", _artefact.baseName,
+ " carries an image spine will not write: ", _bad,
+ "; no image is taken from this artefact");
+ return "";
+ }
+ }
string _root = (tempDir.chainPath("spine-ocda-"
~ _artefact.baseName ~ "-" ~ thisProcessID.to!string).array).to!string;
string _img_dir = (_root.chainPath("media").chainPath("image").array).to!string;
@@ -237,8 +257,18 @@ template spineDocFromArtefact() {
" does not match the digest recorded with it (", _f.sha256, " expected, ",
_got, " found); it is written out as it stands");
}
+ string _out_path = (_img_dir.chainPath(_f.name).array).to!string;
+ /+ ↓ the check on the check: the name rules above already forbid a
+ directory part, so this can only fire if they were loosened
+ +/
+ if (!(carriedPathIsWithin(_img_dir, _out_path))) {
+ stderr.writeln("WARNING: ", _f.name, " in ", _artefact.baseName,
+ " resolves outside the image directory; no image is taken from",
+ " this artefact");
+ return "";
+ }
try {
- (_img_dir.chainPath(_f.name).array).to!string.write(_f.data);
+ _out_path.write(_f.data);
} catch (Exception ex) {
stderr.writeln("WARNING: could not write ", _f.name, ": ", ex.msg);
}