From c259ef15a60c38a6acb442bdfceb0e2215400841 Mon Sep 17 00:00:00 2001 From: adithya_dinesh Date: Tue, 26 Mar 2024 15:19:52 +0530 Subject: [PATCH 1/4] google recaptcha --- src/constants/common.js | 6 ++++++ src/locales/en.json | 4 ++-- src/middlewares/authenticator.js | 15 +++++++++++++++ src/utils/captcha.js | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 src/utils/captcha.js diff --git a/src/constants/common.js b/src/constants/common.js index ce9011075..317783a9e 100644 --- a/src/constants/common.js +++ b/src/constants/common.js @@ -89,4 +89,10 @@ module.exports = { DELETED_STATUS: 'DELETED', DEFAULT_ORG_VISIBILITY: 'PUBLIC', ROLE_TYPE_NON_SYSTEM: 0, + captchaEnabledAPIs: ['/user/v1/account/login', '/interface/v1/account/login'], + google_recaptcha_API: { + HOST: 'https://www.google.com', + URL: '/recaptcha/api/siteverify', + METHOD: 'POST', + }, } diff --git a/src/locales/en.json b/src/locales/en.json index b5dad36d7..dbc9e757a 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -114,6 +114,6 @@ "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.", - "INAVLID_ORG_ROLE_REQ": "Invalid organisation request" - + "INAVLID_ORG_ROLE_REQ": "Invalid organisation request", + "CAPTCHA_VERIFICATION_FAILED": "Captcha verification Failed!" } diff --git a/src/middlewares/authenticator.js b/src/middlewares/authenticator.js index caed59bad..c6f6576da 100644 --- a/src/middlewares/authenticator.js +++ b/src/middlewares/authenticator.js @@ -14,6 +14,7 @@ const roleQueries = require('@database/queries/user-role') const rolePermissionMappingQueries = require('@database/queries/role-permission-mapping') const { Op } = require('sequelize') const responses = require('@helpers/responses') +const { verifyCaptchaToken } = require('@utils/captcha') async function checkPermissions(roleTitle, requestPath, requestMethod) { const parts = requestPath.match(/[^/]+/g) @@ -57,6 +58,20 @@ module.exports = async function (req, res, next) { } return false }) + if (process.env.CAPTCHA_ENABLE && process.env.CAPTCHA_TYPE == 'recaptcha') { + let isCaptchaEnabled = false + isCaptchaEnabled = common.captchaEnabledAPIs.includes(req.path) + + const captchaToken = req.get('captcha-token') + + if (isCaptchaEnabled && !(await verifyCaptchaToken(captchaToken))) { + throw responses.failureResponse({ + message: 'CAPTCHA_VERIFICATION_FAILED', + statusCode: httpStatusCode.unauthorized, + responseCode: 'UNAUTHORIZED', + }) + } + } common.roleValidationPaths.map(function (path) { if (req.path.includes(path)) { diff --git a/src/utils/captcha.js b/src/utils/captcha.js new file mode 100644 index 000000000..d9bc42bb8 --- /dev/null +++ b/src/utils/captcha.js @@ -0,0 +1,32 @@ +'use strict' +const common = require('@constants/common') +const requester = require('@utils/requester') + +exports.verifyCaptchaToken = async (token, options = {}) => { + const headers = { + secret: process.env.RECAPTCHA_SECRET_KEY, + response: token, + } + const requestBody = {} + const queryParams = {} + let response + if (common.google_recaptcha_API.METHOD === 'POST') + response = await requester.post( + common.google_recaptcha_API.HOST, + common.google_recaptcha_API.URL, + headers, + requestBody, + queryParams + ) + else if (common.google_recaptcha_API.METHOD === 'GET') + response = await requester.get( + ecommon.google_recaptcha_API.HOST, + common.google_recaptcha_API.URL, + headers, + pathParams, + queryParams + ) + if (response.success) return true + + return false +} From 4806aff19d7e7c40ec813fdf3441c95b8e751032 Mon Sep 17 00:00:00 2001 From: adithya_dinesh Date: Tue, 26 Mar 2024 17:55:47 +0530 Subject: [PATCH 2/4] removed interface apis --- src/constants/common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constants/common.js b/src/constants/common.js index 317783a9e..e5a0f6397 100644 --- a/src/constants/common.js +++ b/src/constants/common.js @@ -89,7 +89,7 @@ module.exports = { DELETED_STATUS: 'DELETED', DEFAULT_ORG_VISIBILITY: 'PUBLIC', ROLE_TYPE_NON_SYSTEM: 0, - captchaEnabledAPIs: ['/user/v1/account/login', '/interface/v1/account/login'], + captchaEnabledAPIs: ['/user/v1/account/login'], google_recaptcha_API: { HOST: 'https://www.google.com', URL: '/recaptcha/api/siteverify', From 5c618fc26058cf5984df58e71bce8c5139749259 Mon Sep 17 00:00:00 2001 From: adithya_dinesh Date: Tue, 26 Mar 2024 21:13:55 +0530 Subject: [PATCH 3/4] review comments --- src/constants/common.js | 5 ----- src/envVariables.js | 28 ++++++++++++++++++++++++++++ src/middlewares/authenticator.js | 16 +++++++++++----- src/utils/captcha.js | 29 +++++++++++------------------ 4 files changed, 50 insertions(+), 28 deletions(-) diff --git a/src/constants/common.js b/src/constants/common.js index e5a0f6397..74c54835d 100644 --- a/src/constants/common.js +++ b/src/constants/common.js @@ -90,9 +90,4 @@ module.exports = { DEFAULT_ORG_VISIBILITY: 'PUBLIC', ROLE_TYPE_NON_SYSTEM: 0, captchaEnabledAPIs: ['/user/v1/account/login'], - google_recaptcha_API: { - HOST: 'https://www.google.com', - URL: '/recaptcha/api/siteverify', - METHOD: 'POST', - }, } diff --git a/src/envVariables.js b/src/envVariables.js index a8a3ba38a..468afebb9 100644 --- a/src/envVariables.js +++ b/src/envVariables.js @@ -257,6 +257,34 @@ let enviromentVariables = { optional: true, default: 3600000, }, + CAPTCHA_ENABLE: { + message: 'Required CAPTCHA ENABLE true or false', + optional: false, + }, + CAPTCHA_SERVICE: { + message: 'Required CAPTCHA SERVICE', + optional: true, + default: 'googleRecaptcha', + }, + RECAPTCHA_SECRET_KEY: { + message: 'Required CAPTCHA SERVICE secret key', + optional: false, + }, + GOOGLE_RECAPTCHA_HOST: { + message: 'Required CAPTCHA Host IP', + optional: true, + default: 'https://www.google.com', + }, + GOOGLE_RECAPTCHA_URL: { + message: 'Required CAPTCHA SERVICE API URL', + optional: true, + default: '/recaptcha/api/siteverify', + }, + GOOGLE_RECAPTCHA_METHOD: { + message: 'Required CAPTCHA SERVICE Method', + optional: true, + default: 'POST', + }, } let success = true diff --git a/src/middlewares/authenticator.js b/src/middlewares/authenticator.js index c6f6576da..66e2587d1 100644 --- a/src/middlewares/authenticator.js +++ b/src/middlewares/authenticator.js @@ -58,13 +58,19 @@ module.exports = async function (req, res, next) { } return false }) - if (process.env.CAPTCHA_ENABLE && process.env.CAPTCHA_TYPE == 'recaptcha') { - let isCaptchaEnabled = false - isCaptchaEnabled = common.captchaEnabledAPIs.includes(req.path) - const captchaToken = req.get('captcha-token') + // check if captcha is enabled for the route + const isCaptchaEnabledForRoute = common.captchaEnabledAPIs.includes(req.path) ? true : false + + // check if captcha check is enabled in the env + const isCaptchaEnabled = + process.env.CAPTCHA_ENABLE.toLowerCase() == 'true' || process.env.CAPTCHA_ENABLE == true ? true : false - if (isCaptchaEnabled && !(await verifyCaptchaToken(captchaToken))) { + if (isCaptchaEnabled && isCaptchaEnabledForRoute) { + // get the token from API + const captchaToken = req.get('captcha-token') + // verify token + if (!(await verifyCaptchaToken(captchaToken))) { throw responses.failureResponse({ message: 'CAPTCHA_VERIFICATION_FAILED', statusCode: httpStatusCode.unauthorized, diff --git a/src/utils/captcha.js b/src/utils/captcha.js index d9bc42bb8..f716977eb 100644 --- a/src/utils/captcha.js +++ b/src/utils/captcha.js @@ -10,23 +10,16 @@ exports.verifyCaptchaToken = async (token, options = {}) => { const requestBody = {} const queryParams = {} let response - if (common.google_recaptcha_API.METHOD === 'POST') - response = await requester.post( - common.google_recaptcha_API.HOST, - common.google_recaptcha_API.URL, - headers, - requestBody, - queryParams - ) - else if (common.google_recaptcha_API.METHOD === 'GET') - response = await requester.get( - ecommon.google_recaptcha_API.HOST, - common.google_recaptcha_API.URL, - headers, - pathParams, - queryParams - ) + if (process.env.CAPTCHA_SERVICE == 'googleRecaptcha') { + if (process.env.GOOGLE_RECAPTCHA_METHOD === 'POST') + response = await requester.post( + process.env.GOOGLE_RECAPTCHA_HOST, + process.env.GOOGLE_RECAPTCHA_URL, + headers, + requestBody, + queryParams + ) + } if (response.success) return true - - return false + else if (!response.success) return false } From 9f1814f885f532fe538f8fc9264a1a2afea0a83b Mon Sep 17 00:00:00 2001 From: adithya_dinesh Date: Wed, 27 Mar 2024 11:26:13 +0530 Subject: [PATCH 4/4] review comments --- src/envVariables.js | 5 ----- src/middlewares/authenticator.js | 32 ++++++++++++++++---------------- src/utils/captcha.js | 18 +++++++++--------- 3 files changed, 25 insertions(+), 30 deletions(-) diff --git a/src/envVariables.js b/src/envVariables.js index 50ae18326..d8650137e 100644 --- a/src/envVariables.js +++ b/src/envVariables.js @@ -279,11 +279,6 @@ let enviromentVariables = { optional: true, default: '/recaptcha/api/siteverify', }, - GOOGLE_RECAPTCHA_METHOD: { - message: 'Required CAPTCHA SERVICE Method', - optional: true, - default: 'POST', - }, SIGNED_URL_EXPIRY_IN_MILLISECONDS: { message: 'Required signed url expiration time in milliseconds', optional: true, diff --git a/src/middlewares/authenticator.js b/src/middlewares/authenticator.js index 66e2587d1..5f303c345 100644 --- a/src/middlewares/authenticator.js +++ b/src/middlewares/authenticator.js @@ -59,23 +59,23 @@ module.exports = async function (req, res, next) { return false }) - // check if captcha is enabled for the route - const isCaptchaEnabledForRoute = common.captchaEnabledAPIs.includes(req.path) ? true : false - // check if captcha check is enabled in the env - const isCaptchaEnabled = - process.env.CAPTCHA_ENABLE.toLowerCase() == 'true' || process.env.CAPTCHA_ENABLE == true ? true : false - - if (isCaptchaEnabled && isCaptchaEnabledForRoute) { - // get the token from API - const captchaToken = req.get('captcha-token') - // verify token - if (!(await verifyCaptchaToken(captchaToken))) { - throw responses.failureResponse({ - message: 'CAPTCHA_VERIFICATION_FAILED', - statusCode: httpStatusCode.unauthorized, - responseCode: 'UNAUTHORIZED', - }) + const isCaptchaEnabled = process.env.CAPTCHA_ENABLE.toLowerCase() == 'true' + + if (isCaptchaEnabled) { + // check if captcha is enabled for the route + const isCaptchaEnabledForRoute = common.captchaEnabledAPIs.includes(req.path) + if (isCaptchaEnabledForRoute) { + // get the token from API + const captchaToken = req.get('captcha-token') + // verify token + if (!(await verifyCaptchaToken(captchaToken))) { + throw responses.failureResponse({ + message: 'CAPTCHA_VERIFICATION_FAILED', + statusCode: httpStatusCode.unauthorized, + responseCode: 'UNAUTHORIZED', + }) + } } } diff --git a/src/utils/captcha.js b/src/utils/captcha.js index f716977eb..ac3783202 100644 --- a/src/utils/captcha.js +++ b/src/utils/captcha.js @@ -11,15 +11,15 @@ exports.verifyCaptchaToken = async (token, options = {}) => { const queryParams = {} let response if (process.env.CAPTCHA_SERVICE == 'googleRecaptcha') { - if (process.env.GOOGLE_RECAPTCHA_METHOD === 'POST') - response = await requester.post( - process.env.GOOGLE_RECAPTCHA_HOST, - process.env.GOOGLE_RECAPTCHA_URL, - headers, - requestBody, - queryParams - ) + response = await requester.post( + process.env.GOOGLE_RECAPTCHA_HOST, + process.env.GOOGLE_RECAPTCHA_URL, + headers, + requestBody, + queryParams + ) } if (response.success) return true - else if (!response.success) return false + + return false }