diff --git a/src/definitions.d.ts b/src/definitions.d.ts index 5eea687..e6946a7 100644 --- a/src/definitions.d.ts +++ b/src/definitions.d.ts @@ -1,5 +1,10 @@ import { Request, Response } from "express"; +export interface User { + token: string + username: string +} + export interface FileData { // Data from Multer file object path: string @@ -11,7 +16,7 @@ export interface FileData { // Data from ass randomId: string deleteId: string - is: IsPossible, + is: IsPossible thumbnail: string vibrant: string sha1: string @@ -29,21 +34,26 @@ export interface IsPossible { } export interface OpenGraphData { - title?: string - description?: string - author?: string - authorUrl?: string - provider?: string - providerUrl?: string - color?: string + title?: string | string[] + description?: string | string[] + author?: string | string[] + authorUrl?: string | string[] + provider?: string | string[] + providerUrl?: string | string[] + color?: string | string[] } export interface AssRequest extends Request { resourceId?: string ass?: { resourceId: string } - + token?: string + file?: FileData } export interface AssResponse extends Response { -} \ No newline at end of file +} + +export interface ErrWrap extends Error { + code?: number | string +} diff --git a/src/routers/upload.js b/src/routers/upload.ts similarity index 71% rename from src/routers/upload.js rename to src/routers/upload.ts index 9bdaf76..68bc232 100644 --- a/src/routers/upload.js +++ b/src/routers/upload.ts @@ -1,3 +1,5 @@ +import { FileData, AssRequest, AssResponse, ErrWrap, User } from "../definitions"; + const fs = require('fs-extra'); //const rateLimit = require('express-rate-limit'); const { DateTime } = require('luxon'); @@ -10,7 +12,7 @@ const data = require('../data'); const users = require('../auth'); const ASS_LOGO = 'https://cdn.discordapp.com/icons/848274994375294986/8d339d4a2f3f54b2295e5e0ff62bd9e6.png?size=1024'; -const express = require('express'); +import express from 'express'; const router = express.Router(); // Rate limit middleware @@ -20,7 +22,7 @@ const router = express.Router(); })); */ // Block unauthorized requests and attempt token sanitization -router.post('/', (req, res, next) => { +router.post('/', (req: AssRequest, res: AssResponse, next: Function) => { 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) ? log.warn('Upload blocked', 'Unauthorized').callback(() => res.sendStatus(CODE_UNAUTHORIZED)) : next(); // skipcq: JS-0093 @@ -28,30 +30,30 @@ router.post('/', (req, res, next) => { // Upload file //router.post('/', doUpload, processUploaded, ({ next }) => next()); -router.post('/', (req, res, next) => doUpload(req, res, (err) => { +router.post('/', (req: AssRequest, res: AssResponse, next: Function) => doUpload(req, res, (err: Error) => { log.express().Header(req, 'Content-Type'); (err) ? log.error(`Multer encountered an ${!(err.toString().includes('MulterError')) ? 'unknown ' : ''}error`, err).callback(next, err) : log.debug('Multer', 'File saved in temp dir').callback(next); -}), processUploaded, ({ next }) => next()); +}), processUploaded, ({ next }: { next: Function }) => next()); -router.use('/', (err, _req, res, next) => err.code && err.code === 'LIMIT_FILE_SIZE' ? log.warn('Upload blocked', 'File too large').callback(() => res.status(CODE_PAYLOAD_TOO_LARGE).send(`Max upload size: ${maxUploadSize}MB`)) : next(err)); // skipcq: JS-0229 +router.use('/', (err: ErrWrap, _req: AssRequest, res: AssResponse, next: Function) => err.code && err.code === 'LIMIT_FILE_SIZE' ? log.warn('Upload blocked', 'File too large').callback(() => res.status(CODE_PAYLOAD_TOO_LARGE).send(`Max upload size: ${maxUploadSize}MB`)) : next(err)); // skipcq: JS-0229 // Process uploaded file -router.post('/', (req, res, next) => { +router.post('/', (req: AssRequest, res: AssResponse, next: Function) => { // Load overrides const trueDomain = getTrueDomain(req.headers['x-ass-domain']); const generator = req.headers['x-ass-access'] || resourceIdType; // Save domain with file - req.file.domain = `${getTrueHttp()}${trueDomain}`; + req.file!.domain = `${getTrueHttp()}${trueDomain}`; // Get the uploaded time in milliseconds - req.file.timestamp = DateTime.now().toMillis(); + req.file!.timestamp = DateTime.now().toMillis(); // Keep track of the token that uploaded the resource - req.file.token = req.token; + req.file!.token = req.token ?? ''; // Attach any embed overrides, if necessary - req.file.opengraph = { + req.file!.opengraph = { title: req.headers['x-ass-og-title'], description: req.headers['x-ass-og-description'], author: req.headers['x-ass-og-author'], @@ -62,17 +64,17 @@ router.post('/', (req, res, next) => { }; // Save the file information - const resourceId = generateId(generator, resourceIdSize, req.headers['x-ass-gfycat'] || gfyIdSize, req.file.originalname); + const resourceId = generateId(generator, resourceIdSize, req.headers['x-ass-gfycat'] || gfyIdSize, req.file!.originalname); log.debug('Saving data', data.name); data.put(resourceId.split('.')[0], req.file).then(() => { // Log the upload - const logInfo = `${req.file.originalname} (${req.file.mimetype}, ${formatBytes(req.file.size)})`; - log.success('File uploaded', logInfo, `uploaded by ${users[req.token] ? users[req.token].username : ''}`); + const logInfo = `${req.file!.originalname} (${req.file!.mimetype}, ${formatBytes(req.file!.size)})`; + log.success('File uploaded', logInfo, `uploaded by ${users[req.token ?? ''] ? users[req.token ?? ''].username : ''}`); // Build the URLs const resourceUrl = `${getTrueHttp()}${trueDomain}/${resourceId}`; const thumbnailUrl = `${getTrueHttp()}${trueDomain}/${resourceId}/thumbnail`; - const deleteUrl = `${getTrueHttp()}${trueDomain}/${resourceId}/delete/${req.file.deleteId}`; + const deleteUrl = `${getTrueHttp()}${trueDomain}/${resourceId}/delete/${req.file!.deleteId}`; // Send the response res.type('json').send({ resource: resourceUrl, thumbnail: thumbnailUrl, delete: deleteUrl }) @@ -88,10 +90,10 @@ router.post('/', (req, res, next) => { const embed = new MessageEmbed() .setTitle(logInfo) .setURL(resourceUrl) - .setDescription(`**Size:** \`${formatBytes(req.file.size)}\`\n**[Delete](${deleteUrl})**`) + .setDescription(`**Size:** \`${formatBytes(req.file!.size)}\`\n**[Delete](${deleteUrl})**`) .setThumbnail(thumbnailUrl) - .setColor(req.file.vibrant) - .setTimestamp(req.file.timestamp); + .setColor(req.file!.vibrant) + .setTimestamp(req.file!.timestamp); // Send the embed to the webhook, then delete the client after to free resources log.debug('Sending webhook to client', client); @@ -103,14 +105,18 @@ router.post('/', (req, res, next) => { } // Also update the users upload count - if (!users[req.token]) { + if (!users[req.token ?? '']) { 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 + let username: string = generateUsername(); + + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + while (Object.values(users).findIndex((user: User) => user.username === username) !== -1) // skipcq: JS-0073 username = generateUsername(); - users[req.token] = { username, count: 0 }; + + users[req.token ?? ''] = { username, count: 0 }; } - users[req.token].count += 1; + users[req.token ?? ''].count += 1; fs.writeJsonSync(path('auth.json'), { users }, { spaces: 4 }); log.debug('Upload request flow completed', '');