From c137dc7c510745a24b301f90f348e2a183b70276 Mon Sep 17 00:00:00 2001 From: Olivier Legendre Date: Fri, 1 Aug 2025 19:59:04 -0400 Subject: [PATCH 1/3] Update uploads directory handling to check existence before deletion or recreation --- index.js | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/index.js b/index.js index 8621d10..51f29cb 100644 --- a/index.js +++ b/index.js @@ -31,6 +31,8 @@ const keyChars = "23456789ACDEFGHJKLMNPRSTUVWXYZ" const keyLength = 4 + + function doTransliterate(filename) { let name = filename.split(".") const ext = "." + name.splice(-1).join(".") @@ -576,17 +578,29 @@ app.use(router.routes()) app.use(router.allowedMethods()) -fs.rm('uploads', {recursive: true}, (err) => { - if (err) throw err - mkdirp('uploads').then (() => { - // app.listen(port) - const fn = app.callback() - const server = http.createServer(fn) - server.on('checkContinue', (req, res) => { - console.log("check continue!") - fn(req, res) +// First check if the uploads directory exists +fs.access('uploads', (accessErr) => { + const setupServer = () => { + mkdirp('uploads').then(() => { + const fn = app.callback() + const server = http.createServer(fn) + server.on('checkContinue', (req, res) => { + console.log("check continue!") + fn(req, res) + }) + server.listen(port) + console.log('server is listening on port ' + port) }) - server.listen(port) - console.log('server is listening on port ' + port) - }) + } + + if (accessErr) { + // Directory doesn't exist, just create it + setupServer() + } else { + // Directory exists, remove it first then recreate + fs.rm('uploads', { recursive: true }, (err) => { + if (err) throw err + setupServer() + }) + } }) From 948b656a431f3eff21c2b96693752685fc2f4607 Mon Sep 17 00:00:00 2001 From: Olivier Legendre Date: Fri, 1 Aug 2025 21:21:14 -0400 Subject: [PATCH 2/3] fix the "invalid type" error --- index.js | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/index.js b/index.js index 51f29cb..4e11dac 100644 --- a/index.js +++ b/index.js @@ -21,10 +21,11 @@ const expireDelay = 30 // 30 seconds const maxExpireDuration = 1 * 60 * 60 // 1 hour const maxFileSize = 1024 * 1024 * 800 // 800 MB -const TYPE_EPUB = 'application/epub+zip' +const TYPE_EPUB = 'application/epub+zip' // the official IANA standard + const TYPE_MOBI = 'application/x-mobipocket-ebook' -const allowedTypes = [TYPE_EPUB, TYPE_MOBI, 'application/pdf', 'application/vnd.comicbook+zip', 'application/vnd.comicbook-rar', 'text/html', 'text/plain', 'application/zip', 'application/x-rar-compressed'] +const allowedTypes = [TYPE_EPUB, TYPE_MOBI, 'application/pdf', 'application/vnd.comicbook+zip', 'application/vnd.comicbook-rar', 'text/html', 'text/plain', 'application/zip', 'application/x-rar-compressed', 'application/epub'] const allowedExtensions = ['epub', 'mobi', 'pdf', 'cbz', 'cbr', 'html', 'txt'] const keyChars = "23456789ACDEFGHJKLMNPRSTUVWXYZ" @@ -122,7 +123,17 @@ const upload = multer({ cb("Unknown key " + key, false) return } - if ((!allowedTypes.includes(file.mimetype) && file.mimetype != "application/octet-stream") || !allowedExtensions.includes(extname(file.originalname.toLowerCase()).substring(1))) { + + // Handle application/epub mimetype + if (file.mimetype === "application/epub") { + file.mimetype = TYPE_EPUB + } + + const fileExtension = extname(file.originalname.toLowerCase()).substring(1) + const isValidMimetype = allowedTypes.includes(file.mimetype) || file.mimetype === "application/octet-stream" + const isValidExtension = allowedExtensions.includes(fileExtension) + + if (!isValidMimetype || !isValidExtension) { console.error('FileFilter: File is of an invalid type ', file) cb("Invalid filetype: " + JSON.stringify(file), false) return @@ -283,18 +294,37 @@ router.post('/upload', async (ctx, next) => { } let mimetype = ctx.request.file.mimetype + console.log('Second validation - Original mimetype:', mimetype) const type = await FileType.fromFile(ctx.request.file.path) + console.log('Second validation - FileType detection result:', type) if (mimetype == "application/octet-stream" && type) { mimetype = type.mime + console.log('Second validation - Updated mimetype from octet-stream:', mimetype) } if (mimetype == "application/epub") { mimetype = TYPE_EPUB + console.log('Second validation - Converted application/epub to:', TYPE_EPUB) } - if ((!type || !allowedTypes.includes(type.mime)) && !allowedTypes.includes(mimetype)) { + // Convert application/epub to application/epub+zip for consistency + if (type && type.mime === "application/epub") { + type.mime = TYPE_EPUB + console.log('Second validation - Converted type.mime from application/epub to:', TYPE_EPUB) + } + + const isValidTypeMime = type && allowedTypes.includes(type.mime) + const isValidMimetype = allowedTypes.includes(mimetype) + + console.log('Second validation - Is valid type.mime:', isValidTypeMime) + console.log('Second validation - Is valid mimetype:', isValidMimetype) + console.log('Second validation - Final type.mime:', type ? type.mime : 'null') + console.log('Second validation - Final mimetype:', mimetype) + + if (!isValidTypeMime && !isValidMimetype) { + console.error('Second validation - Invalid file type detected') flash(ctx, { message: 'Uploaded file is of an invalid type: ' + ctx.request.file.originalname + ' (' + (type? type.mime : 'unknown mimetype') + ')', success: false, @@ -567,7 +597,7 @@ router.get('/receive', async ctx => { router.get('/', async ctx => { const agent = ctx.get('user-agent') console.log(ctx.ip, agent) - await sendfile(ctx, agent.includes('Kobo') || agent.includes('Kindle') || agent.toLowerCase().includes('tolino') || agent.includes('eReader') /*"eReader" is on Tolino*/ ? 'static/download.html' : 'static/upload.html') + await sendfile(ctx, agent.includes('Kobo') || agent.includes('Kindle') || agent.includes('Linux') || agent.toLowerCase().includes('tolino') || agent.includes('eReader') /*"eReader" is on Tolino*/ ? 'static/download.html' : 'static/upload.html') }) router.get('/:filename', downloadFile) @@ -577,8 +607,6 @@ app.use(serve("static")) app.use(router.routes()) app.use(router.allowedMethods()) - -// First check if the uploads directory exists fs.access('uploads', (accessErr) => { const setupServer = () => { mkdirp('uploads').then(() => { From bc5c8c64dc4b4fe2e906b3dba7946fdc222698ce Mon Sep 17 00:00:00 2001 From: Olivier Legendre Date: Fri, 1 Aug 2025 21:22:03 -0400 Subject: [PATCH 3/3] remove testing data --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 4e11dac..dfabefa 100644 --- a/index.js +++ b/index.js @@ -597,7 +597,7 @@ router.get('/receive', async ctx => { router.get('/', async ctx => { const agent = ctx.get('user-agent') console.log(ctx.ip, agent) - await sendfile(ctx, agent.includes('Kobo') || agent.includes('Kindle') || agent.includes('Linux') || agent.toLowerCase().includes('tolino') || agent.includes('eReader') /*"eReader" is on Tolino*/ ? 'static/download.html' : 'static/upload.html') + await sendfile(ctx, agent.includes('Kobo') || agent.includes('Kindle') || agent.toLowerCase().includes('tolino') || agent.includes('eReader') /*"eReader" is on Tolino*/ ? 'static/download.html' : 'static/upload.html') }) router.get('/:filename', downloadFile)