add configurable size limit, allow arbitrary data if content-type is passed
parent
64ff461da5
commit
8b1857bc3b
29
index.js
29
index.js
|
@ -9,6 +9,7 @@ const bodyParser = require('body-parser')
|
||||||
const PORT = Number(process.env.PRINTSERVANT_PORT) || 3199
|
const PORT = Number(process.env.PRINTSERVANT_PORT) || 3199
|
||||||
const CONFIG = JSON.parse(process.env.PRINTSERVANT_CONFIG || 'null')
|
const CONFIG = JSON.parse(process.env.PRINTSERVANT_CONFIG || 'null')
|
||||||
const SECRET = process.env.PRINTSERVANT_SECRET || ''
|
const SECRET = process.env.PRINTSERVANT_SECRET || ''
|
||||||
|
const MAX_SIZE_MB = Number(process.env.PRINTSERVANT_MAX_SIZE_MB) || 10
|
||||||
|
|
||||||
if (!(PORT && CONFIG)) {
|
if (!(PORT && CONFIG)) {
|
||||||
throw new Error("PRINTSERVANT_PORT and PRINTSERVANT_CONFIG environment variables must be set")
|
throw new Error("PRINTSERVANT_PORT and PRINTSERVANT_CONFIG environment variables must be set")
|
||||||
|
@ -59,10 +60,11 @@ app.get('/', (req, res) => {
|
||||||
- Prints IPP attributes
|
- Prints IPP attributes
|
||||||
- GET /printers/:name/jobs
|
- GET /printers/:name/jobs
|
||||||
- Prints IPP jobs
|
- Prints IPP jobs
|
||||||
- POST /print?printer=:name (body: application/pdf or image/png)
|
- POST /print?printer=:name
|
||||||
- Prints a PDF
|
- Prints a PDF
|
||||||
- ?printer= printer name or alias (case insensitive)
|
- ?printer= printer name or alias (case insensitive)
|
||||||
- ?copies= (optional) number of copies (1-10 allowed)
|
- ?copies= (optional) number of copies (1-10 allowed)
|
||||||
|
- Body: PDF or PNG data; *or* any data if Content-Type header is passed
|
||||||
- Response: 200 OK if sent to printer successfully (not necessarily printed), 4xx/5xx otherwise
|
- Response: 200 OK if sent to printer successfully (not necessarily printed), 4xx/5xx otherwise
|
||||||
</pre>`)
|
</pre>`)
|
||||||
})
|
})
|
||||||
|
@ -107,9 +109,9 @@ app.get('/printers/:name/jobs', (req, res) => {
|
||||||
|
|
||||||
// --- Print API ---
|
// --- Print API ---
|
||||||
|
|
||||||
app.post('/print', bodyParser.raw({ type: '*/*', limit: 10_000_000 }), (req, res) => {
|
app.post('/print', bodyParser.raw({ type: '*/*', limit: MAX_SIZE_MB * 1_000_000 }), (req, res) => {
|
||||||
const { body, query } = req
|
const { body, query, headers } = req
|
||||||
console.log("Received print job: ", { body, query })
|
console.log("Received print job: ", { body, query, headers })
|
||||||
|
|
||||||
// validate query params
|
// validate query params
|
||||||
const { printer: printerName, copies: copiesParam, ...otherParams } = query
|
const { printer: printerName, copies: copiesParam, ...otherParams } = query
|
||||||
|
@ -130,15 +132,21 @@ app.post('/print', bodyParser.raw({ type: '*/*', limit: 10_000_000 }), (req, res
|
||||||
|
|
||||||
// validate body
|
// validate body
|
||||||
if (!body || !body.length) {
|
if (!body || !body.length) {
|
||||||
res.status(400).send("No data received, please send a PDF")
|
res.status(400).send("No data received")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const contentType = headers['content-type']
|
||||||
|
const hasValidContentType = contentType
|
||||||
|
&& contentType !== 'application/octet-stream'
|
||||||
|
&& contentType !== 'application/x-www-form-urlencoded'
|
||||||
|
|
||||||
const isPDF = body.subarray(0, 4).toString() === "%PDF"
|
const isPDF = body.subarray(0, 4).toString() === "%PDF"
|
||||||
const isPNG = body.subarray(0, 8).equals(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]))
|
const isPNG = body.subarray(0, 8).equals(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]))
|
||||||
|
|
||||||
if (!isPDF && !isPNG) {
|
const hasValidFormat = isPDF || isPNG || hasValidContentType
|
||||||
res.status(415).send("Unsupported media type, only PDF and PNG are supported")
|
if (!hasValidFormat) {
|
||||||
|
res.status(415).send("Unknown media type. Pass a PDF or PNG file, or set Content-Type header to print something else.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +160,12 @@ app.post('/print', bodyParser.raw({ type: '*/*', limit: 10_000_000 }), (req, res
|
||||||
// send print job
|
// send print job
|
||||||
const msg = {
|
const msg = {
|
||||||
"operation-attributes-tag": {
|
"operation-attributes-tag": {
|
||||||
"document-format": isPNG ? "image/png" : "application/pdf",
|
"document-format": (() => {
|
||||||
|
if (isPDF) return "application/pdf"
|
||||||
|
if (isPNG) return "image/png"
|
||||||
|
if (contentType) return contentType
|
||||||
|
throw new Error('unreachable')
|
||||||
|
})(),
|
||||||
},
|
},
|
||||||
"job-attributes-tag": {
|
"job-attributes-tag": {
|
||||||
"copies": copies,
|
"copies": copies,
|
||||||
|
|
Loading…
Reference in New Issue