Skip to content

Commit

Permalink
Disable file writing by default
Browse files Browse the repository at this point in the history
Per #1210, #730
  • Loading branch information
tresf committed Nov 8, 2023
1 parent 2ff0b88 commit 883094a
Show file tree
Hide file tree
Showing 9 changed files with 59 additions and 54 deletions.
8 changes: 0 additions & 8 deletions js/qz-tray.js
Original file line number Diff line number Diff line change
Expand Up @@ -1074,14 +1074,6 @@ var qz = (function() {
if (typeof newPrinter === 'string') {
newPrinter = { name: newPrinter };
}

if(newPrinter && newPrinter.file) {
// TODO: Warn for UNC paths too https://github.com/qzind/tray/issues/730
if(newPrinter.file.indexOf("\\\\") != 0) {
_qz.log.warn("Printing to file is deprecated. See https://github.com/qzind/tray/issues/730");
}
}

this.printer = newPrinter;
};

Expand Down
34 changes: 0 additions & 34 deletions sample.html
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ <h3 class="panel-title">Printer</h3>
<div class="form-group">
<div class="btn-group" role="group">
<button type="button" class="btn btn-default btn-sm" onclick="setPrinter($('#printerSearch').val());">Set To Search</button>
<button type="button" class="btn btn-default btn-sm" data-toggle="modal" data-target="#askFileModal">Set To File</button>
<button type="button" class="btn btn-default btn-sm" data-toggle="modal" data-target="#askHostModal">Set To Host</button>
</div>
<button type="button" class="btn btn-warning btn-sm" onclick="clearQueue($('#printerSearch').val());">Clear Queue</button>
Expand Down Expand Up @@ -1349,27 +1348,6 @@ <h4 class="panel-title">Options</h4>
</div>
</div>


<div class="modal fade" id="askFileModal" role="dialog">
<div class="modal-dialog modal-sm" role="document">
<div class="modal-content">
<div class="modal-body">
<div class="form-group">
<label for="askFile">File:</label>
<input type="text" id="askFile" class="form-control" value="C:\tmp\example-file.txt" />
<hr />
<p><span class="text-danger" style="font-weight:bold;"><span class="fa fa-warning"></span> WARNING:</span> This feature has been deprecated. Please configure a local raw <code>FILE:</code> printer, or use <code>File IO</code></a> instead. For more
information please see <a href="https://github.com/qzind/tray/issues/730">issue&nbsp;<code>#730</code>.</a></p>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" onclick="setPrintFile();">Set</button>
</div>
</div>
</div>
</div>

<div class="modal fade" id="askHostModal" role="dialog">
<div class="modal-dialog modal-sm" role="document">
<div class="modal-content">
Expand Down Expand Up @@ -2943,13 +2921,6 @@ <h4 class="panel-title">Options</h4>
}).catch(displayError);
}

$("#askFileModal").on("shown.bs.modal", function() {
$("#askFile").focus().select();
});
$("#askHostModal").on("shown.bs.modal", function() {
$("#askHost").focus().select();
});

//make dirty when changed
$("input").add("select").on('change', function() {
$(this).addClass("dirty");
Expand Down Expand Up @@ -3336,11 +3307,6 @@ <h4 class="panel-title">Options</h4>
return options;
}

function setPrintFile() {
setPrinter({ file: $("#askFile").val() });
$("#askFileModal").modal('hide');
}

function setPrintHost() {
setPrinter({ host: $("#askHost").val(), port: $("#askPort").val() });
$("#askHostModal").modal('hide');
Expand Down
2 changes: 1 addition & 1 deletion src/qz/auth/CRL.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public static CRL getInstance() {
public void run() {
log.info("Loading CRL from {}", CRL_URL);

try(BufferedReader br = new BufferedReader(new InputStreamReader(ConnectionUtilities.getInputStream(CRL_URL)))) {
try(BufferedReader br = new BufferedReader(new InputStreamReader(ConnectionUtilities.getInputStream(CRL_URL, false)))) {
String line;
while((line = br.readLine()) != null) {
//Ignore empty and commented lines
Expand Down
2 changes: 1 addition & 1 deletion src/qz/printer/action/PrintImage.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public void parseData(JSONArray printData, PrintOptions options) throws JSONExce
case PLAIN:
// There's really no such thing as a 'PLAIN' image, assume it's a URL
case FILE:
bi = ImageIO.read(ConnectionUtilities.getInputStream(data.getString("data")));
bi = ImageIO.read(ConnectionUtilities.getInputStream(data.getString("data"), true));
break;
default:
bi = ImageIO.read(new ByteArrayInputStream(flavor.read(data.getString("data"))));
Expand Down
2 changes: 1 addition & 1 deletion src/qz/printer/action/PrintPDF.java
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ 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")));
doc = PDDocument.load(ConnectionUtilities.getInputStream(data.getString("data"), true));
break;
default:
doc = PDDocument.load(new ByteArrayInputStream(flavor.read(data.getString("data"))));
Expand Down
27 changes: 21 additions & 6 deletions src/qz/printer/action/PrintRaw.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

import com.ibm.icu.text.ArabicShapingException;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.ssl.Base64;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.rendering.PDFRenderer;
Expand Down Expand Up @@ -175,7 +174,7 @@ private ImageWrapper getImageWrapper(String data, JSONObject opt, PrintingUtilit
case PLAIN:
// There's really no such thing as a 'PLAIN' image, assume it's a URL
case FILE:
bi = ImageIO.read(ConnectionUtilities.getInputStream(data));
bi = ImageIO.read(ConnectionUtilities.getInputStream(data, true));
break;
default:
bi = ImageIO.read(new ByteArrayInputStream(seekConversion(flavor.read(data), rawOpts)));
Expand All @@ -191,7 +190,7 @@ 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));
doc = PDDocument.load(ConnectionUtilities.getInputStream(data, true));
break;
default:
doc = PDDocument.load(new ByteArrayInputStream(seekConversion(flavor.read(data), rawOpts)));
Expand Down Expand Up @@ -329,7 +328,7 @@ public void print(PrintOutput output, PrintOptions options) throws PrintExceptio
if (output.isSetHost()) {
printToHost(output.getHost(), output.getPort(), bab.getByteArray());
} else if (output.isSetFile()) {
printToFile(output.getFile(), bab.getByteArray());
printToFile(output.getFile(), bab.getByteArray(), true);
} else {
if (rawOpts.isForceRaw()) {
if(tempFiles == null) {
Expand All @@ -339,7 +338,7 @@ public void print(PrintOutput output, PrintOptions options) throws PrintExceptio
if(tempFiles.size() <= j) {
tempFile = File.createTempFile("qz_raw_", null);
tempFiles.add(j, tempFile);
printToFile(tempFile, bab.getByteArray());
printToFile(tempFile, bab.getByteArray(), false);
} else {
tempFile = tempFiles.get(j);
}
Expand Down Expand Up @@ -401,7 +400,15 @@ private void printToHost(String host, int port, byte[] cmds) throws IOException
*
* @param file File to be written
*/
private void printToFile(File file, byte[] cmds) throws IOException {
private void printToFile(File file, byte[] cmds, boolean locationRestricted) throws IOException {
if(file == null) throw new IOException("No file specified");

if(!isAllowed(file)) {
log.error("Printing to file '{}' is not permitted. Configure property '{}' or '{}' to modify this behavior.",
file, ArgValue.SECURITY_PRINT_UNC.getMatch(), ArgValue.SECURITY_PRINT_FILE.getMatch());
throw new IOException(String.format("Printing to file '%s' is not permitted", file));
}

log.debug("Printing to file: {}", file.getName());

//throws any exception and auto-closes stream
Expand All @@ -410,6 +417,14 @@ private void printToFile(File file, byte[] cmds) throws IOException {
}
}

private boolean isAllowed(File file) {
return file.getPath().startsWith("\\\\") ?
// UNC Path
PrefsSearch.getBoolean(ArgValue.SECURITY_PRINT_UNC) :
// Regular file
PrefsSearch.getBoolean(ArgValue.SECURITY_PRINT_FILE);
}

/**
* Constructs a {@code SimpleDoc} with the {@code commands} byte array.
*/
Expand Down
6 changes: 6 additions & 0 deletions src/qz/utils/ArgValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ public enum ArgValue {
"security.file.enabled"),
SECURITY_FILE_STRICT(PREFERENCES, "Enable/disable signing requirements for File Communications features", null, true,
"security.file.strict"),
SECURITY_FILE_PROTOCOLS(PREFERENCES, "URL protocols allowed for print, serial, hid, etc", null, "http,https",
"security.file.protocols"),
SECURITY_PRINT_UNC(PREFERENCES, "Enable/disable printing directly to UNC paths", null, false,
"security.print.unc"),
SECURITY_PRINT_FILE(PREFERENCES, "Enable/disable printing directly to file paths", null, false,
"security.print.file"),
LOG_DISABLE(PREFERENCES, "Disable/enable logging features", null, false,
"log.disable"),
LOG_ROTATE(PREFERENCES, "Number of log files to retain when the size fills up", null, 5,
Expand Down
30 changes: 28 additions & 2 deletions src/qz/utils/ConnectionUtilities.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,17 @@ public final class ConnectionUtilities {
*
* @param urlString an absolute URL giving location of resource to read.
*/
public static InputStream getInputStream(String urlString) throws IOException {
public static InputStream getInputStream(String urlString, boolean protocolRestricted) throws IOException {
try {
URLConnection urlConn = new URL(urlString).openConnection();
URL url = new URL(urlString);
if(protocolRestricted) {
String allowed = PrefsSearch.getString(ArgValue.SECURITY_FILE_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_FILE_PROTOCOLS.getMatch());
throw new IOException(String.format("URL '%s' is not a valid [%s] location", url, allowed));
}
}
URLConnection urlConn = url.openConnection();
for( String key : getRequestProperties().keySet()) {
urlConn.setRequestProperty(key, requestProps.get(key));
}
Expand All @@ -54,6 +62,24 @@ public static InputStream getInputStream(String urlString) throws IOException {
}
}

private static boolean isAllowed(String allowed, URL url) {
if(url == null) return false;
String urlProtocol = url.getProtocol();
if(urlProtocol == null || urlProtocol.trim().isEmpty()) return false;
allowed = ArgValue.SECURITY_FILE_PROTOCOLS.getDefaultVal() +
(allowed == null || allowed.trim().isEmpty() ? "" : "," + allowed);
String[] protocols = allowed.split(",");
// Loop over http, https, etc
for(String protocol : protocols) {
if (url != null) {
if(urlProtocol.trim().equalsIgnoreCase(protocol.trim())) {
return true;
}
}
}
return false;
}

/**
* A blind SSL trust manager, for debugging SSL issues
*/
Expand Down
2 changes: 1 addition & 1 deletion src/qz/utils/FileUtilities.java
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ public static String readLocalFile(Path path) throws IOException {
}

public static byte[] readRawFile(String url) throws IOException {
return readFile(new DataInputStream(ConnectionUtilities.getInputStream(url)));
return readFile(new DataInputStream(ConnectionUtilities.getInputStream(url, true)));
}

private static byte[] readFile(DataInputStream in) throws IOException {
Expand Down

0 comments on commit 883094a

Please sign in to comment.