Properly extend Express interfaces

pull/125/head
tycrek 3 years ago
parent c5460b38e9
commit ab471d43ed
No known key found for this signature in database
GPG Key ID: 25D74F3943625263

@ -1,4 +1,4 @@
import { AssRequest, AssResponse, ErrWrap } from './definitions';
import { ErrWrap } from './definitions';
let doSetup = null;
try {
@ -20,7 +20,7 @@ const { host, port, useSsl, isProxied, s3enabled, frontendName, indexFile, useSi
//#region Imports
import fs from 'fs-extra';
import express from 'express';
import express, { Request, Response, NextFunction } from 'express';
const nofavicon = require('@tycrek/express-nofavicon');
const epcss = require('@tycrek/express-postcss');
import tailwindcss from 'tailwindcss';
@ -96,10 +96,10 @@ app.use('/css', epcss({
}));
// '/:resouceId' always needs to be LAST since it's a catch-all route
app.use('/:resourceId', (req: AssRequest, _res, next) => (req.resourceId = req.params.resourceId, next()), ROUTERS.resource); // skipcq: JS-0086, JS-0090
app.use('/:resourceId', (req, _res, next) => (req.resourceId = req.params.resourceId, next()), ROUTERS.resource); // skipcq: JS-0086, JS-0090
// Error handler
app.use((err: ErrWrap, _req: AssRequest, res: AssResponse, _next: Function) => log.error(err).err(err).callback(() => res.sendStatus(CODE_INTERNAL_SERVER_ERROR))); // skipcq: JS-0128
app.use((err: ErrWrap, _req: Request, res: Response, _next: NextFunction) => log.error(err).err(err).callback(() => res.sendStatus(CODE_INTERNAL_SERVER_ERROR))); // skipcq: JS-0128
// Host the server
log

@ -1,5 +1,17 @@
import { Request, Response } from "express";
declare global {
namespace Express {
interface Request {
resourceId: string
ass: { resourceId: string }
token: string
file: FileData
files: { [key: string]: any }
}
}
}
export interface User {
token: string
username: string
@ -55,18 +67,6 @@ export interface OpenGraphData {
color?: string | string[]
}
export interface AssRequest extends Request {
resourceId?: string
ass?: { resourceId: string }
token?: string
file?: FileData
files?: { [key: string]: any }
}
export interface AssResponse extends Response {
}
export interface ErrWrap extends Error {
code?: number | string
}

@ -1,8 +1,9 @@
import { FileData, IsPossible, AssRequest, AssResponse } from '../definitions';
import { FileData, IsPossible } from '../definitions';
import fs from 'fs-extra';
import escape from 'escape-html';
import fetch, { Response } from 'node-fetch';
import fetch, { Response as FetchResponse } from 'node-fetch';
import { Request, Response } from 'express';
import { deleteS3 } from '../storage';
import { SkynetDelete, SkynetDownload } from '../skynet';
const { diskFilePath, s3enabled, viewDirect, useSia } = require('../../config.json');
@ -15,7 +16,7 @@ import express from 'express';
const router = express.Router();
// Middleware for parsing the resource ID and handling 404
router.use((req: AssRequest, res: AssResponse, next) => {
router.use((req: Request, res: Response, next) => {
// Parse the resource ID
req.ass = { resourceId: escape(req.resourceId || '').split('.')[0] };
@ -26,7 +27,7 @@ router.use((req: AssRequest, res: AssResponse, next) => {
});
// View file
router.get('/', (req: AssRequest, res: AssResponse, next) => data.get(req.ass?.resourceId).then((fileData: FileData) => {
router.get('/', (req: Request, res: Response, next) => data.get(req.ass?.resourceId).then((fileData: FileData) => {
const resourceId = req.ass!.resourceId;
// Build OpenGraph meta tags
@ -60,14 +61,14 @@ router.get('/', (req: AssRequest, res: AssResponse, next) => data.get(req.ass?.r
}).catch(next));
// Direct resource
router.get('/direct*', (req: AssRequest, res: AssResponse, next) => data.get(req.ass?.resourceId).then((fileData: FileData) => {
router.get('/direct*', (req: Request, res: Response, next) => data.get(req.ass?.resourceId).then((fileData: FileData) => {
// Send file as an attachement for downloads
if (req.query.download)
res.header('Content-Disposition', `attachment; filename="${fileData.originalname}"`);
// Return the file differently depending on what storage option was used
const uploaders = {
s3: () => fetch(getS3url(fileData.randomId, fileData.ext)).then((file: Response) => {
s3: () => fetch(getS3url(fileData.randomId, fileData.ext)).then((file: FetchResponse) => {
file.headers.forEach((value, header) => res.setHeader(header, value));
file.body?.pipe(res);
}),
@ -86,7 +87,7 @@ router.get('/direct*', (req: AssRequest, res: AssResponse, next) => data.get(req
}).catch(next));
// Thumbnail response
router.get('/thumbnail', (req: AssRequest, res: AssResponse, next) =>
router.get('/thumbnail', (req: Request, res: Response, next) =>
data.get(req.ass?.resourceId)
.then(({ is, thumbnail }: { is: IsPossible, thumbnail: string }) => fs.readFile((!is || (is.image || is.video)) ? path(diskFilePath, 'thumbnails/', thumbnail) : is.audio ? 'views/ass-audio-icon.png' : 'views/ass-file-icon.png'))
.then((fileData: Buffer) => res.type('jpg').send(fileData))
@ -95,7 +96,7 @@ router.get('/thumbnail', (req: AssRequest, res: AssResponse, next) =>
// oEmbed response for clickable authors/providers
// https://oembed.com/
// https://old.reddit.com/r/discordapp/comments/82p8i6/a_basic_tutorial_on_how_to_get_the_most_out_of/
router.get('/oembed', (req: AssRequest, res: AssResponse, next) =>
router.get('/oembed', (req: Request, res: Response, next) =>
data.get(req.ass?.resourceId)
.then((fileData: FileData) =>
res.type('json').send({
@ -113,7 +114,7 @@ router.get('/oembed', (req: AssRequest, res: AssResponse, next) =>
.catch(next));
// Delete file
router.get('/delete/:deleteId', (req: AssRequest, res: AssResponse, next) => {
router.get('/delete/:deleteId', (req: Request, res: Response, next) => {
let oldName: string, oldType: string; // skipcq: JS-0119
data.get(req.ass?.resourceId)
.then((fileData: FileData) => {

@ -1,4 +1,4 @@
import { FileData, AssRequest, AssResponse, ErrWrap, User } from "../definitions";
import { ErrWrap, User } from "../definitions";
import fs from 'fs-extra';
import bb from 'express-busboy';
@ -13,7 +13,7 @@ import { data } from '../data';
import { users } from '../auth';
const ASS_LOGO = 'https://cdn.discordapp.com/icons/848274994375294986/8d339d4a2f3f54b2295e5e0ff62bd9e6.png?size=1024';
import express from 'express';
import express, { Request, Response } from 'express';
const router = express.Router();
// Set up express-busboy
@ -31,7 +31,7 @@ bb.extend(router, {
})); */
// Block unauthorized requests and attempt token sanitization
router.post('/', (req: AssRequest, res: AssResponse, next: Function) => {
router.post('/', (req: Request, res: Response, 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
@ -41,10 +41,10 @@ router.post('/', (req: AssRequest, res: AssResponse, next: Function) => {
router.post('/', processUploaded);
// Max upload size error handling
router.use('/', (err: ErrWrap, _req: AssRequest, res: AssResponse, next: Function) => err.message === '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: Request, res: Response, next: Function) => err.message === '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: AssRequest, res: AssResponse, next: Function) => {
router.post('/', (req: Request, res: Response, next: Function) => {
// Load overrides
const trueDomain = getTrueDomain(req.headers['x-ass-domain']);
const generator = req.headers['x-ass-access'] || resourceIdType;

@ -1,6 +1,6 @@
// https://docs.digitalocean.com/products/spaces/resources/s3-sdk-examples/
// https://www.digitalocean.com/community/tutorials/how-to-upload-a-file-to-object-storage-with-node-js
import { AssRequest, AssResponse, FileData } from './definitions';
import { FileData } from './definitions';
import fs, { Stats } from 'fs-extra';
import aws from 'aws-sdk';
@ -9,6 +9,7 @@ import Vibrant from './vibrant';
import Hash from './hash';
import { generateId, log } from './utils';
import { SkynetUpload } from './skynet';
import { Request, Response } from 'express';
const { s3enabled, s3endpoint, s3bucket, s3usePathStyle, s3accessKey, s3secretKey, diskFilePath, saveAsOriginal, saveWithDate, mediaStrict, maxUploadSize, useSia } = require('../config.json');
const { CODE_UNSUPPORTED_MEDIA_TYPE } = require('../MagicNumbers.json');
@ -31,11 +32,11 @@ function getDatedDirname() {
return `${diskFilePath}${diskFilePath.endsWith('/') ? '' : '/'}${year}-${`0${month}`.slice(-2)}`; // skipcq: JS-0074
}
function getLocalFilename(req: AssRequest) {
function getLocalFilename(req: Request) {
return `${getDatedDirname()}/${saveAsOriginal ? req.file!.originalname : req.file!.sha1}`;
}
export function processUploaded(req: AssRequest, res: AssResponse, next: Function) { // skipcq: JS-0045
export function processUploaded(req: Request, res: Response, next: Function) { // skipcq: JS-0045
// Fix file object
req.file = req.files!.file;

@ -1,4 +1,4 @@
import { AssRequest, FileData } from './definitions';
import { FileData } from './definitions';
import fs from 'fs-extra';
import Path from 'path';
import fetch from 'node-fetch';
@ -9,6 +9,7 @@ import zwsGen from './generators/zws';
import randomGen from './generators/random';
import gfyGen from './generators/gfycat';
import logger from './logger';
import { Request } from 'express';
const { HTTP, HTTPS, KILOBYTES } = require('../MagicNumbers.json');
// Catch config.json not existing when running setup script
@ -69,7 +70,7 @@ export function arrayEquals(arr1: any[], arr2: any[]) {
return arr1.length === arr2.length && arr1.slice().sort().every((value: string, index: number) => value === arr2.slice().sort()[index])
};
export function verify(req: AssRequest, users: JSON) {
export function verify(req: Request, users: JSON) {
return req.headers.authorization && Object.prototype.hasOwnProperty.call(users, req.headers.authorization);
}
@ -106,7 +107,7 @@ module.exports = {
randomHexColour,
sanitize,
verify,
renameFile: (req: AssRequest, newName: string) => new Promise((resolve: Function, reject) => {
renameFile: (req: Request, newName: string) => new Promise((resolve: Function, reject) => {
try {
const paths = [req.file!.destination, newName];
fs.rename(path(req.file!.path), path(...paths));

Loading…
Cancel
Save