migrated Resource router to TS; added some type definitions

pull/62/head
tycrek 3 years ago
parent 5bd5f258a3
commit 5d9d749062
No known key found for this signature in database
GPG Key ID: 25D74F3943625263

214
package-lock.json generated

@ -14,6 +14,7 @@
"@tycrek/express-nofavicon": "^1.0.2",
"@tycrek/isprod": "^2.0.2",
"@tycrek/log": ">=0.5.x",
"@types/escape-html": "^1.0.1",
"@types/fs-extra": "^9.0.12",
"@types/node": "^14.17.15",
"@types/ws": "^7.4.7",
@ -32,7 +33,7 @@
"luxon": "^1.26.0",
"marked": "^2.0.7",
"multer": "2.0.0-rc.2",
"node-fetch": "^2.6.1",
"node-fetch": "^2.6.2",
"node-vibrant": "*",
"prompt": "^1.1.0",
"pug": "^3.0.2",
@ -42,6 +43,10 @@
"ts": "^0.2.2",
"uuid": "^8.3.2"
},
"devDependencies": {
"@types/express": "^4.17.13",
"@types/node-fetch": "^2.5.12"
},
"engines": {
"node": ">=14.7.x <16",
"npm": ">=7.x.x"
@ -724,6 +729,53 @@
"url": "https://patreon.com/tycrek"
}
},
"node_modules/@types/body-parser": {
"version": "1.19.1",
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.1.tgz",
"integrity": "sha512-a6bTJ21vFOGIkwM0kzh9Yr89ziVxq4vYH2fQ6N8AeipEzai/cFK6aGMArIkUeIdRIgpwQa+2bXiLuUJCpSf2Cg==",
"dev": true,
"dependencies": {
"@types/connect": "*",
"@types/node": "*"
}
},
"node_modules/@types/connect": {
"version": "3.4.35",
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz",
"integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==",
"dev": true,
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/escape-html": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@types/escape-html/-/escape-html-1.0.1.tgz",
"integrity": "sha512-4mI1FuUUZiuT95fSVqvZxp/ssQK9zsa86S43h9x3zPOSU9BBJ+BfDkXwuaU7BfsD+e7U0/cUUfJFk3iW2M4okA=="
},
"node_modules/@types/express": {
"version": "4.17.13",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz",
"integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==",
"dev": true,
"dependencies": {
"@types/body-parser": "*",
"@types/express-serve-static-core": "^4.17.18",
"@types/qs": "*",
"@types/serve-static": "*"
}
},
"node_modules/@types/express-serve-static-core": {
"version": "4.17.24",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz",
"integrity": "sha512-3UJuW+Qxhzwjq3xhwXm2onQcFHn76frIYVbTu+kn24LFxI+dEhdfISDFovPB8VpEgW8oQCTpRuCe+0zJxB7NEA==",
"dev": true,
"dependencies": {
"@types/node": "*",
"@types/qs": "*",
"@types/range-parser": "*"
}
},
"node_modules/@types/fs-extra": {
"version": "9.0.12",
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.12.tgz",
@ -732,11 +784,49 @@
"@types/node": "*"
}
},
"node_modules/@types/mime": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
"integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==",
"dev": true
},
"node_modules/@types/node": {
"version": "14.17.15",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.15.tgz",
"integrity": "sha512-D1sdW0EcSCmNdLKBGMYb38YsHUS6JcM7yQ6sLQ9KuZ35ck7LYCKE7kYFHOO59ayFOY3zobWVZxf4KXhYHcHYFA=="
},
"node_modules/@types/node-fetch": {
"version": "2.5.12",
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.12.tgz",
"integrity": "sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw==",
"dev": true,
"dependencies": {
"@types/node": "*",
"form-data": "^3.0.0"
}
},
"node_modules/@types/qs": {
"version": "6.9.7",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
"integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
"dev": true
},
"node_modules/@types/range-parser": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz",
"integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==",
"dev": true
},
"node_modules/@types/serve-static": {
"version": "1.13.10",
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz",
"integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==",
"dev": true,
"dependencies": {
"@types/mime": "^1",
"@types/node": "*"
}
},
"node_modules/@types/ws": {
"version": "7.4.7",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz",
@ -2061,6 +2151,20 @@
"ms": "2.0.0"
}
},
"node_modules/form-data": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
"integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
"dev": true,
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@ -2894,9 +2998,9 @@
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
},
"node_modules/node-fetch": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==",
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.2.tgz",
"integrity": "sha512-aLoxToI6RfZ+0NOjmWAgn9+LEd30YCkJKFSyWacNZdEKTit/ZMcKjGkTRo8uWEsnIb/hfKecNPEbln02PdWbcA==",
"engines": {
"node": "4.x || >=6.0.0"
}
@ -5105,6 +5209,53 @@
"use-climate-change-reminder": "^0.0.7"
}
},
"@types/body-parser": {
"version": "1.19.1",
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.1.tgz",
"integrity": "sha512-a6bTJ21vFOGIkwM0kzh9Yr89ziVxq4vYH2fQ6N8AeipEzai/cFK6aGMArIkUeIdRIgpwQa+2bXiLuUJCpSf2Cg==",
"dev": true,
"requires": {
"@types/connect": "*",
"@types/node": "*"
}
},
"@types/connect": {
"version": "3.4.35",
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz",
"integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/escape-html": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@types/escape-html/-/escape-html-1.0.1.tgz",
"integrity": "sha512-4mI1FuUUZiuT95fSVqvZxp/ssQK9zsa86S43h9x3zPOSU9BBJ+BfDkXwuaU7BfsD+e7U0/cUUfJFk3iW2M4okA=="
},
"@types/express": {
"version": "4.17.13",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz",
"integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==",
"dev": true,
"requires": {
"@types/body-parser": "*",
"@types/express-serve-static-core": "^4.17.18",
"@types/qs": "*",
"@types/serve-static": "*"
}
},
"@types/express-serve-static-core": {
"version": "4.17.24",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz",
"integrity": "sha512-3UJuW+Qxhzwjq3xhwXm2onQcFHn76frIYVbTu+kn24LFxI+dEhdfISDFovPB8VpEgW8oQCTpRuCe+0zJxB7NEA==",
"dev": true,
"requires": {
"@types/node": "*",
"@types/qs": "*",
"@types/range-parser": "*"
}
},
"@types/fs-extra": {
"version": "9.0.12",
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.12.tgz",
@ -5113,11 +5264,49 @@
"@types/node": "*"
}
},
"@types/mime": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
"integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==",
"dev": true
},
"@types/node": {
"version": "14.17.15",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.15.tgz",
"integrity": "sha512-D1sdW0EcSCmNdLKBGMYb38YsHUS6JcM7yQ6sLQ9KuZ35ck7LYCKE7kYFHOO59ayFOY3zobWVZxf4KXhYHcHYFA=="
},
"@types/node-fetch": {
"version": "2.5.12",
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.12.tgz",
"integrity": "sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw==",
"dev": true,
"requires": {
"@types/node": "*",
"form-data": "^3.0.0"
}
},
"@types/qs": {
"version": "6.9.7",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
"integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
"dev": true
},
"@types/range-parser": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz",
"integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==",
"dev": true
},
"@types/serve-static": {
"version": "1.13.10",
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz",
"integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==",
"dev": true,
"requires": {
"@types/mime": "^1",
"@types/node": "*"
}
},
"@types/ws": {
"version": "7.4.7",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz",
@ -6174,6 +6363,17 @@
}
}
},
"form-data": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
"integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
"dev": true,
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
}
},
"forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@ -6822,9 +7022,9 @@
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
},
"node-fetch": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.2.tgz",
"integrity": "sha512-aLoxToI6RfZ+0NOjmWAgn9+LEd30YCkJKFSyWacNZdEKTit/ZMcKjGkTRo8uWEsnIb/hfKecNPEbln02PdWbcA=="
},
"node-vibrant": {
"version": "3.2.1-alpha.1",

@ -41,6 +41,7 @@
"@tycrek/express-nofavicon": "^1.0.2",
"@tycrek/isprod": "^2.0.2",
"@tycrek/log": ">=0.5.x",
"@types/escape-html": "^1.0.1",
"@types/fs-extra": "^9.0.12",
"@types/node": "^14.17.15",
"@types/ws": "^7.4.7",
@ -59,7 +60,7 @@
"luxon": "^1.26.0",
"marked": "^2.0.7",
"multer": "2.0.0-rc.2",
"node-fetch": "^2.6.1",
"node-fetch": "^2.6.2",
"node-vibrant": "*",
"prompt": "^1.1.0",
"pug": "^3.0.2",
@ -68,5 +69,9 @@
"submodule": "^1.2.1",
"ts": "^0.2.2",
"uuid": "^8.3.2"
},
"devDependencies": {
"@types/express": "^4.17.13",
"@types/node-fetch": "^2.5.12"
}
}
}

@ -0,0 +1,49 @@
import { Request, Response } from "express";
export interface FileData {
// Data from Multer file object
path: string
size: number
mimetype: string
ext: string
originalname: string
// Data from ass
randomId: string
deleteId: string
is: IsPossible,
thumbnail: string
vibrant: string
sha1: string
domain: string
timestamp: number
token: string
opengraph: OpenGraphData
}
export interface IsPossible {
image: boolean
video: boolean
audio: boolean
other: boolean
}
export interface OpenGraphData {
title?: string
description?: string
author?: string
authorUrl?: string
provider?: string
providerUrl?: string
color?: string
}
export interface AssRequest extends Request {
resourceId?: string
ass?: { resourceId: string }
}
export interface AssResponse extends Response {
}

@ -1,6 +1,8 @@
const fs = require('fs-extra');
const escape = require('escape-html');
const fetch = require('node-fetch');
import { FileData, IsPossible, AssRequest, AssResponse } from '../definitions';
import fs from 'fs-extra';
import escape from 'escape-html';
import fetch, { Response } from 'node-fetch';
const { deleteS3 } = require('../storage');
const { diskFilePath, s3enabled, viewDirect } = require('../../config.json');
const { path, log, getTrueHttp, getTrueDomain, formatBytes, formatTimestamp, getS3url, getDirectUrl, getResourceColor, replaceholder } = require('../utils');
@ -8,23 +10,23 @@ const { CODE_UNAUTHORIZED, CODE_NOT_FOUND, } = require('../../MagicNumbers.json'
const data = require('../data');
const users = require('../auth');
const express = require('express');
import express from 'express';
const router = express.Router();
// Middleware for parsing the resource ID and handling 404
router.use((req, res, next) => {
router.use((req: AssRequest, res: AssResponse, next) => {
// Parse the resource ID
req.ass = { resourceId: escape(req.resourceId || '').split('.')[0] };
// If the ID is invalid, return 404. Otherwise, continue normally
data.has(req.ass.resourceId)
.then((has) => has ? next() : res.sendStatus(CODE_NOT_FOUND)) // skipcq: JS-0229
.then((has: boolean) => has ? next() : res.sendStatus(CODE_NOT_FOUND)) // skipcq: JS-0229
.catch(next);
});
// View file
router.get('/', (req, res, next) => data.get(req.ass.resourceId).then((fileData) => {
const { resourceId } = req.ass;
router.get('/', (req: AssRequest, res: AssResponse, next) => data.get(req.ass?.resourceId).then((fileData: FileData) => {
const resourceId = req.ass?.resourceId;
// Build OpenGraph meta tags
const og = fileData.opengraph, ogs = [''];
@ -53,19 +55,19 @@ router.get('/', (req, res, next) => data.get(req.ass.resourceId).then((fileData)
}).catch(next));
// Direct resource
router.get('/direct*', (req, res, next) => data.get(req.ass.resourceId).then((fileData) => {
router.get('/direct*', (req: AssRequest, res: AssResponse, 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) => {
s3: () => fetch(getS3url(fileData.randomId, fileData.ext)).then((file: Response) => {
file.headers.forEach((value, header) => res.setHeader(header, value));
file.body.pipe(res);
file.body?.pipe(res);
}),
local: () => {
res.header('Accept-Ranges', 'bytes').header('Content-Length', fileData.size).type(fileData.mimetype);
res.header('Accept-Ranges', 'bytes').header('Content-Length', `${fileData.size}`).type(fileData.mimetype);
fs.createReadStream(fileData.path).pipe(res);
}
};
@ -74,33 +76,33 @@ router.get('/direct*', (req, res, next) => data.get(req.ass.resourceId).then((fi
}).catch(next));
// Thumbnail response
router.get('/thumbnail', (req, res, next) =>
data.get(req.ass.resourceId)
.then(({ is, thumbnail }) => 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) => res.type('jpg').send(fileData))
router.get('/thumbnail', (req: AssRequest, res: AssResponse, 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))
.catch(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, res, next) =>
data.get(req.ass.resourceId)
.then(({ opengraph, is, size, timestamp, originalname }) =>
router.get('/oembed', (req: AssRequest, res: AssResponse, next) =>
data.get(req.ass?.resourceId)
.then((fileData: FileData) =>
res.type('json').send({
version: '1.0',
type: is.video ? 'video' : is.image ? 'photo' : 'link',
author_url: opengraph.authorUrl,
provider_url: opengraph.providerUrl,
author_name: replaceholder(opengraph.author || '', size, timestamp, originalname),
provider_name: replaceholder(opengraph.provider || '', size, timestamp, originalname)
type: fileData.is.video ? 'video' : fileData.is.image ? 'photo' : 'link',
author_url: fileData.opengraph.authorUrl,
provider_url: fileData.opengraph.providerUrl,
author_name: replaceholder(fileData.opengraph.author || '', fileData.size, fileData.timestamp, fileData.originalname),
provider_name: replaceholder(fileData.opengraph.provider || '', fileData.size, fileData.timestamp, fileData.originalname)
}))
.catch(next));
// Delete file
router.get('/delete/:deleteId', (req, res, next) => {
let oldName, oldType; // skipcq: JS-0119
data.get(req.ass.resourceId)
.then((fileData) => {
router.get('/delete/:deleteId', (req: AssRequest, res: AssResponse, next) => {
let oldName: string, oldType: string; // skipcq: JS-0119
data.get(req.ass?.resourceId)
.then((fileData: FileData) => {
// Extract info for logs
oldName = fileData.originalname;
oldType = fileData.mimetype;
@ -117,7 +119,7 @@ router.get('/delete/:deleteId', (req, res, next) => {
(!fileData.is || (fileData.is.image || fileData.is.video)) && fs.existsSync(path(diskFilePath, 'thumbnails/', fileData.thumbnail))
? fs.rmSync(path(diskFilePath, 'thumbnails/', fileData.thumbnail)) : () => Promise.resolve()]);
})
.then(() => data.del(req.ass.resourceId))
.then(() => data.del(req.ass?.resourceId))
.then(() => (log.success('Deleted', oldName, oldType), res.type('text').send('File has been deleted!'))) // skipcq: JS-0090
.catch(next);
});
Loading…
Cancel
Save