diff --git a/ass.js b/ass.js index 7202a43..9351565 100755 --- a/ass.js +++ b/ass.js @@ -27,7 +27,6 @@ log.blank().info(`* ${ASS_NAME} v${ASS_VERSION} *`).blank(); // Set up premium frontend const FRONTEND_NAME = 'ass-x'; // <-- Change this to use a custom frontend const ASS_PREMIUM = fs.existsSync(`./${FRONTEND_NAME}/package.json`) ? (require('submodule'), require(`./${FRONTEND_NAME}`)) : { enabled: false }; -log.info('Frontend: ', ASS_PREMIUM.enabled ? ASS_PREMIUM.brand : '', ASS_PREMIUM.enabled && ASS_PREMIUM.index ? 'with index' : null); //#region Variables, module setup const app = express(); @@ -39,7 +38,6 @@ const ROUTERS = { // Read users and data const users = require('./auth'); const data = require('./data'); -log.info('StorageEngine: ', data.name, data.type); //#endregion // Create thumbnails directory @@ -55,6 +53,7 @@ app.set('view engine', 'pug'); // Express logger middleware app.use(log.express(true)); +app.use((_req, _res, next) => log.epoch().callback(() => next())); // Helmet security middleware app.use(helmet.noSniff()); @@ -86,16 +85,11 @@ ASS_PREMIUM.enabled && app.use(ASS_PREMIUM.endpoint, ASS_PREMIUM.router); // ski // '/:resouceId' always needs to be LAST since it's a catch-all route app.use('/:resourceId', (req, _, next) => (req.resourceId = req.params.resourceId, next()), ROUTERS.resource); // skipcq: JS-0086, JS-0090 -// Error handler -app.use(([err, , res,]) => { - log.error(err); - res.sendStatus(CODE_INTERNAL_SERVER_ERROR); -}); - // Host the server log .info('Users', `${Object.keys(users).length}`) .info('Files', `${data.size}`) + .info('StorageEngine', data.name, data.type) .info('Frontend', ASS_PREMIUM.enabled ? ASS_PREMIUM.brand : 'disabled', `${ASS_PREMIUM.enabled ? `${getTrueHttp()}${getTrueDomain()}${ASS_PREMIUM.endpoint}` : ''}`) .info('Index redirect', ASS_PREMIUM.enabled && ASS_PREMIUM.index ? `enable` : 'disabled') .blank() diff --git a/checkEngine.js b/checkEngine.js index fd87cff..7cceeb1 100644 --- a/checkEngine.js +++ b/checkEngine.js @@ -18,5 +18,5 @@ function doCheck() { if (require.main !== module) module.exports = doCheck; else doCheck() - .then((result) => logger.success(result)) + .then((result) => logger.comment(`Wanted: ${ENGINES.node} (npm ${ENGINES.npm})`).node().success(result)) .catch((err) => logger.error(err) && process.exit(1)); diff --git a/hash.js b/hash.js index c71529b..3610048 100644 --- a/hash.js +++ b/hash.js @@ -1,6 +1,7 @@ const fs = require('fs-extra'); const crypto = require('crypto'); -const toArray = require('stream-to-array') +const toArray = require('stream-to-array'); +const { log } = require('./utils'); /** * Generates a SHA1 hash for the provided file @@ -12,5 +13,5 @@ module.exports = (file) => toArray((fs.createReadStream(file.path))) .then((parts) => Buffer.concat(parts.map((part) => (Buffer.isBuffer(part) ? part : Buffer.from(part))))) .then((buf) => crypto.createHash('sha1').update(buf).digest('hex')) // skipcq: JS-D003 - .then(resolve) + .then((hash) => log.debug(`Hash for ${file.originalname}`, hash, 'SHA1, hex').callback(resolve, hash)) .catch(reject)); diff --git a/routers/upload.js b/routers/upload.js index 6f58d59..2327a39 100644 --- a/routers/upload.js +++ b/routers/upload.js @@ -21,6 +21,7 @@ const router = express.Router(); // Block unauthorized requests and attempt token sanitization router.post('/', (req, res, next) => { + log.express().Header(req, 'authorization'); req.headers.authorization = req.headers.authorization || ''; req.token = req.headers.authorization.replace(/[^\da-z]/gi, ''); // Strip anything that isn't a digit or ASCII letter !verify(req, users) ? res.sendStatus(CODE_UNAUTHORIZED) : next(); // skipcq: JS-0093 @@ -71,12 +72,14 @@ router.post('/', (req, res, next) => { // Send the response res.type('json').send({ resource: resourceUrl, thumbnail: thumbnailUrl, delete: deleteUrl }) .on('finish', () => { + log.debug('Upload response sent'); // After we have sent the user the response, also send a Webhook to Discord (if headers are present) if (req.headers['x-ass-webhook-client'] && req.headers['x-ass-webhook-token']) { + const client = req.headers['x-ass-webhook-client'] // Build the webhook client & embed - const whc = new WebhookClient(req.headers['x-ass-webhook-client'], req.headers['x-ass-webhook-token']); + const whc = new WebhookClient(client, req.headers['x-ass-webhook-token']); const embed = new MessageEmbed() .setTitle(logInfo) .setURL(resourceUrl) @@ -86,11 +89,12 @@ router.post('/', (req, res, next) => { .setTimestamp(req.file.timestamp); // Send the embed to the webhook, then delete the client after to free resources + log.debug('Sending webhook to', ` to ${client}`); whc.send(null, { username: req.headers['x-ass-webhook-username'] || 'ass', avatarURL: req.headers['x-ass-webhook-avatar'] || ASS_LOGO, embeds: [embed] - }).then(() => whc.destroy()); + }).then(() => log.debug('Webhook sent').callback(() => whc.destroy())); } // Also update the users upload count @@ -102,7 +106,9 @@ router.post('/', (req, res, next) => { users[req.token] = { username, count: 0 }; } users[req.token].count += 1; - fs.writeJsonSync(path('auth.json'), { users }, { spaces: 4 }) + fs.writeJsonSync(path('auth.json'), { users }, { spaces: 4 }); + + log.debug('Upload request flow completed', '').epoch(); }); }).catch(next); }); diff --git a/storage.js b/storage.js index 069233d..dbd81b5 100644 --- a/storage.js +++ b/storage.js @@ -7,7 +7,7 @@ const multer = require('multer'); const Thumbnail = require('./thumbnails'); const Vibrant = require('./vibrant'); const Hash = require('./hash'); -const { getDatedDirname, sanitize, generateId } = require('./utils'); +const { getDatedDirname, sanitize, generateId, formatBytes, log } = require('./utils'); const { s3enabled, s3endpoint, s3bucket, s3accessKey, s3secretKey, saveAsOriginal, maxUploadSize, mediaStrict } = require('./config.json'); const { CODE_UNSUPPORTED_MEDIA_TYPE } = require('./MagicNumbers.json'); @@ -20,10 +20,11 @@ const s3 = new aws.S3({ }); function saveFile(req) { + log.debug('Saving temp file to disk', req.file.path, formatBytes(req.file.size)); return new Promise((resolve, reject) => fs.ensureDir(getDatedDirname()) .then(() => fs.createWriteStream(req.file.path.concat('.temp'))) - .then((stream) => req.file.stream.pipe(stream).on('finish', resolve).on('error', reject)) + .then((stream) => req.file.stream.pipe(stream).on('finish', log.debug('Temp file', 'saved').callback(resolve)).on('error', reject)) .catch(reject)); } @@ -54,6 +55,7 @@ function processUploaded(req, res, next) { // Block the resource if the mimetype is not an image or video if (mediaStrict && !ALLOWED_MIMETYPES.test(req.file.mimetype)) { fs.remove(req.file.path.concat('.temp')); + log.warn('Upload blocked', req.file.originalname, req.file.mimetype).warn('Strict media mode', 'only images, videos, & audio are file permitted'); return res.sendStatus(CODE_UNSUPPORTED_MEDIA_TYPE); } @@ -76,6 +78,7 @@ function processUploaded(req, res, next) { req.file.sha1 = sha1 // skipcq: JS-0090 )) + .then(() => log.debug('Saving file', req.file.originalname, s3enabled ? 'in S3' : 'on disk')) .then(() => // skipcq: JS-0229 new Promise((resolve, reject) => s3enabled @@ -95,7 +98,9 @@ function processUploaded(req, res, next) { .then(resolve) .catch(reject) )) + .then(() => log.debug('File saved', req.file.originalname, s3enabled ? 'in S3' : 'on disk')) .then(() => fs.remove(req.file.path)) + .then(() => log.debug('Temp file', 'deleted')) .then(() => !s3enabled && (req.file.path = getLocalFilename(req))) // skipcq: JS-0090 .then(() => delete req.file.stream) .then(() => next()) diff --git a/utils.js b/utils.js index 3317ca0..35dcb31 100755 --- a/utils.js +++ b/utils.js @@ -76,6 +76,7 @@ function getDatedDirname() { // Set up pathing & the logger const path = (...paths) => Path.join(__dirname, ...paths); const logger = new TLog({ + level: process.env.NODE_ENV === 'production' ? 'info' : 'debug', plugins: { express: true },