diff options
Diffstat (limited to 'src/main/java/org/zwobble')
5 files changed, 114 insertions, 10 deletions
diff --git a/src/main/java/org/zwobble/mammoth/DocumentConverter.java b/src/main/java/org/zwobble/mammoth/DocumentConverter.java index 2dea8e8..c7dca20 100644 --- a/src/main/java/org/zwobble/mammoth/DocumentConverter.java +++ b/src/main/java/org/zwobble/mammoth/DocumentConverter.java @@ -61,6 +61,15 @@ public class DocumentConverter { } /** + * Source documents may reference files outside of the source document. + * Call this to disable access to any such external files during the conversion process. + * This is highly recommended when converting untrusted user input. + */ + public DocumentConverter disableExternalFileAccess() { + return new DocumentConverter(options.disableExternalFileAccess()); + } + + /** * By default, images are converted to {@code <img>} elements with the source included inline in the {@code src} attribute. * Call this to change how images are converted. */ diff --git a/src/main/java/org/zwobble/mammoth/internal/InternalDocumentConverter.java b/src/main/java/org/zwobble/mammoth/internal/InternalDocumentConverter.java index 8ff1e95..3e01181 100644 --- a/src/main/java/org/zwobble/mammoth/internal/InternalDocumentConverter.java +++ b/src/main/java/org/zwobble/mammoth/internal/InternalDocumentConverter.java @@ -45,7 +45,7 @@ public class InternalDocumentConverter { Optional<StyleMap> styleMap = readEmbeddedStyleMap(zipFile).map(StyleMapParser::parse); DocumentToHtmlOptions conversionOptions = styleMap.map(options::addEmbeddedStyleMap).orElse(options); - return readDocument(path, zipFile) + return readDocument(path, zipFile, conversionOptions.externalFileAccess()) .flatMap(nodes -> DocumentToHtml.convertToHtml(nodes, conversionOptions)) .map(Html::stripEmpty) .map(Html::collapse) @@ -69,7 +69,7 @@ public class InternalDocumentConverter { } private InternalResult<String> extractRawText(Optional<Path> path, Archive zipFile) { - return readDocument(path, zipFile) + return readDocument(path, zipFile, options.externalFileAccess()) .map(RawText::extractRawText); } diff --git a/src/main/java/org/zwobble/mammoth/internal/conversion/DocumentToHtmlOptions.java b/src/main/java/org/zwobble/mammoth/internal/conversion/DocumentToHtmlOptions.java index 2c455e2..d12bbd4 100644 --- a/src/main/java/org/zwobble/mammoth/internal/conversion/DocumentToHtmlOptions.java +++ b/src/main/java/org/zwobble/mammoth/internal/conversion/DocumentToHtmlOptions.java @@ -16,6 +16,7 @@ public class DocumentToHtmlOptions { StyleMap.EMPTY, false, false, + false, InternalImageConverter.imgElement(image -> { String base64 = Base64Encoding.streamToBase64(image::getInputStream); String src = "data:" + image.getContentType() + ";base64," + base64; @@ -30,6 +31,7 @@ public class DocumentToHtmlOptions { private final StyleMap embeddedStyleMap; private final boolean disableDefaultStyleMap; private final boolean disableEmbeddedStyleMap; + private final boolean disableExternalFileAccess; private final InternalImageConverter imageConverter; public DocumentToHtmlOptions( @@ -39,6 +41,7 @@ public class DocumentToHtmlOptions { StyleMap embeddedStyleMap, boolean disableDefaultStyleMap, boolean disableEmbeddedStyleMap, + boolean disableExternalFileAccess, InternalImageConverter imageConverter ) { this.idPrefix = idPrefix; @@ -47,15 +50,34 @@ public class DocumentToHtmlOptions { this.embeddedStyleMap = embeddedStyleMap; this.disableDefaultStyleMap = disableDefaultStyleMap; this.disableEmbeddedStyleMap = disableEmbeddedStyleMap; + this.disableExternalFileAccess = disableExternalFileAccess; this.imageConverter = imageConverter; } public DocumentToHtmlOptions idPrefix(String prefix) { - return new DocumentToHtmlOptions(prefix, preserveEmptyParagraphs, styleMap, embeddedStyleMap, disableDefaultStyleMap, disableEmbeddedStyleMap, imageConverter); + return new DocumentToHtmlOptions( + prefix, + preserveEmptyParagraphs, + styleMap, + embeddedStyleMap, + disableDefaultStyleMap, + disableEmbeddedStyleMap, + disableExternalFileAccess, + imageConverter + ); } public DocumentToHtmlOptions preserveEmptyParagraphs() { - return new DocumentToHtmlOptions(idPrefix, true, styleMap, embeddedStyleMap, disableDefaultStyleMap, disableEmbeddedStyleMap, imageConverter); + return new DocumentToHtmlOptions( + idPrefix, + true, + styleMap, + embeddedStyleMap, + disableDefaultStyleMap, + disableEmbeddedStyleMap, + disableExternalFileAccess, + imageConverter + ); } public DocumentToHtmlOptions addStyleMap(String styleMap) { @@ -63,19 +85,68 @@ public class DocumentToHtmlOptions { } public DocumentToHtmlOptions addStyleMap(StyleMap styleMap) { - return new DocumentToHtmlOptions(idPrefix, preserveEmptyParagraphs, this.styleMap.update(styleMap), embeddedStyleMap, disableDefaultStyleMap, disableEmbeddedStyleMap, imageConverter); + return new DocumentToHtmlOptions( + idPrefix, + preserveEmptyParagraphs, + this.styleMap.update(styleMap), + embeddedStyleMap, + disableDefaultStyleMap, + disableEmbeddedStyleMap, + disableExternalFileAccess, + imageConverter + ); } public DocumentToHtmlOptions disableDefaultStyleMap() { - return new DocumentToHtmlOptions(idPrefix, preserveEmptyParagraphs, styleMap, embeddedStyleMap, true, disableEmbeddedStyleMap, imageConverter); + return new DocumentToHtmlOptions( + idPrefix, + preserveEmptyParagraphs, + styleMap, + embeddedStyleMap, + true, + disableEmbeddedStyleMap, + disableExternalFileAccess, + imageConverter + ); } public DocumentToHtmlOptions disableEmbeddedStyleMap() { - return new DocumentToHtmlOptions(idPrefix, preserveEmptyParagraphs, styleMap, embeddedStyleMap, disableDefaultStyleMap, true, imageConverter); + return new DocumentToHtmlOptions( + idPrefix, + preserveEmptyParagraphs, + styleMap, + embeddedStyleMap, + disableDefaultStyleMap, + true, + disableExternalFileAccess, + imageConverter + ); + } + + public DocumentToHtmlOptions disableExternalFileAccess() { + return new DocumentToHtmlOptions( + idPrefix, + preserveEmptyParagraphs, + styleMap, + embeddedStyleMap, + disableDefaultStyleMap, + disableEmbeddedStyleMap, + true, + imageConverter + ); } public DocumentToHtmlOptions addEmbeddedStyleMap(StyleMap embeddedStyleMap) { - return new DocumentToHtmlOptions(idPrefix, preserveEmptyParagraphs, styleMap, embeddedStyleMap, disableDefaultStyleMap, disableEmbeddedStyleMap, imageConverter); + return new DocumentToHtmlOptions( + idPrefix, + preserveEmptyParagraphs, + styleMap, + embeddedStyleMap, + disableDefaultStyleMap, + disableEmbeddedStyleMap, + disableExternalFileAccess, + imageConverter + ); } public DocumentToHtmlOptions imageConverter(ImageConverter.ImgElement imageConverter) { @@ -86,6 +157,7 @@ public class DocumentToHtmlOptions { embeddedStyleMap, disableDefaultStyleMap, disableEmbeddedStyleMap, + disableExternalFileAccess, InternalImageConverter.imgElement(imageConverter) ); } @@ -110,6 +182,10 @@ public class DocumentToHtmlOptions { return styleMap; } + public boolean externalFileAccess() { + return !this.disableExternalFileAccess; + } + public InternalImageConverter imageConverter() { return imageConverter; } diff --git a/src/main/java/org/zwobble/mammoth/internal/docx/DisabledFileReader.java b/src/main/java/org/zwobble/mammoth/internal/docx/DisabledFileReader.java new file mode 100644 index 0000000..03386d4 --- /dev/null +++ b/src/main/java/org/zwobble/mammoth/internal/docx/DisabledFileReader.java @@ -0,0 +1,11 @@ +package org.zwobble.mammoth.internal.docx; + +import java.io.IOException; +import java.io.InputStream; + +public class DisabledFileReader implements FileReader { + @Override + public InputStream getInputStream(String uri) throws IOException { + throw new IOException("could not open external image '" + uri + "': external file access is disabled"); + } +} diff --git a/src/main/java/org/zwobble/mammoth/internal/docx/DocumentReader.java b/src/main/java/org/zwobble/mammoth/internal/docx/DocumentReader.java index 1955e55..495646f 100644 --- a/src/main/java/org/zwobble/mammoth/internal/docx/DocumentReader.java +++ b/src/main/java/org/zwobble/mammoth/internal/docx/DocumentReader.java @@ -22,13 +22,21 @@ import static org.zwobble.mammoth.internal.util.Lists.*; import static org.zwobble.mammoth.internal.util.Strings.trimLeft; public class DocumentReader { - public static InternalResult<Document> readDocument(Optional<Path> path, Archive zipFile) { + public static InternalResult<Document> readDocument( + Optional<Path> path, + Archive zipFile, + boolean externalFileAccess + ) { PartPaths partPaths = findPartPaths(zipFile); Styles styles = readStyles(zipFile, partPaths); Numbering numbering = readNumbering(zipFile, partPaths, styles); ContentTypes contentTypes = readContentTypes(zipFile); - FileReader fileReader = new PathRelativeFileReader(path); + + FileReader fileReader = externalFileAccess + ? new PathRelativeFileReader(path) + : new DisabledFileReader(); + PartWithBodyReader partReader = new PartWithBodyReader(zipFile, contentTypes, fileReader, numbering, styles); return InternalResult.flatMap( readNotes(partReader, partPaths), |
