From 3bda2c0cb41fec3b763c0900f6d43892789b49ba Mon Sep 17 00:00:00 2001 From: tycrek Date: Thu, 17 Jun 2021 09:59:47 -0600 Subject: [PATCH] added S3 file deletion --- ass.js | 35 ++++++++++++++++++++++------------- ogp.js | 4 ++-- storage.js | 12 +++++++----- utils.js | 7 ++++++- 4 files changed, 37 insertions(+), 21 deletions(-) diff --git a/ass.js b/ass.js index 211ce59..04986d1 100755 --- a/ass.js +++ b/ass.js @@ -23,7 +23,7 @@ const Thumbnail = require('./thumbnails'); const Vibrant = require('./vibrant'); const Hash = require('./hash'); const Path = require('path'); -const { uploadLocal, uploadS3 } = require('./storage'); +const { uploadLocal, uploadS3, deleteS3 } = require('./storage'); const { path, saveData, log, verify, generateToken, generateId, formatBytes, arrayEquals, getS3url, downloadTempS3 } = require('./utils'); //#endregion @@ -74,7 +74,9 @@ function startup() { app.set('view engine', 'pug'); app.use(useragent.express()); + // Generate ID's to use for other functions app.use((req, _res, next) => (req.randomId = generateId('random', 32, null, null), next())); + app.use((req, _res, next) => (req.deleteId = generateId('random', 32, null, null), next())); // Don't process favicon requests app.use((req, res, next) => req.url.includes('favicon.ico') ? res.sendStatus(204) : next()); @@ -105,6 +107,7 @@ function startup() { // Pre-response operations app.post('/', (req, _res, next) => { req.file.randomId = req.randomId; + req.file.deleteId = req.deleteId; // Download a temp copy to work with if using S3 storage (s3enabled ? downloadTempS3(req.file) : new Promise((resolve) => resolve())) @@ -175,7 +178,7 @@ function startup() { // Build the URLs let resourceUrl = `${getTrueHttp()}${trueDomain}/${resourceId}`; let thumbnailUrl = `${getTrueHttp()}${trueDomain}/${resourceId}/thumbnail`; - let deleteUrl = `${getTrueHttp()}${trueDomain}/delete/${req.file.filename}`; + let deleteUrl = `${getTrueHttp()}${trueDomain}/${resourceId}/delete/${req.file.deleteId}`; // Send the response res.type('json').send({ resource: resourceUrl, thumbnail: thumbnailUrl, delete: deleteUrl }) @@ -267,22 +270,28 @@ function startup() { }); // Delete file - app.get('/delete/:filename', (req, res) => { - let filename = req.params.filename; - let resourceId = Object.keys(data)[Object.values(data).indexOf(Object.values(data).find((d) => d.filename == filename))]; + app.get('/:resourceId/delete/:deleteId', (req, res) => { + let resourceId = req.params.resourceId; + let deleteId = req.params.deleteId; + let fileData = data[resourceId]; + + // If the delete ID doesn't match, don't delete the file + if (deleteId !== fileData.deleteId) return res.sendStatus(401); // If the ID is invalid, return 400 because we are unable to process the resource - if (!resourceId || !data[resourceId]) return res.sendStatus(400); + if (!resourceId || !fileData) return res.sendStatus(400); - log(`Deleted: ${data[resourceId].originalname} (${data[resourceId].mimetype})`); + log(`Deleted: ${fileData.originalname} (${fileData.mimetype})`); // Save the file information - fs.rmSync(path(data[resourceId].path)); - delete data[resourceId]; - saveData(data); - - res.type('text').send('File has been deleted!'); - }) + Promise.all([s3enabled ? deleteS3(fileData) : fs.rmSync(path(fileData.path)), fs.rmSync(path('uploads/thumbnails/', fileData.thumbnail))]) + .then(() => { + delete data[resourceId]; + saveData(data); + res.type('text').send('File has been deleted!'); + }) + .catch(console.error); + }); app.listen(port, host, () => log(`Server started on [${host}:${port}]\nAuthorized users: ${Object.keys(users).length}\nAvailable files: ${Object.keys(data).length}`)); } diff --git a/ogp.js b/ogp.js index e0972fd..6d87e2b 100644 --- a/ogp.js +++ b/ogp.js @@ -2,7 +2,7 @@ const Mustache = require('mustache'); const DateTime = require('luxon').DateTime; const { homepage, version } = require('./package.json'); const { s3enabled } = require('./config.json'); -const { formatBytes, randomHexColour, getS3url } = require('./utils'); +const { formatBytes, randomHexColour, getS3url, getSafeExt } = require('./utils'); // https://ogp.me/ class OpenGraph { @@ -41,7 +41,7 @@ class OpenGraph { } build() { - let resourceUrl = !s3enabled ? (this.http + this.domain + "/" + this.resourceId + (this.type.includes('video') ? '.mp4' : this.type.includes('gif') ? '.gif' : '')) : getS3url(this.randomId, this.type); + let resourceUrl = !s3enabled ? (this.http + this.domain + "/" + this.resourceId + getSafeExt(this.type)) : getS3url(this.randomId, this.type); return Mustache.render(html, { homepage, version, diff --git a/storage.js b/storage.js index 30a9cb2..f256b67 100644 --- a/storage.js +++ b/storage.js @@ -5,6 +5,7 @@ const fs = require('fs-extra'); const aws = require('aws-sdk'); const multer = require('multer'); const multerS3 = require('multer-s3'); +const { getSafeExt } = require('./utils'); const { diskFilePath, saveWithDate, s3endpoint, s3bucket, s3accessKey, s3secretKey } = require('./config.json'); const s3 = new aws.S3({ @@ -17,11 +18,15 @@ const uploadS3 = multer({ s3: s3, bucket: s3bucket, acl: 'public-read', - key: (req, file, cb) => cb(null, req.randomId.concat(file.mimetype.includes('video') ? '.mp4' : file.mimetype.includes('gif') ? '.gif' : '')), + key: (req, file, cb) => cb(null, req.randomId.concat(getSafeExt(file.mimetype))), contentType: (_req, file, cb) => cb(null, file.mimetype) }) }).single('file'); +const deleteS3 = (file) => + new Promise((resolve, reject) => + s3.deleteObject({ Bucket: s3bucket, Key: file.randomId.concat(getSafeExt(file.mimetype)) }).promise().then(resolve).catch(reject)); + const uploadLocal = multer({ storage: multer.diskStorage({ destination: !saveWithDate ? diskFilePath : (_req, _file, cb) => { @@ -39,7 +44,4 @@ const uploadLocal = multer({ }) }).single('file'); -module.exports = { uploadLocal, uploadS3 }; - -// This deletes everything from the Bucket -//s3.listObjects({ Bucket: s3bucket }, (err, data) => err ? console.error(err) : data['Contents'].forEach((obj) => s3.deleteObject({ Bucket: s3bucket, Key: obj['Key'] }, (err, data) => err ? console.log(err) : console.log(data)))); +module.exports = { uploadLocal, uploadS3, deleteS3 }; diff --git a/utils.js b/utils.js index beab62d..2bec395 100755 --- a/utils.js +++ b/utils.js @@ -45,8 +45,13 @@ module.exports = { .then((f2) => f2.body.pipe(fs.createWriteStream(Path.join(__dirname, 'uploads/', file.originalname)).on('close', () => resolve()))) .catch(reject)), getS3url, + getSafeExt } function getS3url(s3key, type) { - return `https://${s3bucket}.${s3endpoint}/${s3key}${type.includes('video') ? '.mp4' : type.includes('gif') ? '.gif' : ''}`; + return `https://${s3bucket}.${s3endpoint}/${s3key}${getSafeExt(type)}`; +} + +function getSafeExt(type) { + return type.includes('video') ? '.mp4' : type.includes('gif') ? '.gif' : ''; }