feat: add whole JSON size validation and check for storage usage

This commit is contained in:
lefuturiste 2020-07-29 20:12:23 +00:00
parent fefbf15f5e
commit 2b1e35e55f
5 changed files with 72 additions and 2 deletions

View file

@ -1,3 +1,4 @@
import Utils from './Utils'
import aws from 'aws-sdk' import aws from 'aws-sdk'
import multer from 'multer' import multer from 'multer'
import multerS3 from 'multer-s3' import multerS3 from 'multer-s3'
@ -79,4 +80,30 @@ export default class MediaService {
static getMediaBaseUrl() { static getMediaBaseUrl() {
return process.env.S3_BASE_URL == null ? '___BUCKET_BASE_URL_NOT_FOUND_ENV_VAR_ISSUE___' : process.env.S3_BASE_URL return process.env.S3_BASE_URL == null ? '___BUCKET_BASE_URL_NOT_FOUND_ENV_VAR_ISSUE___' : process.env.S3_BASE_URL
} }
static getSizeLimit(): number {
//return 1073741824 for 1 GB
return 1000000000
}
// will return the sum of all the medias size used by the proposedVersion of the organization
static computeSize(version: any) {
// if (!Utils.isUsable(org, 'proposedVersion')) {
// return 0
// }
// let version: any = org.proposedVersion
let size: number = 0
if (Utils.isUsable(version, 'thumbnail.size')) {
size += version.thumbnail.size
}
if (Utils.isUsable(version, 'cover.size')) {
size += version.cover.size
}
if (Utils.isUsable(version, 'gallery') && Array.isArray(version.gallery)) {
version.gallery.forEach((media: any) => {
size += media.size
})
}
return size
}
} }

View file

@ -91,6 +91,7 @@ let main = async () => {
app.use('/delegate', express.Router() app.use('/delegate', express.Router()
.use(DelegateAuthMiddleware.handle) .use(DelegateAuthMiddleware.handle)
.get('/', DelegateController.get) .get('/', DelegateController.get)
.get('/size', DelegateController.getCurrentSize)
//.post('/test', DelegateController.test) //.post('/test', DelegateController.test)
.put('/', DelegateController.update) .put('/', DelegateController.update)
.post('/submit', DelegateController.submit) .post('/submit', DelegateController.submit)

View file

@ -33,7 +33,7 @@ export default class AdminOrganizationController {
_note: 'Invalid import data or csv' _note: 'Invalid import data or csv'
}) })
} }
let promises = parsed.data.map(d => { let promises = parsed.data.map((d: any) => {
return AdminOrganizationController.storeUniversal( return AdminOrganizationController.storeUniversal(
d[0], d[0],
d[1].replace(' ', ''), d[1].replace(' ', ''),

View file

@ -21,6 +21,17 @@ export default class DelegateController {
}) })
} }
static getCurrentSize(req: express.Request, res: express.Response) {
res.json({
success: true,
data: {
size: MediaService.computeSize(res.locals.organization.proposedVersion),
max: MediaService.getSizeLimit()
}
})
}
// static test(req: express.Request, res: express.Response) { // static test(req: express.Request, res: express.Response) {
// res.json({ success: true, body: req.body, organization: res.locals.organization }) // res.json({ success: true, body: req.body, organization: res.locals.organization })
// } // }
@ -103,6 +114,14 @@ export default class DelegateController {
proposedVersion.pricing = [] proposedVersion.pricing = []
} }
// just before updating the whole organization, we want to check the size of the proposedVersion JSON String, just in case it is too large
if (JSON.stringify(proposedVersion).length > 10000) {
return res.status(413).json({
success: false,
errors: [{ code: 'too-large', message: 'The proposedVersion object that you are trying to update is too long, we cannot handle it' }]
})
}
Organization.updateOne({ _id: organization._id }, { Organization.updateOne({ _id: organization._id }, {
proposedVersion, proposedVersion,
updatedAt: new Date() updatedAt: new Date()
@ -173,8 +192,29 @@ export default class DelegateController {
}).catch(err => res.status(400).json({ success: false, errors: err.errors !== undefined ? err.errors : err })) }).catch(err => res.status(400).json({ success: false, errors: err.errors !== undefined ? err.errors : err }))
} }
static verifySize(req: express.Request, res: express.Response, next: any) {
// before starting the upload process, we want to make sure that this organization is not exeeding the size limit for all the file
let currentSize = MediaService.computeSize(res.locals.organization.proposedVersion)
if (currentSize >= MediaService.getSizeLimit()) {
return res
.status(413)
.json({
success: false,
errors: [
{ code: 'quota-exeeded', message: 'We cannot accept this file because you already reached the maximum storage capacity for this organization' }
],
data: {
currentSize,
maxSize: MediaService.getSizeLimit()
}
})
}
next()
}
static uploadThumbnail(): express.RequestHandler[] { static uploadThumbnail(): express.RequestHandler[] {
return [ return [
DelegateController.verifySize,
MediaService.multer('thumbnail'), MediaService.multer('thumbnail'),
(req: express.Request, res: express.Response) => { (req: express.Request, res: express.Response) => {
// if the current thumbnail is defined AND the published thumnbnail is defined AND the current thumbnail is different from the published one // if the current thumbnail is defined AND the published thumnbnail is defined AND the current thumbnail is different from the published one
@ -202,6 +242,7 @@ export default class DelegateController {
static uploadCover(): express.RequestHandler[] { static uploadCover(): express.RequestHandler[] {
return [ return [
DelegateController.verifySize,
MediaService.multer('cover'), MediaService.multer('cover'),
(req: express.Request, res: express.Response) => { (req: express.Request, res: express.Response) => {
// if the current thumbnail is defined AND the published thumnbnail is defined AND the current thumbnail is different from the published one // if the current thumbnail is defined AND the published thumnbnail is defined AND the current thumbnail is different from the published one
@ -226,6 +267,7 @@ export default class DelegateController {
static uploadMedias(): express.RequestHandler[] { static uploadMedias(): express.RequestHandler[] {
return [ return [
DelegateController.verifySize,
MediaService.multer('media', true), MediaService.multer('media', true),
(req: express.Request, res: express.Response) => { (req: express.Request, res: express.Response) => {
let proposedVersion: any = res.locals.organization.proposedVersion let proposedVersion: any = res.locals.organization.proposedVersion

View file

@ -32,7 +32,7 @@ const email = {
lowercase: true, lowercase: true,
unique: true, unique: true,
validate: { validate: {
validator: function(v) { validator: function(v: string) {
return /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(v); return /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(v);
}, },
message: "Invalid email" message: "Invalid email"