Skip to content

Commit 35c8306

Browse files
committed
Disable file writing by default
Per #1210, #730
1 parent 3c0ab94 commit 35c8306

File tree

9 files changed

+59
-54
lines changed

9 files changed

+59
-54
lines changed

js/qz-tray.js

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,14 +1074,6 @@ var qz = (function() {
10741074
if (typeof newPrinter === 'string') {
10751075
newPrinter = { name: newPrinter };
10761076
}
1077-
1078-
if(newPrinter && newPrinter.file) {
1079-
// TODO: Warn for UNC paths too https://github.com/qzind/tray/issues/730
1080-
if(newPrinter.file.indexOf("\\\\") != 0) {
1081-
_qz.log.warn("Printing to file is deprecated. See https://github.com/qzind/tray/issues/730");
1082-
}
1083-
}
1084-
10851077
this.printer = newPrinter;
10861078
};
10871079

sample.html

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,6 @@ <h3 class="panel-title">Printer</h3>
121121
<div class="form-group">
122122
<div class="btn-group" role="group">
123123
<button type="button" class="btn btn-default btn-sm" onclick="setPrinter($('#printerSearch').val());">Set To Search</button>
124-
<button type="button" class="btn btn-default btn-sm" data-toggle="modal" data-target="#askFileModal">Set To File</button>
125124
<button type="button" class="btn btn-default btn-sm" data-toggle="modal" data-target="#askHostModal">Set To Host</button>
126125
</div>
127126
<button type="button" class="btn btn-warning btn-sm" onclick="clearQueue($('#printerSearch').val());">Clear Queue</button>
@@ -1354,27 +1353,6 @@ <h4 class="panel-title">Options</h4>
13541353
</div>
13551354
</div>
13561355

1357-
1358-
<div class="modal fade" id="askFileModal" role="dialog">
1359-
<div class="modal-dialog modal-sm" role="document">
1360-
<div class="modal-content">
1361-
<div class="modal-body">
1362-
<div class="form-group">
1363-
<label for="askFile">File:</label>
1364-
<input type="text" id="askFile" class="form-control" value="C:\tmp\example-file.txt" />
1365-
<hr />
1366-
<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
1367-
information please see <a href="https://github.com/qzind/tray/issues/730">issue&nbsp;<code>#730</code>.</a></p>
1368-
</div>
1369-
</div>
1370-
<div class="modal-footer">
1371-
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
1372-
<button type="button" class="btn btn-primary" onclick="setPrintFile();">Set</button>
1373-
</div>
1374-
</div>
1375-
</div>
1376-
</div>
1377-
13781356
<div class="modal fade" id="askHostModal" role="dialog">
13791357
<div class="modal-dialog modal-sm" role="document">
13801358
<div class="modal-content">
@@ -2982,13 +2960,6 @@ <h4 class="panel-title">Options</h4>
29822960
}).catch(displayError);
29832961
}
29842962

2985-
$("#askFileModal").on("shown.bs.modal", function() {
2986-
$("#askFile").focus().select();
2987-
});
2988-
$("#askHostModal").on("shown.bs.modal", function() {
2989-
$("#askHost").focus().select();
2990-
});
2991-
29922963
//make dirty when changed
29932964
$("input").add("select").on('change', function() {
29942965
$(this).addClass("dirty");
@@ -3375,11 +3346,6 @@ <h4 class="panel-title">Options</h4>
33753346
return options;
33763347
}
33773348

3378-
function setPrintFile() {
3379-
setPrinter({ file: $("#askFile").val() });
3380-
$("#askFileModal").modal('hide');
3381-
}
3382-
33833349
function setPrintHost() {
33843350
setPrinter({ host: $("#askHost").val(), port: $("#askPort").val() });
33853351
$("#askHostModal").modal('hide');

src/qz/auth/CRL.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public static CRL getInstance() {
3838
public void run() {
3939
log.info("Loading CRL from {}", CRL_URL);
4040

41-
try(BufferedReader br = new BufferedReader(new InputStreamReader(ConnectionUtilities.getInputStream(CRL_URL)))) {
41+
try(BufferedReader br = new BufferedReader(new InputStreamReader(ConnectionUtilities.getInputStream(CRL_URL, false)))) {
4242
String line;
4343
while((line = br.readLine()) != null) {
4444
//Ignore empty and commented lines

src/qz/printer/action/PrintImage.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public void parseData(JSONArray printData, PrintOptions options) throws JSONExce
8282
case PLAIN:
8383
// There's really no such thing as a 'PLAIN' image, assume it's a URL
8484
case FILE:
85-
bi = ImageIO.read(ConnectionUtilities.getInputStream(data.getString("data")));
85+
bi = ImageIO.read(ConnectionUtilities.getInputStream(data.getString("data"), true));
8686
break;
8787
default:
8888
bi = ImageIO.read(new ByteArrayInputStream(flavor.read(data.getString("data"))));

src/qz/printer/action/PrintPDF.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ public void parseData(JSONArray printData, PrintOptions options) throws JSONExce
118118
case PLAIN:
119119
// There's really no such thing as a 'PLAIN' PDF, assume it's a URL
120120
case FILE:
121-
doc = PDDocument.load(ConnectionUtilities.getInputStream(data.getString("data")));
121+
doc = PDDocument.load(ConnectionUtilities.getInputStream(data.getString("data"), true));
122122
break;
123123
default:
124124
doc = PDDocument.load(new ByteArrayInputStream(flavor.read(data.getString("data"))));

src/qz/printer/action/PrintRaw.java

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
import com.ibm.icu.text.ArabicShapingException;
1313
import org.apache.commons.lang3.StringUtils;
14-
import org.apache.commons.ssl.Base64;
1514
import org.apache.pdfbox.pdmodel.PDDocument;
1615
import org.apache.pdfbox.pdmodel.common.PDRectangle;
1716
import org.apache.pdfbox.rendering.PDFRenderer;
@@ -175,7 +174,7 @@ private ImageWrapper getImageWrapper(String data, JSONObject opt, PrintingUtilit
175174
case PLAIN:
176175
// There's really no such thing as a 'PLAIN' image, assume it's a URL
177176
case FILE:
178-
bi = ImageIO.read(ConnectionUtilities.getInputStream(data));
177+
bi = ImageIO.read(ConnectionUtilities.getInputStream(data, true));
179178
break;
180179
default:
181180
bi = ImageIO.read(new ByteArrayInputStream(seekConversion(flavor.read(data), rawOpts)));
@@ -191,7 +190,7 @@ private ImageWrapper getPdfWrapper(String data, JSONObject opt, PrintingUtilitie
191190
case PLAIN:
192191
// There's really no such thing as a 'PLAIN' PDF, assume it's a URL
193192
case FILE:
194-
doc = PDDocument.load(ConnectionUtilities.getInputStream(data));
193+
doc = PDDocument.load(ConnectionUtilities.getInputStream(data, true));
195194
break;
196195
default:
197196
doc = PDDocument.load(new ByteArrayInputStream(seekConversion(flavor.read(data), rawOpts)));
@@ -329,7 +328,7 @@ public void print(PrintOutput output, PrintOptions options) throws PrintExceptio
329328
if (output.isSetHost()) {
330329
printToHost(output.getHost(), output.getPort(), bab.getByteArray());
331330
} else if (output.isSetFile()) {
332-
printToFile(output.getFile(), bab.getByteArray());
331+
printToFile(output.getFile(), bab.getByteArray(), true);
333332
} else {
334333
if (rawOpts.isForceRaw()) {
335334
if(tempFiles == null) {
@@ -339,7 +338,7 @@ public void print(PrintOutput output, PrintOptions options) throws PrintExceptio
339338
if(tempFiles.size() <= j) {
340339
tempFile = File.createTempFile("qz_raw_", null);
341340
tempFiles.add(j, tempFile);
342-
printToFile(tempFile, bab.getByteArray());
341+
printToFile(tempFile, bab.getByteArray(), false);
343342
} else {
344343
tempFile = tempFiles.get(j);
345344
}
@@ -401,7 +400,15 @@ private void printToHost(String host, int port, byte[] cmds) throws IOException
401400
*
402401
* @param file File to be written
403402
*/
404-
private void printToFile(File file, byte[] cmds) throws IOException {
403+
private void printToFile(File file, byte[] cmds, boolean locationRestricted) throws IOException {
404+
if(file == null) throw new IOException("No file specified");
405+
406+
if(!isAllowed(file)) {
407+
log.error("Printing to file '{}' is not permitted. Configure property '{}' or '{}' to modify this behavior.",
408+
file, ArgValue.SECURITY_PRINT_UNC.getMatch(), ArgValue.SECURITY_PRINT_FILE.getMatch());
409+
throw new IOException(String.format("Printing to file '%s' is not permitted", file));
410+
}
411+
405412
log.debug("Printing to file: {}", file.getName());
406413

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

420+
private boolean isAllowed(File file) {
421+
return file.getPath().startsWith("\\\\") ?
422+
// UNC Path
423+
PrefsSearch.getBoolean(ArgValue.SECURITY_PRINT_UNC) :
424+
// Regular file
425+
PrefsSearch.getBoolean(ArgValue.SECURITY_PRINT_FILE);
426+
}
427+
413428
/**
414429
* Constructs a {@code SimpleDoc} with the {@code commands} byte array.
415430
*/

src/qz/utils/ArgValue.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ public enum ArgValue {
6969
"security.file.enabled"),
7070
SECURITY_FILE_STRICT(PREFERENCES, "Enable/disable signing requirements for File Communications features", null, true,
7171
"security.file.strict"),
72+
SECURITY_FILE_PROTOCOLS(PREFERENCES, "URL protocols allowed for print, serial, hid, etc", null, "http,https",
73+
"security.file.protocols"),
74+
SECURITY_PRINT_UNC(PREFERENCES, "Enable/disable printing directly to UNC paths", null, false,
75+
"security.print.unc"),
76+
SECURITY_PRINT_FILE(PREFERENCES, "Enable/disable printing directly to file paths", null, false,
77+
"security.print.file"),
7278
LOG_DISABLE(PREFERENCES, "Disable/enable logging features", null, false,
7379
"log.disable"),
7480
LOG_ROTATE(PREFERENCES, "Number of log files to retain when the size fills up", null, 5,

src/qz/utils/ConnectionUtilities.java

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,17 @@ public final class ConnectionUtilities {
3939
*
4040
* @param urlString an absolute URL giving location of resource to read.
4141
*/
42-
public static InputStream getInputStream(String urlString) throws IOException {
42+
public static InputStream getInputStream(String urlString, boolean protocolRestricted) throws IOException {
4343
try {
44-
URLConnection urlConn = new URL(urlString).openConnection();
44+
URL url = new URL(urlString);
45+
if(protocolRestricted) {
46+
String allowed = PrefsSearch.getString(ArgValue.SECURITY_FILE_PROTOCOLS);
47+
if(!isAllowed(allowed, url)) {
48+
log.error("URL '{}' is not a valid http or https location. Configure property '{}' to modify this behavior.", url, ArgValue.SECURITY_FILE_PROTOCOLS.getMatch());
49+
throw new IOException(String.format("URL '%s' is not a valid [%s] location", url, allowed));
50+
}
51+
}
52+
URLConnection urlConn = url.openConnection();
4553
for( String key : getRequestProperties().keySet()) {
4654
urlConn.setRequestProperty(key, requestProps.get(key));
4755
}
@@ -54,6 +62,24 @@ public static InputStream getInputStream(String urlString) throws IOException {
5462
}
5563
}
5664

65+
private static boolean isAllowed(String allowed, URL url) {
66+
if(url == null) return false;
67+
String urlProtocol = url.getProtocol();
68+
if(urlProtocol == null || urlProtocol.trim().isEmpty()) return false;
69+
allowed = ArgValue.SECURITY_FILE_PROTOCOLS.getDefaultVal() +
70+
(allowed == null || allowed.trim().isEmpty() ? "" : "," + allowed);
71+
String[] protocols = allowed.split(",");
72+
// Loop over http, https, etc
73+
for(String protocol : protocols) {
74+
if (url != null) {
75+
if(urlProtocol.trim().equalsIgnoreCase(protocol.trim())) {
76+
return true;
77+
}
78+
}
79+
}
80+
return false;
81+
}
82+
5783
/**
5884
* A blind SSL trust manager, for debugging SSL issues
5985
*/

src/qz/utils/FileUtilities.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,7 @@ public static String readLocalFile(Path path) throws IOException {
592592
}
593593

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

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

0 commit comments

Comments
 (0)