From 7ad1ae213b860275a4e912cc1d3972371effda9a Mon Sep 17 00:00:00 2001 From: Nevil Date: Wed, 13 Mar 2024 19:46:36 +0530 Subject: [PATCH 01/19] fixed an issue with index.js --- src/middlewares/validator.js | 5 ++- src/routes/index.js | 87 +++++++++++++++++++++++++++++++++--- 2 files changed, 85 insertions(+), 7 deletions(-) diff --git a/src/middlewares/validator.js b/src/middlewares/validator.js index 657baf27f..10e50282e 100644 --- a/src/middlewares/validator.js +++ b/src/middlewares/validator.js @@ -7,7 +7,10 @@ module.exports = (req, res, next) => { try { - require(`@validators/${req.params.version}/${req.params.controller}`)[req.params.method](req) + const version = (req.params.version.match(/^v\d+$/) || [])[0] // Match version like v1, v2, etc. + const controllerName = (req.params.controller.match(/^[a-zA-Z0-9_-]+$/) || [])[0] // Allow only alphanumeric characters, underscore, and hyphen + const method = (req.params.method.match(/^[a-zA-Z0-9]+$/) || [])[0] // Allow only alphanumeric characters + require(`@validators/${version}/${controllerName}`)[method](req) } catch {} next() } diff --git a/src/routes/index.js b/src/routes/index.js index 6e6928d31..55d2dd2a6 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -12,15 +12,92 @@ const expressValidator = require('express-validator') const fs = require('fs') const { elevateLog, correlationId } = require('elevate-logger') const logger = elevateLog.init() +const path = require('path') module.exports = (app) => { app.use(authenticator) app.use(pagination) app.use(expressValidator()) + async function getAllowedControllers(directoryPath) { + try { + const getAllFilesAndDirectories = (dir) => { + let filesAndDirectories = [] + fs.readdirSync(dir).forEach((item) => { + const itemPath = path.join(dir, item) + const stat = fs.statSync(itemPath) + if (stat.isDirectory()) { + filesAndDirectories.push({ + name: item, + type: 'directory', + path: itemPath, + }) + filesAndDirectories = filesAndDirectories.concat(getAllFilesAndDirectories(itemPath)) + } else { + filesAndDirectories.push({ + name: item, + type: 'file', + path: itemPath, + }) + } + }) + return filesAndDirectories + } + + const allFilesAndDirectories = getAllFilesAndDirectories(directoryPath) + const allowedControllers = allFilesAndDirectories + .filter((item) => item.type === 'file' && item.name.endsWith('.js')) + .map((item) => path.basename(item.name, '.js')) // Remove the ".js" extension + const allowedVersions = allFilesAndDirectories + .filter((item) => item.type === 'directory') + .map((item) => item.name) + + return { + allowedControllers, + allowedVersions, + } + } catch (err) { + console.error('Unable to scan directory:', err) + return { + allowedControllers: [], + directories: [], + } + } + } async function router(req, res, next) { let controllerResponse let validationError + const version = (req.params.version.match(/^v\d+$/) || [])[0] // Match version like v1, v2, etc. + const controllerName = (req.params.controller.match(/^[a-zA-Z0-9_-]+$/) || [])[0] // Allow only alphanumeric characters, underscore, and hyphen + const file = req.params.file ? (req.params.file.match(/^[a-zA-Z0-9_-]+$/) || [])[0] : null // Same validation as controller, or null if file is not provided + const method = (req.params.method.match(/^[a-zA-Z0-9]+$/) || [])[0] // Allow only alphanumeric characters + try { + if (!version || !controllerName || !method || (req.params.file && !file)) { + // Invalid input, return an error response + const error = new Error('Invalid Path') + error.statusCode = 400 + throw error + } + + const directoryPath = path.resolve(__dirname, '..', 'controllers') + + const { allowedControllers, allowedVersions } = await getAllowedControllers(directoryPath) + + // Validate version + if (!allowedVersions.includes(version)) { + const error = new Error('Invalid version.') + error.statusCode = 400 + throw error + } + // Validate controller + if (!allowedControllers.includes(controllerName)) { + const error = new Error('Invalid controller.') + error.statusCode = 400 + throw error + } + } catch (error) { + return next(error) + } /* Check for input validation error */ try { @@ -53,16 +130,14 @@ module.exports = (app) => { '.js' ) if (folderExists) { - controller = require(`@controllers/${req.params.version}/${req.params.controller}/${req.params.file}`) + controller = require(`@controllers/${version}/${controllerName}/${file}`) } else { - controller = require(`@controllers/${req.params.version}/${req.params.controller}`) + controller = require(`@controllers/${version}/${controllerName}`) } } else { - controller = require(`@controllers/${req.params.version}/${req.params.controller}`) + controller = require(`@controllers/${version}/${controllerName}`) } - controllerResponse = new controller()[req.params.method] - ? await new controller()[req.params.method](req) - : next() + controllerResponse = new controller()[method] ? await new controller()[method](req) : next() } catch (error) { // If controller or service throws some random error return next(error) From c5d225551db792569899acc09bb663059ae43f05 Mon Sep 17 00:00:00 2001 From: adithya_dinesh Date: Mon, 18 Mar 2024 14:41:16 +0530 Subject: [PATCH 02/19] Username Enumeration - generateOtp --- src/services/account.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/services/account.js b/src/services/account.js index c0ce8fbed..3c77fa6f6 100644 --- a/src/services/account.js +++ b/src/services/account.js @@ -639,10 +639,9 @@ module.exports = class AccountHelper { }, }) if (!userCredentials) - return responses.failureResponse({ - message: 'USER_DOESNOT_EXISTS', - statusCode: httpStatusCode.bad_request, - responseCode: 'CLIENT_ERROR', + return responses.successResponse({ + statusCode: httpStatusCode.ok, + message: 'OTP_SENT_SUCCESSFULLY', }) const user = await userQueries.findOne({ @@ -650,10 +649,9 @@ module.exports = class AccountHelper { organization_id: userCredentials.organization_id, }) if (!user) - return responses.failureResponse({ - message: 'USER_DOESNOT_EXISTS', - statusCode: httpStatusCode.bad_request, - responseCode: 'CLIENT_ERROR', + return responses.successResponse({ + statusCode: httpStatusCode.ok, + message: 'OTP_SENT_SUCCESSFULLY', }) const isPasswordSame = bcryptJs.compareSync(bodyData.password, userCredentials.password) From 195eb24187cb3fe4550786711a2c44c20a3c6144 Mon Sep 17 00:00:00 2001 From: sumanvpacewisdom Date: Tue, 19 Mar 2024 15:32:27 +0530 Subject: [PATCH 03/19] Audit Bug - 1148 , 1152 , 1153 --- src/constants/common.js | 2 +- src/envVariables.js | 4 ++-- src/locales/en.json | 4 +++- src/services/org-admin.js | 13 +++++++++++++ src/validators/v1/account.js | 20 ++++++++++++++++++-- src/validators/v1/admin.js | 10 +++++++++- 6 files changed, 46 insertions(+), 7 deletions(-) diff --git a/src/constants/common.js b/src/constants/common.js index 159efde6f..ce9011075 100644 --- a/src/constants/common.js +++ b/src/constants/common.js @@ -28,7 +28,7 @@ module.exports = { '/user/v1/user-role/default', ], notificationEmailType: 'email', - accessTokenExpiry: `${process.env.ACCESS_TOKEN_EXPIRY}d`, + accessTokenExpiry: process.env.ACCESS_TOKEN_EXPIRY, refreshTokenExpiry: `${process.env.REFRESH_TOKEN_EXPIRY}d`, refreshTokenExpiryInMs: Number(process.env.REFRESH_TOKEN_EXPIRY) * 24 * 60 * 60 * 1000, refreshTokenLimit: 3, diff --git a/src/envVariables.js b/src/envVariables.js index e5ad54689..b61ff67ae 100644 --- a/src/envVariables.js +++ b/src/envVariables.js @@ -96,11 +96,11 @@ let enviromentVariables = { optional: process.env.CLOUD_STORAGE === 'AZURE' ? false : true, }, ACCESS_TOKEN_EXPIRY: { - message: 'Required access token expiry in days', + message: 'Required access token expiry', optional: false, }, REFRESH_TOKEN_EXPIRY: { - message: 'Required refresh token expiry in days', + message: 'Required refresh token expiry', optional: false, }, API_DOC_URL: { diff --git a/src/locales/en.json b/src/locales/en.json index 9cba64a1a..b5dad36d7 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -113,5 +113,7 @@ "ROLES_HAS_EMPTY_LIST": "Empty roles list", "COLUMN_DOES_NOT_EXISTS": "Role column does not exists", "PERMISSION_DENIED": "You do not have the required permissions to access this resource. Please contact your administrator for assistance.", - "RELATED_ORG_REMOVAL_FAILED": "Requested organization not related the organization. Please check the values." + "RELATED_ORG_REMOVAL_FAILED": "Requested organization not related the organization. Please check the values.", + "INAVLID_ORG_ROLE_REQ": "Invalid organisation request" + } diff --git a/src/services/org-admin.js b/src/services/org-admin.js index 3b5d136bc..bd496d222 100644 --- a/src/services/org-admin.js +++ b/src/services/org-admin.js @@ -237,6 +237,19 @@ module.exports = class OrgAdminHelper { const requestId = bodyData.request_id delete bodyData.request_id + const requestDetail = await orgRoleReqQueries.requestDetails({ + id: requestId, + organization_id: tokenInformation.organization_id, + }) + + if (requestDetail.status !== common.REQUESTED_STATUS) { + return responses.failureResponse({ + message: 'INAVLID_ORG_ROLE_REQ', + statusCode: httpStatusCode.bad_request, + responseCode: 'CLIENT_ERROR', + }) + } + bodyData.handled_by = tokenInformation.id const rowsAffected = await orgRoleReqQueries.update( { id: requestId, organization_id: tokenInformation.organization_id }, diff --git a/src/validators/v1/account.js b/src/validators/v1/account.js index 449860c2d..260c05c98 100644 --- a/src/validators/v1/account.js +++ b/src/validators/v1/account.js @@ -25,7 +25,15 @@ module.exports = { .withMessage('email is invalid') .normalizeEmail({ gmail_remove_dots: false }) - req.checkBody('password').trim().notEmpty().withMessage('password field is empty') + req.checkBody('password') + .notEmpty() + .withMessage('Password field is empty') + .matches(/^(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*()_+{}|:"<>?~`\-=[\];',.\/])[^ ]{10,}$/) + .withMessage( + 'Password must have at least one uppercase letter, one number, one special character, and be at least 10 characters long' + ) + .custom((value) => !/\s/.test(value)) + .withMessage('Password cannot contain spaces') if (req.body.role) { req.checkBody('role').trim().not().isIn([common.ADMIN_ROLE]).withMessage("User does't have admin access") @@ -64,7 +72,15 @@ module.exports = { resetPassword: (req) => { req.checkBody('email').notEmpty().withMessage('email field is empty').isEmail().withMessage('email is invalid') - req.checkBody('password').notEmpty().withMessage('password field is empty') + req.checkBody('password') + .notEmpty() + .withMessage('Password field is empty') + .matches(/^(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*()_+{}|:"<>?~`\-=[\];',.\/])[^ ]{10,}$/) + .withMessage( + 'Password must have at least one uppercase letter, one number, one special character, and be at least 10 characters long' + ) + .custom((value) => !/\s/.test(value)) + .withMessage('Password cannot contain spaces') req.checkBody('otp') .notEmpty() diff --git a/src/validators/v1/admin.js b/src/validators/v1/admin.js index 575be9190..75ffdbc89 100644 --- a/src/validators/v1/admin.js +++ b/src/validators/v1/admin.js @@ -27,7 +27,15 @@ module.exports = { .withMessage('email is invalid') .normalizeEmail() - req.checkBody('password').trim().notEmpty().withMessage('password field is empty') + req.checkBody('password') + .notEmpty() + .withMessage('Password field is empty') + .matches(/^(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*()_+{}|:"<>?~`\-=[\];',.\/])[^ ]{10,}$/) + .withMessage( + 'Password must have at least one uppercase letter, one number, one special character, and be at least 10 characters long' + ) + .custom((value) => !/\s/.test(value)) + .withMessage('Password cannot contain spaces') }, login: (req) => { From 861c2a0afacfa58b2f05fa57735e415c9319f5a8 Mon Sep 17 00:00:00 2001 From: vishnu Date: Tue, 19 Mar 2024 16:18:40 +0530 Subject: [PATCH 04/19] 1142 -security fix, downloadableUrl API --- src/.env.sample | 3 +++ src/envVariables.js | 5 +++++ src/generics/utils.js | 3 ++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/.env.sample b/src/.env.sample index ad7a7da79..858787335 100644 --- a/src/.env.sample +++ b/src/.env.sample @@ -167,3 +167,6 @@ GENERIC_INVITATION_EMAIL_TEMPLATE_CODE=generic_invite # Allowed host by CORS ALLOWED_HOST = "http://examplDomain.com" + +# Downloadabale url exipres after +DOWNLOAD_URL_EXPIRATION_DURATION = 120000 \ No newline at end of file diff --git a/src/envVariables.js b/src/envVariables.js index e5ad54689..5fc0ce707 100644 --- a/src/envVariables.js +++ b/src/envVariables.js @@ -237,6 +237,11 @@ let enviromentVariables = { optional: true, default: '*', }, + DOWNLOAD_URL_EXPIRATION_DURATION: { + message: 'Required downloadable url expiration time', + optional: true, + default: 3600000, + }, } let success = true diff --git a/src/generics/utils.js b/src/generics/utils.js index 7a57f1fc8..2e45d706f 100644 --- a/src/generics/utils.js +++ b/src/generics/utils.js @@ -53,8 +53,9 @@ const getDownloadableUrl = async (imgPath) => { bucketName: process.env.DEFAULT_GCP_BUCKET_NAME, gcpProjectId: process.env.GCP_PROJECT_ID, gcpJsonFilePath: path.join(__dirname, '../', process.env.GCP_PATH), + expiry: Date.now() + parseFloat(process.env.DOWNLOAD_URL_EXPIRATION_DURATION), } - imgPath = await GcpFileHelper.getDownloadableUrl(options) + imgPath = await GcpFileHelper.getSignedDownloadableUrl(options) } else if (process.env.CLOUD_STORAGE === 'AWS') { const options = { destFilePath: imgPath, From 0e825a01ece75029fa87859adbee2f6785e83448 Mon Sep 17 00:00:00 2001 From: vishnu Date: Tue, 19 Mar 2024 16:24:39 +0530 Subject: [PATCH 05/19] package version updated --- src/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/package.json b/src/package.json index c6da7f3ee..39f87028e 100644 --- a/src/package.json +++ b/src/package.json @@ -37,7 +37,7 @@ "crypto": "^1.0.1", "csvtojson": "^2.0.10", "dotenv": "^10.0.0", - "elevate-cloud-storage": "2.0.0", + "elevate-cloud-storage": "2.6.1", "elevate-encryption": "^1.0.1", "elevate-logger": "^3.1.0", "elevate-node-cache": "^1.0.6", From cfe344da767dc54e43a83bc98ea9d1165c5fca65 Mon Sep 17 00:00:00 2001 From: adithya_dinesh Date: Tue, 19 Mar 2024 23:04:08 +0530 Subject: [PATCH 06/19] blacklisting update --- src/constants/blacklistConfig.js | 385 +++++++++++++++++++ src/validators/common.js | 3 + src/validators/v1/account.js | 32 ++ src/validators/v1/admin.js | 6 + src/validators/v1/entity-type.js | 5 +- src/validators/v1/entity.js | 4 + src/validators/v1/form.js | 4 + src/validators/v1/modules.js | 4 + src/validators/v1/notification.js | 6 +- src/validators/v1/org-admin.js | 4 + src/validators/v1/organization.js | 6 +- src/validators/v1/permissions.js | 5 +- src/validators/v1/role-permission-mapping.js | 4 + src/validators/v1/user-role.js | 4 + src/validators/v1/user.js | 4 +- 15 files changed, 470 insertions(+), 6 deletions(-) create mode 100644 src/constants/blacklistConfig.js create mode 100644 src/validators/common.js diff --git a/src/constants/blacklistConfig.js b/src/constants/blacklistConfig.js new file mode 100644 index 000000000..72c39e26f --- /dev/null +++ b/src/constants/blacklistConfig.js @@ -0,0 +1,385 @@ +const account = { + create: ['id', 'last_logged_in_at', 'has_accepted_terms_and_conditions', 'refresh_tokens', 'organization_id'], + login: [ + 'id', + 'email_verified', + 'name', + 'gender', + 'location', + 'about', + 'share_link', + 'status', + 'image', + 'last_logged_in_at', + 'has_accepted_terms_and_conditions', + 'refresh_tokens', + 'languages', + 'preferred_language', + 'organization_id', + 'roles', + 'custom_entity_text', + 'meta', + ], + logout: [ + 'id', + 'email', + 'email_verified', + 'name', + 'password', + 'gender', + 'location', + 'about', + 'share_link', + 'status', + 'image', + 'last_logged_in_at', + 'has_accepted_terms_and_conditions', + 'languages', + 'preferred_language', + 'organization_id', + 'roles', + 'custom_entity_text', + 'meta', + ], + generateToken: [ + 'id', + 'email', + 'email_verified', + 'name', + 'password', + 'gender', + 'location', + 'about', + 'share_link', + 'status', + 'image', + 'last_logged_in_at', + 'has_accepted_terms_and_conditions', + 'languages', + 'preferred_language', + 'organization_id', + 'roles', + 'custom_entity_text', + 'meta', + ], + generateOtp: [ + 'id', + 'email_verified', + 'name', + 'gender', + 'location', + 'about', + 'share_link', + 'status', + 'image', + 'last_logged_in_at', + 'has_accepted_terms_and_conditions', + 'languages', + 'preferred_language', + 'organization_id', + 'roles', + 'custom_entity_text', + 'meta', + ], + registrationOtp: [ + 'id', + 'email_verified', + 'name', + 'gender', + 'location', + 'about', + 'share_link', + 'status', + 'image', + 'last_logged_in_at', + 'has_accepted_terms_and_conditions', + 'languages', + 'preferred_language', + 'organization_id', + 'roles', + 'custom_entity_text', + 'meta', + ], + resetPassword: [ + 'id', + 'email_verified', + 'name', + 'gender', + 'location', + 'about', + 'share_link', + 'status', + 'image', + 'last_logged_in_at', + 'has_accepted_terms_and_conditions', + 'refresh_tokens', + 'languages', + 'preferred_language', + 'organization_id', + 'roles', + 'custom_entity_text', + 'meta', + ], + changeRole: [ + 'id', + 'email_verified', + 'name', + 'password', + 'gender', + 'location', + 'about', + 'share_link', + 'status', + 'image', + 'last_logged_in_at', + 'has_accepted_terms_and_conditions', + 'refresh_tokens', + 'languages', + 'preferred_language', + 'organization_id', + 'custom_entity_text', + 'meta', + ], +} +const admin = { + create: [ + 'id', + 'email_verified', + 'gender', + 'location', + 'about', + 'share_link', + 'status', + 'image', + 'last_logged_in_at', + 'has_accepted_terms_and_conditions', + 'refresh_tokens', + 'languages', + 'preferred_language', + 'organization_id', + 'roles', + 'custom_entity_text', + 'meta', + ], + login: [ + 'id', + 'email_verified', + 'gender', + 'location', + 'about', + 'share_link', + 'status', + 'image', + 'last_logged_in_at', + 'has_accepted_terms_and_conditions', + 'refresh_tokens', + 'languages', + 'preferred_language', + 'organization_id', + 'roles', + 'custom_entity_text', + 'meta', + ], + addOrgAdmin: [ + 'id', + 'email_verified', + 'gender', + 'location', + 'about', + 'password', + 'share_link', + 'status', + 'image', + 'last_logged_in_at', + 'has_accepted_terms_and_conditions', + 'refresh_tokens', + 'languages', + 'preferred_language', + 'roles', + 'custom_entity_text', + 'meta', + ], + deactivateUser: [ + 'email_verified', + 'gender', + 'location', + 'about', + 'password', + 'share_link', + 'status', + 'image', + 'last_logged_in_at', + 'has_accepted_terms_and_conditions', + 'refresh_tokens', + 'languages', + 'preferred_language', + 'organization_id', + 'roles', + 'custom_entity_text', + 'meta', + ], +} +const entityType = { + create: [ + 'id', + 'status', + 'created_by', + 'updated_by', + 'organization_id', + 'parent_id', + 'allow_custom_entities', + 'has_entities', + ], + update: [ + 'id', + 'created_by', + 'updated_by', + 'allow_filtering', + 'organization_id', + 'parent_id', + 'allow_custom_entities', + 'has_entities', + ], +} + +const entity = { + create: ['id', 'status', 'type', 'created_by', 'updated_by'], + update: ['id', 'entity_type_id', 'created_by', 'updated_by'], +} + +const form = { + create: ['id', 'version', 'organization_id'], + update: ['id', 'version', 'organization_id'], +} + +const modules = { + create: ['id'], + update: [], +} + +const notification = { + create: ['id', 'created_by', 'updated_by'], + update: ['id', 'created_by', 'updated_by'], +} + +const orgAdmin = { + bulkUserCreate: [ + 'id', + 'email_verified', + 'name', + 'gender', + 'location', + 'about', + 'share_link', + 'status', + 'image', + 'last_logged_in_at', + 'has_accepted_terms_and_conditions', + 'refresh_tokens', + 'languages', + 'preferred_language', + 'organization_id', + 'roles', + 'custom_entity_text', + 'meta', + ], + updateRequestStatus: [ + 'id', + 'email_verified', + 'name', + 'gender', + 'location', + 'about', + 'share_link', + 'image', + 'last_logged_in_at', + 'has_accepted_terms_and_conditions', + 'refresh_tokens', + 'languages', + 'preferred_language', + 'organization_id', + 'roles', + 'custom_entity_text', + 'meta', + ], +} + +const organization = { + create: [ + 'id', + 'description', + 'status', + 'org_admin', + 'parent_id', + 'related_orgs', + 'in_domain_visibility', + 'created_by', + 'updated_by', + ], + update: [ + 'id', + 'description', + 'status', + 'org_admin', + 'parent_id', + 'related_orgs', + 'in_domain_visibility', + 'created_by', + 'updated_by', + ], + requestOrgRole: [ + 'id', + 'description', + 'status', + 'org_admin', + 'parent_id', + 'related_orgs', + 'in_domain_visibility', + 'created_by', + 'updated_by', + ], +} + +const permissions = { + create: ['id'], + update: ['id'], +} + +const rolePermissionMapping = { + create: ['created_by'], + update: ['module', 'request_type', 'api_path', 'created_by'], +} + +const userRole = { + create: ['id', 'organization_id'], + update: ['id', 'organization_id'], +} + +const user = { + update: [ + 'id', + 'share_link', + 'last_logged_in_at', + 'refresh_tokens', + 'organization_id', + 'roles', + 'custom_entity_text', + 'meta', + ], +} + +module.exports = { + account, + admin, + entityType, + entity, + form, + modules, + notification, + orgAdmin, + organization, + permissions, + rolePermissionMapping, + userRole, + user, +} diff --git a/src/validators/common.js b/src/validators/common.js new file mode 100644 index 000000000..b4d539e4a --- /dev/null +++ b/src/validators/common.js @@ -0,0 +1,3 @@ +module.exports = function filterRequestBody(reqBody, blacklist) { + return Object.fromEntries(Object.entries(reqBody).filter(([key]) => !blacklist.includes(key))) +} diff --git a/src/validators/v1/account.js b/src/validators/v1/account.js index 449860c2d..3d9491666 100644 --- a/src/validators/v1/account.js +++ b/src/validators/v1/account.js @@ -5,8 +5,11 @@ * Description : Validations of accounts controller */ const common = require('@constants/common') +const filterRequestBody = require('../common') +const { account } = require('@constants/blacklistConfig') module.exports = { create: (req) => { + req.body = filterRequestBody(req.body, account.create) req.checkBody('name') .trim() .notEmpty() @@ -33,6 +36,7 @@ module.exports = { }, login: (req) => { + req.body = filterRequestBody(req.body, account.login) req.checkBody('email') .trim() .notEmpty() @@ -45,24 +49,29 @@ module.exports = { }, logout: (req) => { + req.body = filterRequestBody(req.body, account.logout) req.checkBody('refresh_token').notEmpty().withMessage('refresh_token field is empty') }, generateToken: (req) => { + req.body = filterRequestBody(req.body, account.generateToken) req.checkBody('refresh_token').notEmpty().withMessage('refresh_token field is empty') }, generateOtp: (req) => { + req.body = filterRequestBody(req.body, account.generateOtp) req.checkBody('email').notEmpty().withMessage('email field is empty').isEmail().withMessage('email is invalid') req.checkBody('password').trim().notEmpty().withMessage('password field is empty') }, registrationOtp: (req) => { + req.body = filterRequestBody(req.body, account.registrationOtp) req.checkBody('email').notEmpty().withMessage('email field is empty').isEmail().withMessage('email is invalid') req.checkBody('name').notEmpty().withMessage('name field is empty') }, resetPassword: (req) => { + req.body = filterRequestBody(req.body, account.resetPassword) req.checkBody('email').notEmpty().withMessage('email field is empty').isEmail().withMessage('email is invalid') req.checkBody('password').notEmpty().withMessage('password field is empty') @@ -76,6 +85,7 @@ module.exports = { }, changeRole: (req) => { + req.body = filterRequestBody(req.body, account.changeRole) req.checkBody('email').notEmpty().withMessage('email field is empty').isEmail().withMessage('email is invalid') req.checkBody('role').notEmpty().withMessage('role field is empty') }, @@ -83,4 +93,26 @@ module.exports = { listUser: (req) => { req.checkQuery('type').notEmpty().withMessage('type can not be null').isString() }, + + search: (req) => { + req.checkQuery('type') + .notEmpty() + .withMessage('type can not be null') + .isString() + .notIn([common.ADMIN_ROLE, common.MENTEE_ROLE, common.MENTEE_ROLE, common.ORG_ADMIN_ROLE]) + .withMessage('Invalid type value') + req.checkQuery('organization_id').isNumeric().withMessage('organization_id must be an Id') + req.checkBody('user_ids') + .isArray() + .withMessage('user_ids must be an array') + .custom((value) => { + // Check if all elements in the array are integers + for (const id of value) { + if (!Number.isInteger(id)) { + throw new Error('All elements in user_ids must be integers') + } + } + return true + }) + }, } diff --git a/src/validators/v1/admin.js b/src/validators/v1/admin.js index 575be9190..e5aaa41d9 100644 --- a/src/validators/v1/admin.js +++ b/src/validators/v1/admin.js @@ -5,12 +5,15 @@ * Description : Validations of admin controller */ +const filterRequestBody = require('../common') +const { admin } = require('@constants/blacklistConfig') module.exports = { deleteUser: (req) => { req.checkParams('id').notEmpty().withMessage('id param is empty') }, create: (req) => { + req.body = filterRequestBody(req.body, admin.create) req.checkBody('secret_code').trim().notEmpty().withMessage('secret_code field is empty') req.checkBody('name') .trim() @@ -31,6 +34,7 @@ module.exports = { }, login: (req) => { + req.body = filterRequestBody(req.body, admin.login) req.checkBody('email') .trim() .notEmpty() @@ -43,6 +47,7 @@ module.exports = { }, addOrgAdmin: (req) => { + req.body = filterRequestBody(req.body, admin.addOrgAdmin) req.checkBody('organization_id').notEmpty().withMessage('organization_id field is empty') req.checkBody(['user_id', 'email']).custom(() => { @@ -65,6 +70,7 @@ module.exports = { }, deactivateUser: (req) => { + req.body = filterRequestBody(req.body, admin.deactivateUser) const field = req.body.email ? 'email' : req.body.id ? 'id' : null if (field) { req.checkBody(field).isArray().notEmpty().withMessage(` ${field} must be an array and should not be empty.`) diff --git a/src/validators/v1/entity-type.js b/src/validators/v1/entity-type.js index fca56b740..d39584a29 100644 --- a/src/validators/v1/entity-type.js +++ b/src/validators/v1/entity-type.js @@ -4,9 +4,11 @@ * Date : 04-Nov-2021 * Description : Validations of user entities controller */ - +const filterRequestBody = require('../common') +const { entityType } = require('@constants/blacklistConfig') module.exports = { create: (req) => { + req.body = filterRequestBody(req.body, entityType.create) req.checkBody('value') .trim() .notEmpty() @@ -41,6 +43,7 @@ module.exports = { }, update: (req) => { + req.body = filterRequestBody(req.body, entityType.update) req.checkParams('id').notEmpty().withMessage('id param is empty') req.checkBody('value') diff --git a/src/validators/v1/entity.js b/src/validators/v1/entity.js index ddaf66a65..6db5c7099 100644 --- a/src/validators/v1/entity.js +++ b/src/validators/v1/entity.js @@ -4,9 +4,12 @@ * Date : 04-Nov-2021 * Description : Validations of user entities controller */ +const filterRequestBody = require('../common') +const { entity } = require('@constants/blacklistConfig') module.exports = { create: (req) => { + req.body = filterRequestBody(req.body, entity.create) req.checkBody('value') .trim() .notEmpty() @@ -29,6 +32,7 @@ module.exports = { }, update: (req) => { + req.body = filterRequestBody(req.body, entity.update) req.checkParams('id').notEmpty().withMessage('id param is empty') req.checkBody('value') diff --git a/src/validators/v1/form.js b/src/validators/v1/form.js index 93bde96b5..6a1af4c67 100644 --- a/src/validators/v1/form.js +++ b/src/validators/v1/form.js @@ -4,9 +4,12 @@ * Date : 03-Nov-2021 * Description : Validations of forms controller */ +const filterRequestBody = require('../common') +const { form } = require('@constants/blacklistConfig') module.exports = { create: (req) => { + req.body = filterRequestBody(req.body, form.create) req.checkBody('type') .trim() .notEmpty() @@ -34,6 +37,7 @@ module.exports = { }, update: (req) => { + req.body = filterRequestBody(req.body, form.update) req.checkBody('type') .notEmpty() .withMessage('type field is empty') diff --git a/src/validators/v1/modules.js b/src/validators/v1/modules.js index 35e3f2fca..8f0394643 100644 --- a/src/validators/v1/modules.js +++ b/src/validators/v1/modules.js @@ -1,5 +1,8 @@ +const filterRequestBody = require('../common') +const { modules } = require('@constants/blacklistConfig') module.exports = { create: (req) => { + req.body = filterRequestBody(req.body, modules.create) req.checkBody('code') .trim() .notEmpty() @@ -16,6 +19,7 @@ module.exports = { }, update: (req) => { + req.body = filterRequestBody(req.body, modules.update) req.checkParams('id').notEmpty().withMessage('id param is empty') req.checkBody('code') diff --git a/src/validators/v1/notification.js b/src/validators/v1/notification.js index 265c3e27f..9cef644a9 100644 --- a/src/validators/v1/notification.js +++ b/src/validators/v1/notification.js @@ -4,9 +4,11 @@ * Date : 03-Nov-2023 * Description : Validations of notification controller */ - +const filterRequestBody = require('../common') +const { notification } = require('@constants/blacklistConfig') module.exports = { create: (req) => { + req.body = filterRequestBody(req.body, notification.create) req.checkBody('type').trim().notEmpty().withMessage('type field is empty') req.checkBody('code').trim().notEmpty().withMessage('code field is empty') @@ -17,6 +19,7 @@ module.exports = { }, update: (req) => { + req.body = filterRequestBody(req.body, notification.update) req.checkBody('type').trim().notEmpty().withMessage('type field is empty') req.checkBody('code').trim().notEmpty().withMessage('code field is empty') @@ -27,7 +30,6 @@ module.exports = { }, read: (req) => { - console.log(req.params.id, req.query.code, 'kjkkkkkkk') if (req.params.id || req.query.code) { if (req.params.id) { req.checkParams('id').notEmpty().withMessage('id param is empty') diff --git a/src/validators/v1/org-admin.js b/src/validators/v1/org-admin.js index c31f4bdbf..a8bcd1dac 100644 --- a/src/validators/v1/org-admin.js +++ b/src/validators/v1/org-admin.js @@ -4,15 +4,19 @@ * Date : 19-Jun-2023 * Description : Validations of admin controller */ +const filterRequestBody = require('../common') +const { orgAdmin } = require('@constants/blacklistConfig') module.exports = { bulkUserCreate: (req) => { + req.body = filterRequestBody(req.body, orgAdmin.bulkUserCreate) req.checkBody('file_path').notEmpty().withMessage('file_path field is empty') }, getRequestDetails: (req) => { req.checkParams('id').notEmpty().withMessage('id param is empty') }, updateRequestStatus: (req) => { + req.body = filterRequestBody(req.body, orgAdmin.updateRequestStatus) req.checkBody('request_id').notEmpty().withMessage('request_id field is empty') req.checkBody('status').notEmpty().withMessage('status field is empty') }, diff --git a/src/validators/v1/organization.js b/src/validators/v1/organization.js index 0c2a8b8e0..be2cacd1d 100644 --- a/src/validators/v1/organization.js +++ b/src/validators/v1/organization.js @@ -4,9 +4,11 @@ * Date : 25-July-2023 * Description : Validations of Organization controller */ - +const filterRequestBody = require('../common') +const { organization } = require('@constants/blacklistConfig') module.exports = { create: (req) => { + req.body = filterRequestBody(req.body, organization.create) req.checkBody('code').trim().notEmpty().withMessage('code field is empty') req.checkBody('name') .trim() @@ -20,10 +22,12 @@ module.exports = { }, update: (req) => { + req.body = filterRequestBody(req.body, organization.update) req.checkParams('id').notEmpty().withMessage('id param is empty') }, requestOrgRole: (req) => { + req.body = filterRequestBody(req.body, organization.requestOrgRole) req.checkBody('role').notEmpty().withMessage('role field is empty') req.checkBody('form_data').notEmpty().withMessage('form_data field is empty') }, diff --git a/src/validators/v1/permissions.js b/src/validators/v1/permissions.js index 4f7d6d510..caba25a77 100644 --- a/src/validators/v1/permissions.js +++ b/src/validators/v1/permissions.js @@ -1,5 +1,6 @@ const Permission = require('@database/models/index').Permission - +const filterRequestBody = require('../common') +const { permissions } = require('@constants/blacklistConfig') async function isUniqueCode(value) { const existingRecord = await Permission.findOne({ where: { code: value } }) if (existingRecord) { @@ -10,6 +11,7 @@ async function isUniqueCode(value) { module.exports = { create: (req) => { + req.body = filterRequestBody(req.body, permissions.create) req.checkBody('code') .trim() .notEmpty() @@ -48,6 +50,7 @@ module.exports = { }, update: (req) => { + req.body = filterRequestBody(req.body, permissions.update) req.checkParams('id').notEmpty().withMessage('id param is empty') req.checkBody('code') diff --git a/src/validators/v1/role-permission-mapping.js b/src/validators/v1/role-permission-mapping.js index 043982d1c..c10f4a10b 100644 --- a/src/validators/v1/role-permission-mapping.js +++ b/src/validators/v1/role-permission-mapping.js @@ -1,5 +1,8 @@ +const filterRequestBody = require('../common') +const { rolePermissionMapping } = require('@constants/blacklistConfig') module.exports = { create: (req) => { + req.body = filterRequestBody(req.body, rolePermissionMapping.create) req.checkBody('permission_id') .trim() .notEmpty() @@ -15,6 +18,7 @@ module.exports = { }, delete: (req) => { + req.body = filterRequestBody(req.body, rolePermissionMapping.delete) req.checkBody('permission_id') .trim() .notEmpty() diff --git a/src/validators/v1/user-role.js b/src/validators/v1/user-role.js index db654cb72..6efaa4a33 100644 --- a/src/validators/v1/user-role.js +++ b/src/validators/v1/user-role.js @@ -1,3 +1,5 @@ +const filterRequestBody = require('../common') +const { userRole } = require('@constants/blacklistConfig') const validateList = (req, allowedVariables) => { allowedVariables.forEach((variable) => { req.checkQuery(variable) @@ -9,6 +11,7 @@ const validateList = (req, allowedVariables) => { module.exports = { create: (req) => { + req.body = filterRequestBody(req.body, userRole.create) req.checkBody('title') .trim() .notEmpty() @@ -40,6 +43,7 @@ module.exports = { }, update: (req) => { + req.body = filterRequestBody(req.body, userRole.update) req.checkParams('id').notEmpty().withMessage('id param is empty') req.checkBody('title') diff --git a/src/validators/v1/user.js b/src/validators/v1/user.js index 312b81d7b..d0734ed71 100644 --- a/src/validators/v1/user.js +++ b/src/validators/v1/user.js @@ -4,9 +4,11 @@ * Date : 17-July-2023 * Description : Validations of user controller */ - +const filterRequestBody = require('../common') +const { user } = require('@constants/blacklistConfig') module.exports = { update: (req) => { + req.body = filterRequestBody(req.body, user.update) if (req.body.preferred_language) { req.checkBody('preferred_language') .trim() From 5817165679a96671c4b515f8b55fc5f688ddfdae Mon Sep 17 00:00:00 2001 From: sumanvpacewisdom Date: Wed, 20 Mar 2024 16:21:17 +0530 Subject: [PATCH 07/19] Comment Changes regarding the password --- src/envVariables.js | 11 +++++++++++ src/validators/v1/account.js | 14 +++++--------- src/validators/v1/admin.js | 8 +++----- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/envVariables.js b/src/envVariables.js index b61ff67ae..0a9a29855 100644 --- a/src/envVariables.js +++ b/src/envVariables.js @@ -237,6 +237,17 @@ let enviromentVariables = { optional: true, default: '*', }, + PASSWORD_POLICY_REGEX: { + message: 'Required password policy', + optional: true, + default: '/^(?=.*[A-Z])(?=.*d)(?=.*[!@#$%^&*()_+{}|:<>?~`-=[];,./])[^ ]{11,}$/', + }, + PASSWORD_POLICY_MESSAGE: { + message: 'Required password policy message', + optional: true, + default: + 'Password must have at least one uppercase letter, one number, one special character, and be at least 10 characters long', + }, } let success = true diff --git a/src/validators/v1/account.js b/src/validators/v1/account.js index 260c05c98..aa906017c 100644 --- a/src/validators/v1/account.js +++ b/src/validators/v1/account.js @@ -25,13 +25,11 @@ module.exports = { .withMessage('email is invalid') .normalizeEmail({ gmail_remove_dots: false }) - req.checkBody('password') + req.checkBody('password') .notEmpty() .withMessage('Password field is empty') - .matches(/^(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*()_+{}|:"<>?~`\-=[\];',.\/])[^ ]{10,}$/) - .withMessage( - 'Password must have at least one uppercase letter, one number, one special character, and be at least 10 characters long' - ) + .matches(process.env.PASSWORD_POLICY_REGEX) + .withMessage(process.env.PASSWORD_POLICY_MESSAGE) .custom((value) => !/\s/.test(value)) .withMessage('Password cannot contain spaces') @@ -75,10 +73,8 @@ module.exports = { req.checkBody('password') .notEmpty() .withMessage('Password field is empty') - .matches(/^(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*()_+{}|:"<>?~`\-=[\];',.\/])[^ ]{10,}$/) - .withMessage( - 'Password must have at least one uppercase letter, one number, one special character, and be at least 10 characters long' - ) + .matches(process.env.PASSWORD_POLICY_REGEX) + .withMessage(process.env.PASSWORD_POLICY_MESSAGE) .custom((value) => !/\s/.test(value)) .withMessage('Password cannot contain spaces') diff --git a/src/validators/v1/admin.js b/src/validators/v1/admin.js index 75ffdbc89..1877d9f36 100644 --- a/src/validators/v1/admin.js +++ b/src/validators/v1/admin.js @@ -27,13 +27,11 @@ module.exports = { .withMessage('email is invalid') .normalizeEmail() - req.checkBody('password') + req.checkBody('password') .notEmpty() .withMessage('Password field is empty') - .matches(/^(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*()_+{}|:"<>?~`\-=[\];',.\/])[^ ]{10,}$/) - .withMessage( - 'Password must have at least one uppercase letter, one number, one special character, and be at least 10 characters long' - ) + .matches(process.env.PASSWORD_POLICY_REGEX) + .withMessage(process.env.PASSWORD_POLICY_MESSAGE) .custom((value) => !/\s/.test(value)) .withMessage('Password cannot contain spaces') }, From e78676718bf37830bfa6351b79e444780235eb60 Mon Sep 17 00:00:00 2001 From: Nevil Date: Thu, 21 Mar 2024 10:28:14 +0530 Subject: [PATCH 08/19] updated validators --- src/constants/blacklistConfig.js | 38 +++++-------------------------- src/validators/v1/entity-type.js | 7 ++---- src/validators/v1/entity.js | 26 ++++++++++++++++----- src/validators/v1/organization.js | 22 +++++++++++++++++- src/validators/v1/user.js | 14 ++++++++++-- 5 files changed, 61 insertions(+), 46 deletions(-) diff --git a/src/constants/blacklistConfig.js b/src/constants/blacklistConfig.js index 72c39e26f..a212cd6e3 100644 --- a/src/constants/blacklistConfig.js +++ b/src/constants/blacklistConfig.js @@ -220,26 +220,8 @@ const admin = { ], } const entityType = { - create: [ - 'id', - 'status', - 'created_by', - 'updated_by', - 'organization_id', - 'parent_id', - 'allow_custom_entities', - 'has_entities', - ], - update: [ - 'id', - 'created_by', - 'updated_by', - 'allow_filtering', - 'organization_id', - 'parent_id', - 'allow_custom_entities', - 'has_entities', - ], + create: ['id', 'status', 'created_by', 'updated_by', 'organization_id', 'parent_id', 'allow_filtering'], + update: ['id', 'created_by', 'updated_by', 'allow_filtering', 'organization_id', 'parent_id'], } const entity = { @@ -307,18 +289,6 @@ const orgAdmin = { const organization = { create: [ 'id', - 'description', - 'status', - 'org_admin', - 'parent_id', - 'related_orgs', - 'in_domain_visibility', - 'created_by', - 'updated_by', - ], - update: [ - 'id', - 'description', 'status', 'org_admin', 'parent_id', @@ -327,6 +297,7 @@ const organization = { 'created_by', 'updated_by', ], + update: ['id', 'org_admin', 'parent_id', 'related_orgs', 'in_domain_visibility', 'created_by', 'updated_by'], requestOrgRole: [ 'id', 'description', @@ -365,6 +336,9 @@ const user = { 'roles', 'custom_entity_text', 'meta', + 'email', + 'email_verified', + 'password', ], } diff --git a/src/validators/v1/entity-type.js b/src/validators/v1/entity-type.js index d39584a29..ce8bc7ebd 100644 --- a/src/validators/v1/entity-type.js +++ b/src/validators/v1/entity-type.js @@ -27,7 +27,7 @@ module.exports = { .trim() .notEmpty() .withMessage('data_type field is empty') - .matches(/^[A-Za-z]+$/) + .matches(/^[A-Za-z\[\]]+$/) .withMessage('data_type is invalid, must not contain spaces') req.checkBody('model_names') @@ -61,14 +61,11 @@ module.exports = { .matches(/^[A-Z]+$/) .withMessage('status is invalid, must be in all caps') - req.checkBody('deleted').optional().isBoolean().withMessage('deleted is invalid') - req.checkBody('allow_filtering').optional().isEmpty().withMessage('allow_filtering is not allowed in create') - req.checkBody('data_type') .trim() .notEmpty() .withMessage('data_type field is empty') - .matches(/^[A-Za-z]+$/) + .matches(/^[A-Za-z\[\]]+$/) .withMessage('data_type is invalid, must not contain spaces') req.checkBody('model_names') diff --git a/src/validators/v1/entity.js b/src/validators/v1/entity.js index 6db5c7099..13dc7850f 100644 --- a/src/validators/v1/entity.js +++ b/src/validators/v1/entity.js @@ -29,6 +29,18 @@ module.exports = { .withMessage('entity_type_id field is empty') .isNumeric() .withMessage('entity_type_id is invalid, must be numeric') + + req.checkBody('status') + .optional() + .notEmpty() + .withMessage('status field is empty') + .matches(/^[A-Z]+$/) + .withMessage('status is invalid, must be in all caps and no spaces') + req.checkBody('type') + .notEmpty() + .withMessage('type field is empty') + .matches(/^[A-Z]+$/) + .withMessage('type is invalid, must be in all caps and no spaces') }, update: (req) => { @@ -47,15 +59,17 @@ module.exports = { req.checkBody('status') .optional() + .optional() + .notEmpty() + .withMessage('status field is empty') .matches(/^[A-Z]+$/) - .withMessage('status is invalid, must be in all caps') - - req.checkBody('deleted').optional().isBoolean().withMessage('deleted is invalid') - + .withMessage('status is invalid, must be in all caps and no spaces') req.checkBody('type') .optional() - .matches(/^[A-Za-z]+$/) - .withMessage('type is invalid, must not contain spaces') + .notEmpty() + .withMessage('type field is empty') + .matches(/^[A-Z]+$/) + .withMessage('type is invalid, must be in all caps and no spaces') }, read: (req) => { diff --git a/src/validators/v1/organization.js b/src/validators/v1/organization.js index be2cacd1d..58651f2f2 100644 --- a/src/validators/v1/organization.js +++ b/src/validators/v1/organization.js @@ -17,13 +17,33 @@ module.exports = { .matches(/^[A-Za-z ]+$/) .withMessage('name is invalid') - req.checkBody('description').trim().notEmpty().withMessage('description field is empty') + req.checkBody('description') + .trim() + .notEmpty() + .withMessage('description field is empty') + .matches(/(\b)(on\S+)(\s*)=|javascript:|<(|\/|[^\/>][^>]+|\/[^>][^>]+)>/gi) + .withMessage('invalid description') req.checkBody('domains').trim().notEmpty().withMessage('domains field is empty') }, update: (req) => { req.body = filterRequestBody(req.body, organization.update) req.checkParams('id').notEmpty().withMessage('id param is empty') + req.checkBody('name') + .optional() + .trim() + .notEmpty() + .withMessage('name field is empty') + .matches(/^[A-Za-z ]+$/) + .withMessage('name is invalid') + + req.checkBody('description') + .optional() + .trim() + .notEmpty() + .withMessage('description field is empty') + .matches(/(\b)(on\S+)(\s*)=|javascript:|<(|\/|[^\/>][^>]+|\/[^>][^>]+)>/gi) + .withMessage('invalid description') }, requestOrgRole: (req) => { diff --git a/src/validators/v1/user.js b/src/validators/v1/user.js index d0734ed71..40feb3f7e 100644 --- a/src/validators/v1/user.js +++ b/src/validators/v1/user.js @@ -21,7 +21,12 @@ module.exports = { .isIn(['MALE', 'FEMALE', 'OTHER']) .withMessage('gender is invalid, must be either MALE, FEMALE or OTHER') - req.checkBody('name').trim().notEmpty().withMessage('name field is empty') + req.checkBody('name') + .trim() + .notEmpty() + .withMessage('name field is empty') + .matches(/^[A-Za-z ]+$/) + .withMessage('This field can only contain alphabets') req.checkBody('location') .notEmpty() @@ -29,7 +34,12 @@ module.exports = { .isString() .withMessage('location is invalid') - req.checkBody('about').trim().notEmpty().withMessage('about field is empty') + req.checkBody('about') + .trim() + .notEmpty() + .withMessage('about field is empty') + .matches(/(\b)(on\S+)(\s*)=|javascript:|<(|\/|[^\/>][^>]+|\/[^>][^>]+)>/gi) + .withMessage('invalid about') req.checkBody('has_accepted_terms_and_conditions') .optional() From cf8509226bf48372fdb9ec470d471fdff9fdd984 Mon Sep 17 00:00:00 2001 From: Nevil Date: Thu, 21 Mar 2024 10:39:25 +0530 Subject: [PATCH 09/19] updated blackList --- src/constants/blacklistConfig.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/constants/blacklistConfig.js b/src/constants/blacklistConfig.js index a212cd6e3..a5ee04a55 100644 --- a/src/constants/blacklistConfig.js +++ b/src/constants/blacklistConfig.js @@ -1,5 +1,5 @@ const account = { - create: ['id', 'last_logged_in_at', 'has_accepted_terms_and_conditions', 'refresh_tokens', 'organization_id'], + create: ['id', 'last_logged_in_at', 'refresh_tokens', 'organization_id'], login: [ 'id', 'email_verified', @@ -152,7 +152,6 @@ const admin = { 'status', 'image', 'last_logged_in_at', - 'has_accepted_terms_and_conditions', 'refresh_tokens', 'languages', 'preferred_language', From a607cb4f79ede831e6e78649fe4660b8346ae8a4 Mon Sep 17 00:00:00 2001 From: adithya_dinesh Date: Thu, 21 Mar 2024 12:16:20 +0530 Subject: [PATCH 10/19] user update blacklist updated --- src/constants/blacklistConfig.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/constants/blacklistConfig.js b/src/constants/blacklistConfig.js index 72c39e26f..b48a1dcae 100644 --- a/src/constants/blacklistConfig.js +++ b/src/constants/blacklistConfig.js @@ -358,11 +358,18 @@ const userRole = { const user = { update: [ 'id', + 'email', + 'email_verified', + 'password', + 'about', 'share_link', + 'status', 'last_logged_in_at', + 'has_accepted_terms_and_conditions', 'refresh_tokens', + 'languages', + 'preferred_language', 'organization_id', - 'roles', 'custom_entity_text', 'meta', ], From c633acb182abfa7bf84ad19e7545f61a34c82011 Mon Sep 17 00:00:00 2001 From: adithya_dinesh Date: Thu, 21 Mar 2024 12:24:41 +0530 Subject: [PATCH 11/19] user update blacklist updated - Added roles --- src/constants/blacklistConfig.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/constants/blacklistConfig.js b/src/constants/blacklistConfig.js index b48a1dcae..f9bad8bcc 100644 --- a/src/constants/blacklistConfig.js +++ b/src/constants/blacklistConfig.js @@ -370,6 +370,7 @@ const user = { 'languages', 'preferred_language', 'organization_id', + 'roles', 'custom_entity_text', 'meta', ], From 88c6a8930163bf8fe3ba8b6049d95f2ccf564747 Mon Sep 17 00:00:00 2001 From: Nevil Date: Thu, 21 Mar 2024 12:30:51 +0530 Subject: [PATCH 12/19] updated blacklist --- src/constants/blacklistConfig.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/constants/blacklistConfig.js b/src/constants/blacklistConfig.js index a5ee04a55..0830cf6b9 100644 --- a/src/constants/blacklistConfig.js +++ b/src/constants/blacklistConfig.js @@ -338,6 +338,7 @@ const user = { 'email', 'email_verified', 'password', + 'has_accepted_terms_and_conditions', ], } From 182188c6b24aef06b52526d4c0106388d6d6b836 Mon Sep 17 00:00:00 2001 From: Nevil Date: Thu, 21 Mar 2024 18:28:30 +0530 Subject: [PATCH 13/19] added cloud-services to valid list --- src/routes/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/routes/index.js b/src/routes/index.js index 55d2dd2a6..b73743c62 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -89,7 +89,9 @@ module.exports = (app) => { error.statusCode = 400 throw error } + // Validate controller + allowedControllers.push('cloud-services') if (!allowedControllers.includes(controllerName)) { const error = new Error('Invalid controller.') error.statusCode = 400 From e180323dfcf503fd11366f8b49342e6da505113c Mon Sep 17 00:00:00 2001 From: adithya_dinesh Date: Fri, 22 Mar 2024 12:49:16 +0530 Subject: [PATCH 14/19] user update blacklist updated - changes --- src/constants/blacklistConfig.js | 1 - src/validators/v1/organization.js | 2 ++ src/validators/v1/user.js | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/constants/blacklistConfig.js b/src/constants/blacklistConfig.js index 19a3f876d..cf4038180 100644 --- a/src/constants/blacklistConfig.js +++ b/src/constants/blacklistConfig.js @@ -84,7 +84,6 @@ const account = { registrationOtp: [ 'id', 'email_verified', - 'name', 'gender', 'location', 'about', diff --git a/src/validators/v1/organization.js b/src/validators/v1/organization.js index 58651f2f2..9a0bcf838 100644 --- a/src/validators/v1/organization.js +++ b/src/validators/v1/organization.js @@ -21,6 +21,7 @@ module.exports = { .trim() .notEmpty() .withMessage('description field is empty') + .not() .matches(/(\b)(on\S+)(\s*)=|javascript:|<(|\/|[^\/>][^>]+|\/[^>][^>]+)>/gi) .withMessage('invalid description') req.checkBody('domains').trim().notEmpty().withMessage('domains field is empty') @@ -42,6 +43,7 @@ module.exports = { .trim() .notEmpty() .withMessage('description field is empty') + .not() .matches(/(\b)(on\S+)(\s*)=|javascript:|<(|\/|[^\/>][^>]+|\/[^>][^>]+)>/gi) .withMessage('invalid description') }, diff --git a/src/validators/v1/user.js b/src/validators/v1/user.js index 40feb3f7e..a0ceb2c2f 100644 --- a/src/validators/v1/user.js +++ b/src/validators/v1/user.js @@ -38,6 +38,7 @@ module.exports = { .trim() .notEmpty() .withMessage('about field is empty') + .not() .matches(/(\b)(on\S+)(\s*)=|javascript:|<(|\/|[^\/>][^>]+|\/[^>][^>]+)>/gi) .withMessage('invalid about') From c7241baa106c640cf774c33602f43b4abdf9c6b9 Mon Sep 17 00:00:00 2001 From: adithya_dinesh Date: Fri, 22 Mar 2024 12:53:46 +0530 Subject: [PATCH 15/19] user update blacklist updated - changes --- src/constants/blacklistConfig.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/constants/blacklistConfig.js b/src/constants/blacklistConfig.js index cf4038180..f6e21fc1f 100644 --- a/src/constants/blacklistConfig.js +++ b/src/constants/blacklistConfig.js @@ -327,17 +327,9 @@ const userRole = { const user = { update: [ 'id', - 'email', - 'email_verified', - 'password', - 'about', 'share_link', - 'status', 'last_logged_in_at', - 'has_accepted_terms_and_conditions', 'refresh_tokens', - 'languages', - 'preferred_language', 'organization_id', 'roles', 'custom_entity_text', From 353b1bb52b94f6fd69cea547a19393246a0bf39d Mon Sep 17 00:00:00 2001 From: sumanvpacewisdom Date: Fri, 22 Mar 2024 14:35:28 +0530 Subject: [PATCH 16/19] Default variable changes for regex in env --- src/envVariables.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/envVariables.js b/src/envVariables.js index 0a9a29855..a335ee039 100644 --- a/src/envVariables.js +++ b/src/envVariables.js @@ -240,7 +240,7 @@ let enviromentVariables = { PASSWORD_POLICY_REGEX: { message: 'Required password policy', optional: true, - default: '/^(?=.*[A-Z])(?=.*d)(?=.*[!@#$%^&*()_+{}|:<>?~`-=[];,./])[^ ]{11,}$/', + default: '^(?=.*[A-Z])(?=.*d)(?=.*[!@$%^&*()_+{}|:<>?~`-=[],./])[^ ]{11,}$', }, PASSWORD_POLICY_MESSAGE: { message: 'Required password policy message', From 03de8c715b64f9b86300153ac316268d9535a2ed Mon Sep 17 00:00:00 2001 From: vishnu Date: Fri, 22 Mar 2024 16:29:51 +0530 Subject: [PATCH 17/19] bulk upload internal process failure fix --- src/services/userInvite.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/services/userInvite.js b/src/services/userInvite.js index bd6cb052d..d74c240f2 100644 --- a/src/services/userInvite.js +++ b/src/services/userInvite.js @@ -50,8 +50,8 @@ module.exports = class UserInviteHelper { // upload output file to cloud const uploadRes = await this.uploadFileToCloud(outputFilename, inviteeFileDir, data.user.id) - const output_path = uploadRes.result.uploadDest + const output_path = uploadRes.result.uploadDest const update = { output_path, updated_by: data.user.id, @@ -103,13 +103,17 @@ module.exports = class UserInviteHelper { static async downloadCSV(filePath) { try { const downloadableUrl = await utils.getDownloadableUrl(filePath) - const fileName = path.basename(downloadableUrl) - const downloadPath = path.join(inviteeFileDir, fileName) + let fileName = path.basename(downloadableUrl) + // Find the index of the first occurrence of '?' + const index = fileName.indexOf('?') + // Extract the portion of the string before the '?' if it exists, otherwise use the entire string + fileName = index !== -1 ? fileName.substring(0, index) : fileName + + const downloadPath = path.join(inviteeFileDir, fileName) const response = await axios.get(downloadableUrl, { responseType: common.responseType, }) - const writeStream = fs.createWriteStream(downloadPath) response.data.pipe(writeStream) From 655b9352cda17abab3ad32e688172cbbe7108609 Mon Sep 17 00:00:00 2001 From: sumanvpacewisdom Date: Fri, 22 Mar 2024 16:58:26 +0530 Subject: [PATCH 18/19] envVariables chnages --- src/envVariables.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/envVariables.js b/src/envVariables.js index f86629912..a8a3ba38a 100644 --- a/src/envVariables.js +++ b/src/envVariables.js @@ -244,14 +244,14 @@ let enviromentVariables = { PASSWORD_POLICY_REGEX: { message: 'Required password policy', optional: true, - default: '^(?=.*[A-Z])(?=.*d)(?=.*[!@$%^&*()_+{}|:<>?~`-=[],./])[^ ]{11,}$', + default: '^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{10,}$', }, PASSWORD_POLICY_MESSAGE: { message: 'Required password policy message', optional: true, default: 'Password must have at least one uppercase letter, one number, one special character, and be at least 10 characters long', - }, + }, DOWNLOAD_URL_EXPIRATION_DURATION: { message: 'Required downloadable url expiration time', optional: true, From d23c25bf1ae6c84a14a1293e9a8b42d089f13a24 Mon Sep 17 00:00:00 2001 From: Nevil Date: Fri, 22 Mar 2024 19:40:55 +0530 Subject: [PATCH 19/19] fixed an issue with refresh token update --- src/services/account.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/account.js b/src/services/account.js index 3c77fa6f6..7c46c6c3f 100644 --- a/src/services/account.js +++ b/src/services/account.js @@ -279,7 +279,7 @@ module.exports = class AccountHelper { last_logged_in_at: new Date().getTime(), } - await userQueries.updateUser({ id: user.id, organization_id: userCredentials.organization_id }, update) + await userQueries.updateUser({ id: user.id, organization_id: user.organization_id }, update) await utilsHelper.redisDel(encryptedEmailId) //make the user as org admin