diff --git a/lib/printing/pdfbox-app-2.0.31.jar b/lib/printing/pdfbox-app-3.0.4.jar similarity index 63% rename from lib/printing/pdfbox-app-2.0.31.jar rename to lib/printing/pdfbox-app-3.0.4.jar index c74c99374..52d64efab 100644 Binary files a/lib/printing/pdfbox-app-2.0.31.jar and b/lib/printing/pdfbox-app-3.0.4.jar differ diff --git a/src/qz/printer/action/PrintPDF.java b/src/qz/printer/action/PrintPDF.java index 8e3e68cf2..fd288ddf9 100644 --- a/src/qz/printer/action/PrintPDF.java +++ b/src/qz/printer/action/PrintPDF.java @@ -3,7 +3,9 @@ import com.github.zafarkhaja.semver.Version; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.pdfbox.Loader; import org.apache.pdfbox.io.IOUtils; +import org.apache.pdfbox.io.RandomAccessReadBuffer; import org.apache.pdfbox.multipdf.Splitter; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; @@ -118,10 +120,18 @@ public void parseData(JSONArray printData, PrintOptions options) throws JSONExce case PLAIN: // There's really no such thing as a 'PLAIN' PDF, assume it's a URL case FILE: - doc = PDDocument.load(ConnectionUtilities.getInputStream(data.getString("data"), true)); + doc = Loader.loadPDF( + new RandomAccessReadBuffer( + ConnectionUtilities.protocolRestricted(data.getString("data")).openStream() + ) + ); break; default: - doc = PDDocument.load(new ByteArrayInputStream(flavor.read(data.getString("data")))); + doc = Loader.loadPDF( + new RandomAccessReadBuffer( + flavor.read(data.getString("data")) + ) + ); } if (pxlOpts.getBounds() != null) { diff --git a/src/qz/printer/action/PrintRaw.java b/src/qz/printer/action/PrintRaw.java index aa4a3a52b..092368f92 100644 --- a/src/qz/printer/action/PrintRaw.java +++ b/src/qz/printer/action/PrintRaw.java @@ -11,6 +11,8 @@ import com.ibm.icu.text.ArabicShapingException; import org.apache.commons.lang3.StringUtils; +import org.apache.pdfbox.Loader; +import org.apache.pdfbox.io.RandomAccessReadBuffer; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.common.PDRectangle; import org.apache.pdfbox.rendering.PDFRenderer; @@ -190,10 +192,18 @@ private ImageWrapper getPdfWrapper(String data, JSONObject opt, PrintingUtilitie case PLAIN: // There's really no such thing as a 'PLAIN' PDF, assume it's a URL case FILE: - doc = PDDocument.load(ConnectionUtilities.getInputStream(data, true)); + doc = Loader.loadPDF( + new RandomAccessReadBuffer( + ConnectionUtilities.protocolRestricted(data).openStream() + ) + ); break; default: - doc = PDDocument.load(new ByteArrayInputStream(seekConversion(flavor.read(data), rawOpts))); + doc = Loader.loadPDF( + new RandomAccessReadBuffer( + seekConversion(flavor.read(data), rawOpts) + ) + ); } double scale; diff --git a/src/qz/printer/action/pdf/ParamPdfRenderer.java b/src/qz/printer/action/pdf/ParamPdfRenderer.java index 4236e2fa7..d9d03c0ce 100644 --- a/src/qz/printer/action/pdf/ParamPdfRenderer.java +++ b/src/qz/printer/action/pdf/ParamPdfRenderer.java @@ -39,8 +39,8 @@ public OpaquePageDrawer(PageDrawerParameters parameters) throws IOException { super(parameters); // Note: These must match PdfFontPageDrawer's ignoreTransparency condition - addOperator(new OpaqueDrawObject()); - addOperator(new OpaqueGraphicStateParameters()); + addOperator(new OpaqueDrawObject(this)); + addOperator(new OpaqueGraphicStateParameters(this)); } } } diff --git a/src/qz/printer/rendering/OpaqueDrawObject.java b/src/qz/printer/rendering/OpaqueDrawObject.java index 2b73b0fd5..36562b84a 100644 --- a/src/qz/printer/rendering/OpaqueDrawObject.java +++ b/src/qz/printer/rendering/OpaqueDrawObject.java @@ -1,5 +1,7 @@ package qz.printer.rendering; +import org.apache.pdfbox.contentstream.PDFGraphicsStreamEngine; +import org.apache.pdfbox.contentstream.PDFStreamEngine; import org.apache.pdfbox.contentstream.operator.MissingOperandException; import org.apache.pdfbox.contentstream.operator.Operator; import org.apache.pdfbox.contentstream.operator.graphics.GraphicsOperatorProcessor; @@ -16,7 +18,9 @@ // override draw object to remove any calls to show transparency public class OpaqueDrawObject extends GraphicsOperatorProcessor { - public OpaqueDrawObject() { } + public OpaqueDrawObject(PDFGraphicsStreamEngine context) { + super(context); + } public void process(Operator operator, List operands) throws IOException { if (operands.isEmpty()) { @@ -25,26 +29,26 @@ public void process(Operator operator, List operands) throws IOExceptio COSBase base0 = operands.get(0); if (base0 instanceof COSName) { COSName objectName = (COSName)base0; - PDXObject xobject = context.getResources().getXObject(objectName); + PDXObject xobject = getGraphicsContext().getResources().getXObject(objectName); if (xobject == null) { throw new MissingResourceException("Missing XObject: " + objectName.getName()); } else { if (xobject instanceof PDImageXObject) { PDImageXObject image = (PDImageXObject)xobject; - context.drawImage(image); + getGraphicsContext().drawImage(image); } else if (xobject instanceof PDFormXObject) { try { - context.increaseLevel(); - if (context.getLevel() <= 25) { + getGraphicsContext().increaseLevel(); + if (getGraphicsContext().getLevel() <= 25) { PDFormXObject form = (PDFormXObject)xobject; - context.showForm(form); + getGraphicsContext().showForm(form); } //LOG.error("recursion is too deep, skipping form XObject"); } finally { - context.decreaseLevel(); + getGraphicsContext().decreaseLevel(); } } diff --git a/src/qz/printer/rendering/OpaqueGraphicStateParameters.java b/src/qz/printer/rendering/OpaqueGraphicStateParameters.java index f7532e799..43be6a4ab 100644 --- a/src/qz/printer/rendering/OpaqueGraphicStateParameters.java +++ b/src/qz/printer/rendering/OpaqueGraphicStateParameters.java @@ -39,6 +39,10 @@ public class OpaqueGraphicStateParameters extends OperatorProcessor { private static final Log LOG = LogFactory.getLog(OpaqueGraphicStateParameters.class); + public OpaqueGraphicStateParameters(PDFStreamEngine context) { + super(context); + } + @Override public void process(Operator operator, List arguments) throws IOException { diff --git a/src/qz/printer/rendering/PdfFontPageDrawer.java b/src/qz/printer/rendering/PdfFontPageDrawer.java index cfb96943d..7a003440c 100644 --- a/src/qz/printer/rendering/PdfFontPageDrawer.java +++ b/src/qz/printer/rendering/PdfFontPageDrawer.java @@ -33,8 +33,8 @@ public PdfFontPageDrawer(PageDrawerParameters parameters, boolean ignoresTranspa if (ignoresTransparency) { // Note: These must match ParamPdfRenderer's OpaquePageDrawer - addOperator(new OpaqueDrawObject()); - addOperator(new OpaqueGraphicStateParameters()); + addOperator(new OpaqueDrawObject(this)); + addOperator(new OpaqueGraphicStateParameters(this)); } } diff --git a/src/qz/utils/ConnectionUtilities.java b/src/qz/utils/ConnectionUtilities.java index 466a02828..edd77e6e3 100644 --- a/src/qz/utils/ConnectionUtilities.java +++ b/src/qz/utils/ConnectionUtilities.java @@ -16,6 +16,7 @@ import java.net.URISyntaxException; import java.net.URL; import java.net.URLConnection; +import java.nio.file.Path; import java.nio.file.Paths; import java.security.cert.Certificate; import java.security.cert.X509Certificate; @@ -44,14 +45,7 @@ public final class ConnectionUtilities { */ public static InputStream getInputStream(String urlString, boolean protocolRestricted) throws IOException { try { - URL url = new URL(urlString); - if(protocolRestricted) { - String allowed = PrefsSearch.getString(ArgValue.SECURITY_DATA_PROTOCOLS); - if(!isAllowed(allowed, url)) { - log.error("URL '{}' is not a valid http or https location. Configure property '{}' to modify this behavior.", url, ArgValue.SECURITY_DATA_PROTOCOLS.getMatch()); - throw new IOException(String.format("URL '%s' is not a valid [%s] location", url, allowed)); - } - } + URL url = protocolRestricted ? protocolRestricted(urlString) : new URL(urlString); URLConnection urlConn = url.openConnection(); for( String key : getRequestProperties().keySet()) { urlConn.setRequestProperty(key, requestProps.get(key)); @@ -65,6 +59,24 @@ public static InputStream getInputStream(String urlString, boolean protocolRestr } } + /** + * Checks urlString for restricted protocol throws IOException if not permitted + * returns URL if permitted + * + * @param urlString + * @return a URL + * @throws IOException + */ + public static URL protocolRestricted(String urlString) throws IOException { + URL url = new URL(urlString); + String allowed = PrefsSearch.getString(ArgValue.SECURITY_DATA_PROTOCOLS); + if(!isAllowed(allowed, url)) { + log.error("URL '{}' is not a valid http or https location. Configure property '{}' to modify this behavior.", url, ArgValue.SECURITY_DATA_PROTOCOLS.getMatch()); + throw new IOException(String.format("URL '%s' is not a valid [%s] location", url, allowed)); + } + return url; + } + private static boolean isAllowed(String allowed, URL url) { if(url == null) return false; String urlProtocol = url.getProtocol();