feat: added global admin webhook (#142)

Adds options to log all uploads from all users with a webhook
pull/171/head
tycrek 2 years ago
parent 122386021f
commit 1aaf298b02
No known key found for this signature in database
GPG Key ID: FF8A54DCE404885A

@ -10,7 +10,7 @@ import { processUploaded } from '../storage';
import { path, log, verify, getTrueHttp, getTrueDomain, generateId, formatBytes } from '../utils';
import { data } from '../data';
import { users } from '../auth';
const { maxUploadSize, resourceIdSize, gfyIdSize, resourceIdType, spaceReplace }: Config = fs.readJsonSync(path('config.json'));
const { maxUploadSize, resourceIdSize, gfyIdSize, resourceIdType, spaceReplace, adminWebhookEnabled, adminWebhookUrl, adminWebhookUsername, adminWebhookAvatar }: Config = fs.readJsonSync(path('config.json'));
const { CODE_UNAUTHORIZED, CODE_PAYLOAD_TOO_LARGE }: MagicNumbers = fs.readJsonSync(path('MagicNumbers.json'));
const ASS_LOGO = 'https://cdn.discordapp.com/icons/848274994375294986/8d339d4a2f3f54b2295e5e0ff62bd9e6.png?size=1024';
@ -110,42 +110,58 @@ router.post('/', (req: Request, res: Response, next: Function) => {
.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 : '<token-only>'}`);
const uploader = users[req.token ?? ''] ? users[req.token ?? ''].username : '<token-only>';
log.success('File uploaded', logInfo, `uploaded by ${uploader}`);
// Build the URLs
const resourceUrl = `${getTrueHttp()}${trueDomain}/${resourceId}`;
const thumbnailUrl = `${getTrueHttp()}${trueDomain}/${resourceId}/thumbnail`;
const deleteUrl = `${getTrueHttp()}${trueDomain}/${resourceId}/delete/${req.file.deleteId}`;
const buildSendWebhook = (url: string, username: string, avatar: string, admin = false) => {
if (url === '') return;
// Build the webhook
const hook = new Webhook(url);
hook.setUsername(username);
hook.setAvatar(avatar);
// Build the embed
const embed = new MessageBuilder()
.setTitle(logInfo)
//@ts-ignore
.setURL(resourceUrl)
.setDescription(`${admin ? `**User:** \`${uploader}\`\n` : ''}**Size:** \`${formatBytes(req.file.size)}\`\n**[Delete](${deleteUrl})**`)
.setThumbnail(thumbnailUrl)
.setColor(req.file.vibrant)
.setTimestamp();
// Send the embed to the webhook, then delete the client after to free resources
log.debug(`Sending${admin ? ' admin' : ''} embed to webhook`);
hook.send(embed)
.then(() => log.debug(`Webhook${admin ? ' admin' : ''} sent`))
.catch((err) => log.error('Webhook error').err(err));
}
// Send the response
res.type('json').send({ resource: resourceUrl, thumbnail: thumbnailUrl, delete: deleteUrl })
.on('finish', () => {
log.debug('Upload response sent');
// After we have sent the user the response, also send a Webhook to Discord (if headers are present)
if (req.headers['x-ass-webhook-url']) {
// Build the webhook
const hook = new Webhook(req.headers['x-ass-webhook-url']?.toString());
hook.setUsername(req.headers['x-ass-webhook-username']?.toString() || 'ass');
hook.setAvatar(req.headers['x-ass-webhook-avatar']?.toString() || ASS_LOGO);
// Build the embed
const embed = new MessageBuilder()
.setTitle(logInfo)
//@ts-ignore
.setURL(resourceUrl)
.setDescription(`**Size:** \`${formatBytes(req.file.size)}\`\n**[Delete](${deleteUrl})**`)
.setThumbnail(thumbnailUrl)
.setColor(req.file.vibrant)
.setTimestamp();
// Send the embed to the webhook, then delete the client after to free resources
log.debug('Sending embed to webhook');
hook.send(embed)
.then(() => log.debug('Webhook sent'))
.catch((err) => log.error('Webhook error').err(err));
}
if (req.headers['x-ass-webhook-url'])
buildSendWebhook(
req.headers['x-ass-webhook-url']?.toString(),
req.headers['x-ass-webhook-username']?.toString() || 'ass',
req.headers['x-ass-webhook-avatar']?.toString() || ASS_LOGO);
// Send the webhook to the default webhook, if it exists
if (adminWebhookEnabled)
buildSendWebhook(
adminWebhookUrl,
adminWebhookUsername.trim().length === 0 ? 'ass admin logs' : adminWebhookUsername,
adminWebhookAvatar.trim().length === 0 ? ASS_LOGO : adminWebhookAvatar,
true);
// Also update the users upload count
if (!users[req.token ?? '']) {

@ -15,9 +15,17 @@ const config = {
dataEngine: '@tycrek/papito',
frontendName: 'ass-x',
useSia: false,
adminWebhookEnabled: false,
s3enabled: false,
};
// Default admin webhook
const adminWebhookConfig = {
adminWebhookUrl: '',
adminWebhookUsername: '',
adminWebhookAvatar: '',
}
// Default S3 config
const s3config = {
s3endpoint: 'sfo3.digitaloceanspaces.com',
@ -178,6 +186,12 @@ function doSetup() {
default: config.useSia,
required: false
},
adminWebhookEnabled: {
description: 'Enable admin Discord webhook (This will let you audit ALL uploads, from ALL users)',
type: 'boolean',
default: config.adminWebhookEnabled,
required: false
},
s3enabled: {
description: 'Enable uploading to S3 storage endpoints',
type: 'boolean',
@ -187,6 +201,29 @@ function doSetup() {
}
};
const adminWebhookSchema = {
properties: {
adminWebhookUrl: {
description: 'Discord webhook URL for admin notifications',
type: 'string',
default: adminWebhookConfig.adminWebhookUrl,
required: true
},
adminWebhookUsername: {
description: 'Username to send the webhook as',
type: 'string',
default: adminWebhookConfig.adminWebhookUsername,
required: false
},
adminWebhookAvatar: {
description: 'Avatar to use for the webhook icon',
type: 'string',
default: adminWebhookConfig.adminWebhookAvatar,
required: false
}
}
};
const s3schema = {
properties: {
s3endpoint: {
@ -231,9 +268,12 @@ function doSetup() {
prompt.get(setupSchema)
.then((r) => results = r) // skipcq: JS-0086
// Check if using admin webhook
.then(() => results.adminWebhookEnabled ? prompt.get(adminWebhookSchema) : adminWebhookConfig) // skipcq: JS-0229
.then((r) => Object.entries(r).forEach(([k, v]) => results[k] = v)) // skipcq: JS-0086
// Check if using S3
.then(() => results.s3enabled ? prompt.get(s3schema) : s3config) // skipcq: JS-0229
.then((r) => Object.entries(r).forEach(([key, value]) => results[key] = value)) // skipcq: JS-0086
.then((r) => Object.entries(r).forEach(([k, v]) => results[k] = v)) // skipcq: JS-0086
// Verify information is correct
.then(() => log

@ -16,6 +16,10 @@ declare module 'ass-json' {
frontendName: string
indexFile: string
useSia: boolean
adminWebhookEnabled: boolean
adminWebhookUrl: string
adminWebhookUsername: string
adminWebhookAvatar: string
s3enabled: boolean
s3endpoint: string
s3bucket: string

Loading…
Cancel
Save