const crypto = require('crypto'); const storage = require('../storage'); const config = require('../config'); const mozlog = require('../log'); const log = mozlog('send.upload'); const validateIV = route_id => { return route_id.match(/^[0-9a-fA-F]{24}$/) !== null; }; module.exports = function(req, res) { const newId = crypto.randomBytes(5).toString('hex'); let meta; try { meta = JSON.parse(req.header('X-File-Metadata')); } catch (e) { res.sendStatus(400); return; } if ( !meta.hasOwnProperty('id') || !meta.hasOwnProperty('filename') || !validateIV(meta.id) ) { res.sendStatus(404); return; } meta.delete = crypto.randomBytes(10).toString('hex'); req.pipe(req.busboy); req.busboy.on( 'file', async (fieldname, file, filename, encoding, mimeType) => { try { meta.mimeType = mimeType || 'application/octet-stream'; await storage.set(newId, file, filename, meta); const protocol = config.env === 'production' ? 'https' : req.protocol; const url = `${protocol}://${req.get('host')}/download/${newId}/`; res.json({ url, delete: meta.delete, id: newId }); } catch (e) { log.error('upload', e); if (e.message === 'limit') { return res.sendStatus(413); } res.sendStatus(500); } } ); req.on('close', async err => { try { await storage.forceDelete(newId); } catch (e) { log.info('DeleteError:', newId); } }); };