diff --git a/backend/UserConfig.ts b/backend/UserConfig.ts index 8b452e0..1a94a0a 100644 --- a/backend/UserConfig.ts +++ b/backend/UserConfig.ts @@ -3,6 +3,7 @@ import { UserConfiguration, UserConfigTypeChecker, PostgresConfiguration } from import fs from 'fs-extra'; import { path } from '@tycrek/joint'; import { log } from './log.js'; +import fetch from "node-fetch"; const FILEPATH = path.join('.ass-data/userconfig.json'); @@ -40,6 +41,10 @@ const Checkers: UserConfigTypeChecker = { idSize: numChecker, gfySize: numChecker, maximumFileSize: numChecker, + discordWebhook: (val) => { + const regex = /^https:\/\/discord\.com\/api\/webhooks\/\d+\/\S+$/; + return regex.test(val); + }, s3: { endpoint: basicStringChecker, @@ -96,6 +101,7 @@ export class UserConfig { if (!Checkers.idSize(config.idSize)) throw new Error('Invalid ID size'); if (!Checkers.gfySize(config.gfySize)) throw new Error('Invalid Gfy size'); if (!Checkers.maximumFileSize(config.maximumFileSize)) throw new Error('Invalid maximum file size'); + if (!Checkers.discordWebhook(config.discordWebhook)) throw new Error('Invalid Discord webhook'); // * Optional S3 config if (config.s3 != null) { diff --git a/backend/routers/index.ts b/backend/routers/index.ts index b62aa59..3a44cc3 100644 --- a/backend/routers/index.ts +++ b/backend/routers/index.ts @@ -3,6 +3,7 @@ import { BusBoyFile, AssFile } from 'ass'; import fs from 'fs-extra'; import bb from 'express-busboy'; import crypto from 'crypto'; +import fetch from 'node-fetch'; import { Router } from 'express'; import { Readable } from 'stream'; @@ -88,7 +89,21 @@ router.post('/', rateLimiterMiddleware("upload", UserConfig.config?.rateLimit?.u data.put('files', assFile.fakeid, assFile); log.debug('File saved to', !s3 ? assFile.save.local! : 'S3'); - return res.type('json').send({ resource: `${req.ass.host}/${assFile.fakeid}` }); + await res.type('json').send({ resource: `${req.ass.host}/${assFile.fakeid}` }); + + // Send to Discord webhook + try { + await fetch(UserConfig.config.discordWebhook, { + method: "POST", + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ content: `New upload: ${req.ass.host}/${assFile.fakeid}` }) + }) + } catch (err) { + log.warn("Failed to send request to Discord webhook"); + console.error(err); + } } catch (err) { log.error('Failed to upload file', bbFile.filename); console.error(err); diff --git a/backend/utils.ts b/backend/utils.ts index 64df481..ece47cf 100644 --- a/backend/utils.ts +++ b/backend/utils.ts @@ -1,4 +1,7 @@ import { DateTime } from 'luxon'; +import { id } from 'william.js'; + +export const customId = (length: number, alphabet: string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") => id(length, 1, alphabet); export const randomHexColour = () => { // From: https://www.geeksforgeeks.org/javascript-generate-random-hex-codes-color/ const letters = '0123456789ABCDEF'; diff --git a/common/types.d.ts b/common/types.d.ts index 299b1ad..e3572a9 100644 --- a/common/types.d.ts +++ b/common/types.d.ts @@ -25,6 +25,7 @@ declare module 'ass' { idSize: number; gfySize: number; maximumFileSize: number; + discordWebhook: string; s3?: S3Configuration; database?: DatabaseConfiguration; @@ -154,6 +155,7 @@ declare module 'ass' { idSize: (val: any) => boolean; gfySize: (val: any) => boolean; maximumFileSize: (val: any) => boolean; + discordWebhook: (val: any) => boolean; s3: { endpoint: (val: any) => boolean; bucket: (val: any) => boolean; diff --git a/package.json b/package.json index c50dda2..98e926a 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "luxon": "^3.4.4", "memorystore": "^1.6.7", "mysql2": "^3.6.5", + "node-fetch": "^3.3.2", "node-vibrant": "^3.1.6", "pg": "^8.11.3", "pug": "^3.0.2", @@ -61,7 +62,8 @@ "shoelace-fontawesome-pug": "^6.4.3", "shoelace-pug-loader": "^2.11.0", "tailwindcss": "^3.3.6", - "typescript": "^5.3.2" + "typescript": "^5.3.2", + "william.js": "^1.2.2" }, "devDependencies": { "@types/bcrypt": "^5.0.2",