From f9bd9ed8b18fa8b175a8a7b1ad2b4aaa44be53c0 Mon Sep 17 00:00:00 2001 From: Juan Miguel Sanchez Mola Date: Thu, 14 Nov 2024 15:36:53 -0400 Subject: [PATCH 1/7] Updates --- rair-node/bin/api/files/files.Controller.js | 18 +++++++++++++----- rair-node/bin/schemas/files.js | 20 ++++++++++++++++++++ rair-node/bin/schemas/index.js | 9 ++++----- rair-node/bin/schemas/removeMedia.js | 7 ------- rair-node/bin/schemas/updateMedia.js | 11 ----------- 5 files changed, 37 insertions(+), 28 deletions(-) create mode 100644 rair-node/bin/schemas/files.js delete mode 100644 rair-node/bin/schemas/removeMedia.js delete mode 100644 rair-node/bin/schemas/updateMedia.js diff --git a/rair-node/bin/api/files/files.Controller.js b/rair-node/bin/api/files/files.Controller.js index be7b28578..0065e6528 100644 --- a/rair-node/bin/api/files/files.Controller.js +++ b/rair-node/bin/api/files/files.Controller.js @@ -23,18 +23,18 @@ const { File } = require('../../models'); const router = express.Router(); router.patch( - '/update/:mediaId', + '/update/:id', requireUserSession, - validation(['removeMedia'], 'params'), + validation(['fileId'], 'params'), validation(['updateMedia'], 'body'), isOwner(File), updateMedia, ); router.delete( - '/remove/:mediaId', + '/remove/:id', requireUserSession, - validation(['removeMedia'], 'params'), + validation(['fileId'], 'params'), isOwner(File), deleteMedia, ); @@ -70,15 +70,23 @@ router.get( validation(['dbId'], 'params'), getFilesForToken, ); -router.get('/:id/unlocks', getFileAndOffer); +router.get( + '/:id/unlocks', + validation(['fileId'], 'params'), + getFileAndOffer, +); router.post( '/:id/unlocks', + validation(['fileId'], 'params'), + validation(['offerArray'], 'body'), requireUserSession, isFileOwner, connectFileAndOffer, ); router.delete( '/:id/unlocks', + validation(['fileId'], 'params'), + validation(['offerArray'], 'body'), requireUserSession, isFileOwner, removeFileAndOffer, diff --git a/rair-node/bin/schemas/files.js b/rair-node/bin/schemas/files.js new file mode 100644 index 000000000..8210e9b6c --- /dev/null +++ b/rair-node/bin/schemas/files.js @@ -0,0 +1,20 @@ +const Joi = require('joi'); +const { mongoId } = require('./reusableCustomTypes'); + +module.exports = { + updateMedia: () => ({ + title: Joi.string().min(1).max(30), + description: Joi.string().min(1).max(300), + contract: Joi.string(), + product: Joi.string(), + offer: Joi.array().items(mongoId), + category: Joi.string().min(1), + demo: Joi.boolean(), + }), + offerArray: () => ({ + offers: Joi.array().items(mongoId).required(), + }), + singleOffer: () => ({ + offer: mongoId.required(), + }), +}; diff --git a/rair-node/bin/schemas/index.js b/rair-node/bin/schemas/index.js index f63f43568..f64070700 100644 --- a/rair-node/bin/schemas/index.js +++ b/rair-node/bin/schemas/index.js @@ -1,4 +1,5 @@ const admin = require('./admin'); +const databaseSchemas = require('./databaseSchemas'); const addMedia = require('./addMedia'); const authentication = require('./authentication'); const createContract = require('./createContract'); @@ -7,8 +8,7 @@ const getChallenge = require('./getChallenge'); const getChallengeV2 = require('./getChallengeV2'); const filterAndSort = require('./filterAndSort'); const getToken = require('./getToken'); -const removeMedia = require('./removeMedia'); -const updateMedia = require('./updateMedia'); +const { updateMedia, offerArray } = require('./files'); const stream = require('./stream'); const uploadVideo = require('./uploadVideo'); const uploadVideoFile = require('./uploadVideoFile'); @@ -70,7 +70,6 @@ module.exports = { getChallenge, filterAndSort, getToken, - removeMedia, stream, uploadVideo, uploadVideoFile, @@ -85,6 +84,7 @@ module.exports = { // Media files updateMedia, + offerArray, analyticsParams, analyticsQuery, @@ -115,9 +115,8 @@ module.exports = { // favorites createFavoriteToken, - // V2 Validation // Database schemas (using the Entity helper) - ...require('./databaseSchemas'), + ...databaseSchemas, // Media schemas validateMediaData, addFileFromMediaService, diff --git a/rair-node/bin/schemas/removeMedia.js b/rair-node/bin/schemas/removeMedia.js deleted file mode 100644 index 7c04c267b..000000000 --- a/rair-node/bin/schemas/removeMedia.js +++ /dev/null @@ -1,7 +0,0 @@ -const Joi = require('joi'); -const { customValidator } = require('./helpers'); - -module.exports = () => ({ - mediaId: Joi.custom(customValidator({ min: 3, max: 50 })) - .required(), -}); diff --git a/rair-node/bin/schemas/updateMedia.js b/rair-node/bin/schemas/updateMedia.js deleted file mode 100644 index 7b7aa2b52..000000000 --- a/rair-node/bin/schemas/updateMedia.js +++ /dev/null @@ -1,11 +0,0 @@ -const Joi = require('joi'); - -module.exports = () => ({ - title: Joi.string().min(1).max(30), - description: Joi.string().min(1).max(300), - contract: Joi.string(), - product: Joi.string(), - offer: Joi.array().items(Joi.string()), - category: Joi.string().min(1), - demo: Joi.boolean(), -}); From 71c5c9f77075990f097ef90703885089781915a9 Mon Sep 17 00:00:00 2001 From: Juan Miguel Sanchez Mola Date: Fri, 15 Nov 2024 10:12:15 -0400 Subject: [PATCH 2/7] Fix delete file --- rair-node/bin/api/files/files.Service.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/rair-node/bin/api/files/files.Service.js b/rair-node/bin/api/files/files.Service.js index cec1bc301..0217b3bae 100644 --- a/rair-node/bin/api/files/files.Service.js +++ b/rair-node/bin/api/files/files.Service.js @@ -176,32 +176,32 @@ module.exports = { }, deleteMedia: async (req, res, next) => { try { - const { mediaId } = req.params; + const { id } = req.params; - const fileData = await File.findOne({ _id: mediaId }); + const fileData = await File.findOne({ _id: id }); let deleteResponse; if (!fileData.storage) { - log.error(`Can't tell where media ID ${mediaId} is stored, will not unpin/delete from storage, just from DB`); + log.error(`Can't tell where media ID ${id} is stored, will not unpin/delete from storage, just from DB`); deleteResponse = { success: true }; } else { switch (fileData.storage) { case 'gcp': - deleteResponse = await gcp.removeFile(config.gcp.videoBucketName, mediaId); + deleteResponse = await gcp.removeFile(config.gcp.videoBucketName, id); break; case 'ipfs': - deleteResponse = await removePin(mediaId); + deleteResponse = await removePin(id); break; default: - log.error(`Unknown storage type for media ID ${mediaId} : ${fileData.storage}`); + log.error(`Unknown storage type for media ID ${id} : ${fileData.storage}`); break; } } if (deleteResponse.success) { - await File.deleteOne({ _id: mediaId }); - await Unlock.deleteMany({ file: mediaId }); - log.info(`File with ID: ${mediaId}, was removed from DB.`); + await File.deleteOne({ _id: id }); + await Unlock.deleteMany({ file: id }); + log.info(`File with ID: ${id}, was removed from DB.`); res.json({ success: true, }); From 2ebdc87110cd551286c876ad52f7f17dbfcf6d3e Mon Sep 17 00:00:00 2001 From: Juan Miguel Sanchez Mola Date: Fri, 15 Nov 2024 10:17:40 -0400 Subject: [PATCH 3/7] Only alphanumeric characters --- rair-node/bin/schemas/commonApiSchemas.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rair-node/bin/schemas/commonApiSchemas.js b/rair-node/bin/schemas/commonApiSchemas.js index eef2b6ab1..1815b66d1 100644 --- a/rair-node/bin/schemas/commonApiSchemas.js +++ b/rair-node/bin/schemas/commonApiSchemas.js @@ -13,7 +13,7 @@ module.exports = { ids: Joi.array().items(mongoId), }), fileId: () => ({ - id: Joi.string().required(), + id: Joi.string().alphanum().required(), }), productId: () => ({ productId: mongoId, From 60b7fa2dc103d782e1b6fdb5cb3c73892595e95f Mon Sep 17 00:00:00 2001 From: Juan Miguel Sanchez Mola Date: Fri, 15 Nov 2024 10:35:02 -0400 Subject: [PATCH 4/7] Fix delete offer unlock --- rair-node/bin/api/files/files.Controller.js | 2 +- rair-node/bin/schemas/index.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/rair-node/bin/api/files/files.Controller.js b/rair-node/bin/api/files/files.Controller.js index 0065e6528..029fde3e6 100644 --- a/rair-node/bin/api/files/files.Controller.js +++ b/rair-node/bin/api/files/files.Controller.js @@ -86,7 +86,7 @@ router.post( router.delete( '/:id/unlocks', validation(['fileId'], 'params'), - validation(['offerArray'], 'body'), + validation(['singleOffer'], 'body'), requireUserSession, isFileOwner, removeFileAndOffer, diff --git a/rair-node/bin/schemas/index.js b/rair-node/bin/schemas/index.js index f64070700..ed7db7426 100644 --- a/rair-node/bin/schemas/index.js +++ b/rair-node/bin/schemas/index.js @@ -8,7 +8,7 @@ const getChallenge = require('./getChallenge'); const getChallengeV2 = require('./getChallengeV2'); const filterAndSort = require('./filterAndSort'); const getToken = require('./getToken'); -const { updateMedia, offerArray } = require('./files'); +const { updateMedia, offerArray, singleOffer } = require('./files'); const stream = require('./stream'); const uploadVideo = require('./uploadVideo'); const uploadVideoFile = require('./uploadVideoFile'); @@ -85,6 +85,7 @@ module.exports = { // Media files updateMedia, offerArray, + singleOffer, analyticsParams, analyticsQuery, From af8a158a9f02a37a1387fd82ec98c7d8feb9a31b Mon Sep 17 00:00:00 2001 From: Juan Miguel Sanchez Mola Date: Fri, 15 Nov 2024 10:41:05 -0400 Subject: [PATCH 5/7] Fix media patch --- rair-node/bin/api/files/files.Service.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rair-node/bin/api/files/files.Service.js b/rair-node/bin/api/files/files.Service.js index 0217b3bae..4e419afcb 100644 --- a/rair-node/bin/api/files/files.Service.js +++ b/rair-node/bin/api/files/files.Service.js @@ -218,7 +218,7 @@ module.exports = { }, updateMedia: async (req, res, next) => { try { - const { mediaId } = req.params; + const { id } = req.params; // eslint-disable-next-line no-unused-vars const { _id, ...cleanBody } = req.body; @@ -229,7 +229,7 @@ module.exports = { req.body = bodyForNonAdmins; } - const updateRes = await File.updateOne({ _id: mediaId }, cleanBody); + const updateRes = await File.updateOne({ _id: id }, cleanBody); if (!updateRes.acknowledged) { return res.json({ success: false, message: 'An error has ocurred' }); @@ -237,7 +237,7 @@ module.exports = { if (updateRes.matchedCount === 1 && updateRes.modifiedCount === 0) { return res.json({ success: false, message: 'Nothing to update' }); } - log.info(`File with ID: ${mediaId}, was updated on DB.`); + log.info(`File with ID: ${id}, was updated on DB.`); return res.json({ success: true }); } catch (err) { return next(err); From b65f945aa2322f4f729b84e67379a6453d66d201 Mon Sep 17 00:00:00 2001 From: Juan Miguel Sanchez Mola Date: Fri, 15 Nov 2024 11:50:55 -0400 Subject: [PATCH 6/7] Total count for users --- rair-node/bin/api/users/users.Service.js | 22 ++++++++++++++++++---- rair-node/bin/index.js | 1 - 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/rair-node/bin/api/users/users.Service.js b/rair-node/bin/api/users/users.Service.js index 0f0e78f30..b5b566bef 100644 --- a/rair-node/bin/api/users/users.Service.js +++ b/rair-node/bin/api/users/users.Service.js @@ -89,12 +89,26 @@ exports.listUsers = async (req, res, next) => { } queriedFields[field] = 1; }); - const list = await User.find({}, queriedFields) - .skip(pageNum * itemsPerPage) - .limit(itemsPerPage); + const [result] = await User.aggregate([ + { + $project: queriedFields, + }, + { + $facet: { + list: [ + { $skip: pageNum * itemsPerPage }, + { $limit: itemsPerPage }, + ], + count: [ + { $count: 'total' }, + ], + }, + }, + ]); return res.json({ success: true, - data: list, + data: result.list, + totalCount: result?.count?.[0]?.total || 0, }); } catch (err) { return next(err); diff --git a/rair-node/bin/index.js b/rair-node/bin/index.js index e531693ed..80cc298e4 100644 --- a/rair-node/bin/index.js +++ b/rair-node/bin/index.js @@ -55,7 +55,6 @@ async function main() { }, }); - const hls = await StartHLS(); const limiter = rateLimit({ From 4a33341583f6857cf5144c606093797c74f4b1b2 Mon Sep 17 00:00:00 2001 From: Juan Miguel Sanchez Mola Date: Fri, 15 Nov 2024 12:11:54 -0400 Subject: [PATCH 7/7] Rate limit env --- docker-compose-prod.yaml | 1 + docker-compose-web.yml | 1 + docker-compose.local-new.yml | 1 + docker-compose.local-ssl-with_certbot.yml | 1 + docker-compose.local-ssl-without_certbot.yml | 1 + docker-compose.yml | 1 + rair-node/bin/index.js | 3 +-- rair-node/bin/schemas/commonApiSchemas.js | 2 +- 8 files changed, 8 insertions(+), 3 deletions(-) diff --git a/docker-compose-prod.yaml b/docker-compose-prod.yaml index ec280b3ce..73e2eedf2 100644 --- a/docker-compose-prod.yaml +++ b/docker-compose-prod.yaml @@ -67,6 +67,7 @@ services: AWS_SECRET_ACCESS_KEY: ${filebase_secret_access_key} FILEBASE_BUCKET: ${filebase_bucket} YOTI_CLIENT_ID: ${yoti_client_id} + RATE_LIMIT_MINUTE: ${rate_limit_minute} ports: - 3000:3000 - 5000:5000 diff --git a/docker-compose-web.yml b/docker-compose-web.yml index 8c886be28..b55244dfd 100644 --- a/docker-compose-web.yml +++ b/docker-compose-web.yml @@ -64,6 +64,7 @@ services: AWS_SECRET_ACCESS_KEY: ${filebase_secret_access_key} FILEBASE_BUCKET: ${filebase_bucket} YOTI_CLIENT_ID: ${yoti_client_id} + RATE_LIMIT_MINUTE: ${rate_limit_minute} ports: - 3000:3000 - 5000:5000 diff --git a/docker-compose.local-new.yml b/docker-compose.local-new.yml index 6008aabb2..c1459c5e9 100644 --- a/docker-compose.local-new.yml +++ b/docker-compose.local-new.yml @@ -53,6 +53,7 @@ services: AWS_SECRET_ACCESS_KEY: ${filebase_secret_access_key} FILEBASE_BUCKET: ${filebase_bucket} YOTI_CLIENT_ID: ${yoti_client_id} + RATE_LIMIT_MINUTE: ${rate_limit_minute} ports: - 3000:3000 - 5000:5000 diff --git a/docker-compose.local-ssl-with_certbot.yml b/docker-compose.local-ssl-with_certbot.yml index 089089e4f..1fbb09c5d 100644 --- a/docker-compose.local-ssl-with_certbot.yml +++ b/docker-compose.local-ssl-with_certbot.yml @@ -75,6 +75,7 @@ services: AWS_SECRET_ACCESS_KEY: ${filebase_secret_access_key} FILEBASE_BUCKET: ${filebase_bucket} YOTI_CLIENT_ID: ${yoti_client_id} + RATE_LIMIT_MINUTE: ${rate_limit_minute} ports: - 3000:3000 - 5000:5000 diff --git a/docker-compose.local-ssl-without_certbot.yml b/docker-compose.local-ssl-without_certbot.yml index a79bccf4c..538d4acc2 100644 --- a/docker-compose.local-ssl-without_certbot.yml +++ b/docker-compose.local-ssl-without_certbot.yml @@ -66,6 +66,7 @@ services: AWS_SECRET_ACCESS_KEY: ${filebase_secret_access_key} FILEBASE_BUCKET: ${filebase_bucket} YOTI_CLIENT_ID: ${yoti_client_id} + RATE_LIMIT_MINUTE: ${rate_limit_minute} ports: - 3000:3000 - 5000:5000 diff --git a/docker-compose.yml b/docker-compose.yml index 67d82bddb..e9b839a69 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -66,6 +66,7 @@ services: AWS_SECRET_ACCESS_KEY: ${filebase_secret_access_key} FILEBASE_BUCKET: ${filebase_bucket} YOTI_CLIENT_ID: ${yoti_client_id} + RATE_LIMIT_MINUTE: ${rate_limit_minute} ports: - 3000:3000 - 5000:5000 diff --git a/rair-node/bin/index.js b/rair-node/bin/index.js index 80cc298e4..3aea4a34b 100644 --- a/rair-node/bin/index.js +++ b/rair-node/bin/index.js @@ -5,7 +5,6 @@ const cookieParser = require('cookie-parser'); const { nanoid } = require('nanoid'); const fs = require('fs'); const cors = require('cors'); -const lusca = require('lusca'); const { createServer } = require('http'); const { Server } = require('socket.io'); const morgan = require('morgan'); @@ -59,7 +58,7 @@ async function main() { const limiter = rateLimit({ windowMs: 60 * 1000, // 1 minute - limit: 500, + limit: process.env.RATE_LIMIT_MINUTE || 500, standardHeaders: 'draft-7', // draft-6: `RateLimit-*` headers; draft-7: combined `RateLimit` header legacyHeaders: false, // Disable the `X-RateLimit-*` headers. }); diff --git a/rair-node/bin/schemas/commonApiSchemas.js b/rair-node/bin/schemas/commonApiSchemas.js index 1815b66d1..eef2b6ab1 100644 --- a/rair-node/bin/schemas/commonApiSchemas.js +++ b/rair-node/bin/schemas/commonApiSchemas.js @@ -13,7 +13,7 @@ module.exports = { ids: Joi.array().items(mongoId), }), fileId: () => ({ - id: Joi.string().alphanum().required(), + id: Joi.string().required(), }), productId: () => ({ productId: mongoId,