diff options
Diffstat (limited to 'src/sisudoc/ocda/abstraction/doc_from_artefact.d')
| -rw-r--r-- | src/sisudoc/ocda/abstraction/doc_from_artefact.d | 32 |
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); } |
