diff --git a/MagicNumbers.json b/MagicNumbers.json new file mode 100644 index 0000000..7a40859 --- /dev/null +++ b/MagicNumbers.json @@ -0,0 +1,9 @@ +{ + "HTTP": 80, + "HTTPS": 443, + "CODE_NO_CONTENT": 204, + "CODE_BAD_REQUEST": 400, + "CODE_UNAUTHORIZED": 401, + "CODE_NOT_FOUND": 404, + "KILOBYTES": 1024 +} \ No newline at end of file diff --git a/ass.js b/ass.js index 9a2add0..9d0c41e 100755 --- a/ass.js +++ b/ass.js @@ -23,9 +23,9 @@ const OpenGraph = require('./ogp'); const Thumbnail = require('./thumbnails'); const Vibrant = require('./vibrant'); const Hash = require('./hash'); -const Path = require('path'); const { uploadLocal, uploadS3, deleteS3 } = require('./storage'); const { path, saveData, log, verify, getTrueHttp, getTrueDomain, renameFile, generateToken, generateId, formatBytes, arrayEquals, getS3url, downloadTempS3, sanitize } = require('./utils'); +const { CODE_NO_CONTENT, CODE_BAD_REQUEST, CODE_UNAUTHORIZED, CODE_NOT_FOUND } = require('./MagicNumbers.json'); //#endregion //#region Variables, module setup @@ -74,12 +74,12 @@ function startup() { // Rate limit app.use(rateLimit({ - windowMs: 1000 * 60, // 60 seconds - max: 90 // Limit each IP to 30 requests per windowMs + windowMs: 1000 * 60, // 60 seconds // skipcq: JS-0074 + max: 90 // Limit each IP to 30 requests per windowMs // skipcq: JS-0074 })); // Don't process favicon requests - app.use((req, res, next) => (req.url.includes('favicon.ico') ? res.sendStatus(204) : next())); + app.use((req, res, next) => (req.url.includes('favicon.ico') ? res.sendStatus(CODE_NO_CONTENT) : next())); // Index app.get('/', (_req, res) => fs.readFile(path('README.md')).then((bytes) => bytes.toString()).then(marked).then((d) => res.render('index', { data: d }))); @@ -87,12 +87,12 @@ function startup() { // Block unauthorized requests and attempt token sanitization app.post('/', (req, res, next) => { req.token = req.headers.authorization.replace(/[^\da-z]/gi, ''); - !verify(req, users) ? res.sendStatus(401) : next(); // skipcq: JS-0093 + !verify(req, users) ? res.sendStatus(CODE_UNAUTHORIZED) : next(); // skipcq: JS-0093 }); // Generate ID's to use for other functions - app.post('/', (req, _res, next) => (req.randomId = generateId('random', 32, null, null), next())); // skipcq: JS-0086, JS-0090 - app.post('/', (req, _res, next) => (req.deleteId = generateId('random', 32, null, null), next())); // skipcq: JS-0086, JS-0090 + app.post('/', (req, _res, next) => (req.randomId = generateId('random', 32, null, null), next())); // skipcq: JS-0074, JS-0086, JS-0090 + app.post('/', (req, _res, next) => (req.deleteId = generateId('random', 32, null, null), next())); // skipcq: JS-0074, JS-0086, JS-0090 // Upload file (local & S3) // skipcq: JS-0093 s3enabled @@ -189,7 +189,7 @@ function startup() { // Also update the users upload count if (!users[req.token]) { - const generateUsername = () => generateId('random', 20, null); + const generateUsername = () => generateId('random', 20, null); // skipcq: JS-0074 let username = generateUsername(); while (Object.values(users).findIndex((user) => user.username === username) !== -1) // skipcq: JS-0073 username = generateUsername(); @@ -206,7 +206,7 @@ function startup() { req.ass = { resourceId: escape(req.params.resourceId).split('.')[0] }; // If the ID is invalid, return 404. Otherwise, continue normally // skipcq: JS-0093 - (!req.ass.resourceId || !data[req.ass.resourceId]) ? res.sendStatus(404) : next(); + (!req.ass.resourceId || !data[req.ass.resourceId]) ? res.sendStatus(CODE_NOT_FOUND) : next(); }); // View file @@ -277,10 +277,10 @@ function startup() { const fileData = data[resourceId]; // If the delete ID doesn't match, don't delete the file - if (deleteId !== fileData.deleteId) return res.sendStatus(401); + if (deleteId !== fileData.deleteId) return res.sendStatus(CODE_UNAUTHORIZED); // If the ID is invalid, return 400 because we are unable to process the resource - if (!resourceId || !fileData) return res.sendStatus(400); + if (!resourceId || !fileData) return res.sendStatus(CODE_BAD_REQUEST); log(`Deleted: ${fileData.originalname} (${fileData.mimetype})`); diff --git a/generators/token.js b/generators/token.js index 1d567f0..78af767 100644 --- a/generators/token.js +++ b/generators/token.js @@ -15,7 +15,7 @@ if (require.main === module) { fs.readJson(authPath) .then((auth) => { // Generate the user - const username = process.argv[2] ? process.argv[2].replace(/[^\da-z_]/gi, '').substring(0, MAX_USERNAME) : randomGen({ length: 20 }); + const username = process.argv[2] ? process.argv[2].replace(/[^\da-z_]/gi, '').substring(0, MAX_USERNAME) : randomGen({ length: 20 }); // skipcq: JS-0074 if (!auth.users) auth.users = {}; if (Object.values(auth.users).findIndex((user) => user.username === username) !== -1) { console.log('Username already exists!'); diff --git a/storage.js b/storage.js index 522a6b7..558ea4c 100644 --- a/storage.js +++ b/storage.js @@ -34,7 +34,7 @@ const uploadLocal = multer({ const [month, , year] = new Date().toLocaleDateString('en-US').split('/'); // Add 0 before single digit months (6 turns into 06) - const folder = `${diskFilePath}/${year}-${`0${month}`.slice(-2)}`; + const folder = `${diskFilePath}/${year}-${`0${month}`.slice(-2)}`; // skipcq: JS-0074 // Create folder if it doesn't exist fs.ensureDirSync(folder); diff --git a/utils.js b/utils.js index 316caee..617e9a1 100755 --- a/utils.js +++ b/utils.js @@ -6,16 +6,19 @@ const token = require('./generators/token'); const zwsGen = require('./generators/zws'); const randomGen = require('./generators/random'); const gfyGen = require('./generators/gfycat'); -const { useSsl, port, isProxied, s3bucket, s3endpoint } = require('./config.json'); +const { useSsl, port, domain, isProxied, s3bucket, s3endpoint } = require('./config.json'); +const { HTTP, HTTPS, KILOBYTES } = require('./MagicNumbers.json'); -function getS3url(s3key, type) { - return `https://${s3bucket}.${s3endpoint}/${s3key}${getSafeExt(type)}`; -} +const path = (...paths) => Path.join(__dirname, ...paths); function getSafeExt(type) { return type.includes('video') ? '.mp4' : type.includes('gif') ? '.gif' : ''; } +function getS3url(s3key, type) { + return `https://${s3bucket}.${s3endpoint}/${s3key}${getSafeExt(type)}`; +} + const idModes = { zws: 'zws', // Zero-width spaces (see: https://zws.im/) og: 'original', // Use original uploaded filename @@ -29,12 +32,12 @@ GENERATORS.set(idModes.r, randomGen); GENERATORS.set(idModes.gfy, gfyGen); module.exports = { + path, log: console.log, - path: (...paths) => Path.join(__dirname, ...paths), saveData: (data) => fs.writeJsonSync(Path.join(__dirname, 'data.json'), data, { spaces: 4 }), verify: (req, users) => req.headers.authorization && Object.prototype.hasOwnProperty.call(users, req.headers.authorization), getTrueHttp: () => ('http').concat(useSsl ? 's' : '').concat('://'), - getTrueDomain: (d = domain) => d.concat((port === 80 || port === 443 || isProxied) ? '' : `:${port}`), + getTrueDomain: (d = domain) => d.concat((port === HTTP || port === HTTPS || isProxied) ? '' : `:${port}`), renameFile: (req, newName) => new Promise((resolve, reject) => { try { const paths = [req.file.destination, newName]; @@ -47,16 +50,16 @@ module.exports = { }), generateToken: () => token(), generateId: (mode, length, gfyLength, originalName) => (GENERATORS.has(mode) ? GENERATORS.get(mode)({ length, gfyLength }) : originalName), - formatBytes: (bytes, decimals = 2) => { + formatBytes: (bytes, decimals = 2) => { // skipcq: JS-0074 if (bytes === 0) return '0 Bytes'; const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; - const i = Math.floor(Math.log(bytes) / Math.log(1024)); - return parseFloat((bytes / Math.pow(1024, i)).toFixed(decimals < 0 ? 0 : decimals)).toString().concat(` ${sizes[i]}`); + const i = Math.floor(Math.log(bytes) / Math.log(KILOBYTES)); + return parseFloat((bytes / Math.pow(KILOBYTES, i)).toFixed(decimals < 0 ? 0 : decimals)).toString().concat(` ${sizes[i]}`); }, randomHexColour: () => { // From: https://www.geeksforgeeks.org/javascript-generate-random-hex-codes-color/ const letters = "0123456789ABCDEF"; let colour = '#'; - for (let i = 0; i < 6; i++) + for (let i = 0; i < 6; i++) // skipcq: JS-0074 colour += letters[(Math.floor(Math.random() * letters.length))]; return colour; },