diff --git a/backend/.env b/backend/.env index 360866b0c..63b602223 100644 --- a/backend/.env +++ b/backend/.env @@ -1,7 +1,8 @@ -#DATABASE = "mongodb://localhost:27017" -#RESEND_API = "your resend_api" -#OPENAI_API_KEY = "your open_ai api key" +DATABASE = "mongodb://localhost:27017" +RESEND_API = "your resend_api" +OPENAI_API_KEY = "your open_ai api key" JWT_SECRET= "your_private_jwt_secret_key" NODE_ENV = "production" OPENSSL_CONF='/dev/null' PUBLIC_SERVER_FILE="http://localhost:8888/" +# RECAPTCHA_SECRET_KEY = RECAPTCHA_SECRET_KEY \ No newline at end of file diff --git a/backend/package-lock.json b/backend/package-lock.json index 268204e70..39df0c32d 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -1,15 +1,16 @@ { "name": "idurar-erp-crm", - "version": "4.0.0-beta.3", + "version": "4.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "idurar-erp-crm", - "version": "4.0.0-beta.3", + "version": "4.0.0", "license": "Fair-code License", "dependencies": { "@aws-sdk/client-s3": "^3.509.0", + "axios": "^1.7.2", "bcryptjs": "^2.4.3", "compression": "^1.7.4", "cookie-parser": "^1.4.6", @@ -1815,6 +1816,16 @@ "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", "optional": true }, + "node_modules/axios": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/babel-walk": { "version": "3.0.0-canary-5", "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz", @@ -2858,6 +2869,25 @@ "node": ">= 0.8" } }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/foreground-child": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", @@ -4372,6 +4402,11 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", diff --git a/backend/package.json b/backend/package.json index 2e28def1c..49106d3db 100644 --- a/backend/package.json +++ b/backend/package.json @@ -15,6 +15,7 @@ }, "dependencies": { "@aws-sdk/client-s3": "^3.509.0", + "axios": "^1.7.2", "bcryptjs": "^2.4.3", "compression": "^1.7.4", "cookie-parser": "^1.4.6", diff --git a/backend/src/controllers/middlewaresControllers/createAuthMiddleware/login.js b/backend/src/controllers/middlewaresControllers/createAuthMiddleware/login.js index 7b57c615e..43bafcd22 100644 --- a/backend/src/controllers/middlewaresControllers/createAuthMiddleware/login.js +++ b/backend/src/controllers/middlewaresControllers/createAuthMiddleware/login.js @@ -11,21 +11,25 @@ const { loadSettings } = require('@/middlewares/settings'); const { useAppSettings } = require('@/settings'); const authUser = require('./authUser'); +const reCaptcha = require('./reCaptcha') const login = async (req, res, { userModel }) => { const UserPasswordModel = mongoose.model(userModel + 'Password'); const UserModel = mongoose.model(userModel); - const { email, password } = req.body; + + const { loginData,recaptchaToken} = req.body; + const {email,password} = loginData; // validate const objectSchema = Joi.object({ email: Joi.string() .email({ tlds: { allow: true } }) .required(), - password: Joi.string().required(), - }); + password: Joi.string().required(), + recaptchaToken : Joi.string().required() + }); - const { error, value } = objectSchema.validate({ email, password }); + const { error, value } = objectSchema.validate({ email, password,recaptchaToken }); if (error) { return res.status(409).json({ success: false, @@ -55,7 +59,8 @@ const login = async (req, res, { userModel }) => { message: 'Your account is disabled, contact your account adminstrator', }); - // authUser if your has correct password + await reCaptcha(recaptchaToken); + authUser(req, res, { user, databasePassword, password, UserPasswordModel }); }; diff --git a/backend/src/controllers/middlewaresControllers/createAuthMiddleware/reCaptcha.js b/backend/src/controllers/middlewaresControllers/createAuthMiddleware/reCaptcha.js new file mode 100644 index 000000000..dab2f562a --- /dev/null +++ b/backend/src/controllers/middlewaresControllers/createAuthMiddleware/reCaptcha.js @@ -0,0 +1,22 @@ +const axios = require('axios') +const reCaptcha = async({response}) =>{ + const SECRET_KEY = process.env.RECAPTCHA_SECRET_KEY; + const url = `https://www.google.com/recaptcha/api/siteverify?secret=${SECRET_KEY}&response=${response}`; + + try{ const reCaptchaResponse = await axios.post(url,{}); + if(reCaptchaResponse.success == false) + return res.status(409).json({ + success: false, + result: null, + message: 'Captcha was wrong.Retry', + }); } + catch(error){ + console.error('Error verifying reCAPTCHA:', error); + return { + success: false, + result: null, + message: 'Error verifying reCAPTCHA', + }; + } +} +module.exports = reCaptcha; \ No newline at end of file diff --git a/frontend/.env b/frontend/.env index e179ff244..8a4c30475 100644 --- a/frontend/.env +++ b/frontend/.env @@ -2,4 +2,5 @@ # ----> Remove # comment VITE_FILE_BASE_URL = 'http://localhost:8888/' VITE_BACKEND_SERVER="http://your_backend_url_server.com/" -PROD = false \ No newline at end of file +PROD = false +# SITE_KEY = RECAPTCHA_SITE_KEY \ No newline at end of file diff --git a/frontend/index.html b/frontend/index.html index 165630563..a05fdde8c 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -7,6 +7,7 @@ IDURAR ERP CRM | Open Code Source +
diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 806b68ce3..59f9678dd 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "idurar-erp-crm", - "version": "4.0.0-beta.3", + "version": "4.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "idurar-erp-crm", - "version": "4.0.0-beta.3", + "version": "4.0.0", "dependencies": { "@ant-design/icons": "^5.3.0", "@ant-design/pro-layout": "^7.17.19", diff --git a/frontend/src/pages/Login.jsx b/frontend/src/pages/Login.jsx index c1f8a1f5d..0ef764dd9 100644 --- a/frontend/src/pages/Login.jsx +++ b/frontend/src/pages/Login.jsx @@ -19,10 +19,15 @@ const LoginPage = () => { const navigate = useNavigate(); // const size = useSize(); - const dispatch = useDispatch(); - const onFinish = (values) => { - dispatch(login({ loginData: values })); - }; + const onFinish = async (values) => { + try { + const token = await grecaptcha.execute(YOUR_SITE_KEY, { action: 'submit' }); + console.log(token); + dispatch(login({ loginData: values, recaptchaToken: token })); + } catch (error) { + console.error('Error executing reCAPTCHA:', error); + } + } useEffect(() => { if (isSuccess) navigate('/');