From 3953f441430aa901d47091cd8fad5d0b544f0420 Mon Sep 17 00:00:00 2001 From: James-jamames Date: Thu, 7 Dec 2023 16:54:54 -0300 Subject: [PATCH 1/2] + Recaptcha --- src/client/package-lock.json | 32 ++++++++++ src/client/package.json | 3 +- .../src/app/@core/interfaces/contact.ts | 2 +- src/client/src/app/app.module.ts | 11 +++- .../pages/contato/contato.component.ts | 61 ++++++++++--------- .../src/environments/environment.homolog.ts | 5 +- .../src/environments/environment.prod.ts | 5 +- src/client/src/environments/environment.ts | 5 +- src/server/controllers/contact.js | 5 -- src/server/database/queries/contact.js | 8 +-- src/server/middleware/data-injector.js | 1 - src/server/middleware/re-captcha.js | 16 +++++ src/server/routes/contact.js | 3 +- 13 files changed, 110 insertions(+), 47 deletions(-) create mode 100644 src/server/middleware/re-captcha.js diff --git a/src/client/package-lock.json b/src/client/package-lock.json index b311af0..7a6a5d8 100644 --- a/src/client/package-lock.json +++ b/src/client/package-lock.json @@ -37,6 +37,7 @@ "jspdf-autotable": "^3.5.23", "lodash-es": "^4.17.21", "moment": "^2.29.1", + "ng-recaptcha": "^8.0.1", "ngx-drag-scroll": "^12.0.0-beta.1", "ol": "6.14.1", "ol-ext": "3.2.13", @@ -2933,6 +2934,11 @@ "@types/node": "*" } }, + "node_modules/@types/grecaptcha": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/grecaptcha/-/grecaptcha-3.0.7.tgz", + "integrity": "sha512-ah5GDQfsiK3dnkaCbYcDFZXkZCG3o90VRu9hzXHnSe4kACrRB1KUI/ZyWHvYmqm1W5Tl8B5YxxT98uGTlkbf2Q==" + }, "node_modules/@types/jasmine": { "version": "3.8.2", "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.8.2.tgz", @@ -10146,6 +10152,18 @@ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" }, + "node_modules/ng-recaptcha": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ng-recaptcha/-/ng-recaptcha-8.0.1.tgz", + "integrity": "sha512-Urc/0iGof9gqdXJ3HydpDrDlS3qLnjYLHqabCexpci8H3g6fYPeVWCKa2/haDHPUiyGc/+SXUaf7qTHlzJjObg==", + "dependencies": { + "@types/grecaptcha": "^3.0.1", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/core": "^12.0.0" + } + }, "node_modules/ngx-drag-scroll": { "version": "12.0.0-beta.2", "resolved": "https://registry.npmjs.org/ngx-drag-scroll/-/ngx-drag-scroll-12.0.0-beta.2.tgz", @@ -19606,6 +19624,11 @@ "@types/node": "*" } }, + "@types/grecaptcha": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/grecaptcha/-/grecaptcha-3.0.7.tgz", + "integrity": "sha512-ah5GDQfsiK3dnkaCbYcDFZXkZCG3o90VRu9hzXHnSe4kACrRB1KUI/ZyWHvYmqm1W5Tl8B5YxxT98uGTlkbf2Q==" + }, "@types/jasmine": { "version": "3.8.2", "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.8.2.tgz", @@ -25300,6 +25323,15 @@ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" }, + "ng-recaptcha": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ng-recaptcha/-/ng-recaptcha-8.0.1.tgz", + "integrity": "sha512-Urc/0iGof9gqdXJ3HydpDrDlS3qLnjYLHqabCexpci8H3g6fYPeVWCKa2/haDHPUiyGc/+SXUaf7qTHlzJjObg==", + "requires": { + "@types/grecaptcha": "^3.0.1", + "tslib": "^2.0.0" + } + }, "ngx-drag-scroll": { "version": "12.0.0-beta.2", "resolved": "https://registry.npmjs.org/ngx-drag-scroll/-/ngx-drag-scroll-12.0.0-beta.2.tgz", diff --git a/src/client/package.json b/src/client/package.json index 102413c..89d7ed5 100755 --- a/src/client/package.json +++ b/src/client/package.json @@ -40,6 +40,7 @@ "jspdf-autotable": "^3.5.23", "lodash-es": "^4.17.21", "moment": "^2.29.1", + "ng-recaptcha": "^8.0.1", "ngx-drag-scroll": "^12.0.0-beta.1", "ol": "6.14.1", "ol-ext": "3.2.13", @@ -66,4 +67,4 @@ "karma-jasmine-html-reporter": "~1.7.0", "typescript": "~4.3.2" } -} \ No newline at end of file +} diff --git a/src/client/src/app/@core/interfaces/contact.ts b/src/client/src/app/@core/interfaces/contact.ts index c485911..7463891 100755 --- a/src/client/src/app/@core/interfaces/contact.ts +++ b/src/client/src/app/@core/interfaces/contact.ts @@ -4,5 +4,5 @@ export interface Contact { subject: string; institution: string; message: string; - status: string; + token: string; } \ No newline at end of file diff --git a/src/client/src/app/app.module.ts b/src/client/src/app/app.module.ts index 8a3cce0..3dd6b34 100755 --- a/src/client/src/app/app.module.ts +++ b/src/client/src/app/app.module.ts @@ -14,6 +14,8 @@ import { environment } from '../environments/environment'; import { HttpClient, HTTP_INTERCEPTORS } from '@angular/common/http'; import { NoCacheHeaders } from "./@core/interceptors/no-cache-headers.interceptor"; +import { RECAPTCHA_V3_SITE_KEY, RecaptchaV3Module } from 'ng-recaptcha'; + /** * The http loader factory : Loads the files from define path. * @param {HttpClient} http @@ -31,6 +33,7 @@ export function HttpLoaderFactory(http: HttpClient) { AppComponent ], imports: [ + RecaptchaV3Module, BrowserModule, BrowserAnimationsModule, AppRoutingModule, @@ -50,11 +53,15 @@ export function HttpLoaderFactory(http: HttpClient) { } }), ], - providers: [ { + providers: [{ provide: HTTP_INTERCEPTORS, useClass: NoCacheHeaders, multi: true - },], + }, + { + provide: RECAPTCHA_V3_SITE_KEY, + useValue: environment.recaptcha.siteKey, + }], bootstrap: [AppComponent], }) diff --git a/src/client/src/app/hotsite/pages/contato/contato.component.ts b/src/client/src/app/hotsite/pages/contato/contato.component.ts index cf1038c..fe876f9 100755 --- a/src/client/src/app/hotsite/pages/contato/contato.component.ts +++ b/src/client/src/app/hotsite/pages/contato/contato.component.ts @@ -1,11 +1,9 @@ import { Component, OnInit } from '@angular/core'; import { NgForm } from '@angular/forms'; -import { error } from 'console'; import { MessageService } from 'primeng/api'; -//import {InputTextModule} from 'primeng/inputtext'; -import {InputTextareaModule} from 'primeng/inputtextarea'; import { LocalizationService } from 'src/app/@core/internationalization/localization.service'; import { ContatoService } from './contato.service'; +import { ReCaptchaV3Service } from 'ng-recaptcha'; @Component({ selector: 'app-contato', @@ -19,41 +17,48 @@ export class ContatoComponent implements OnInit { constructor( private contatoService: ContatoService, protected messageService: MessageService, - public localizationService: LocalizationService) { + public localizationService: LocalizationService, + private recaptchaV3Service: ReCaptchaV3Service) { } ngOnInit() { } onSubmit(contactForm: NgForm) { - if (contactForm.valid) { - this.erroForm = false; - - const contact = contactForm.value; - contact.status = "RECEIVED"; - this.contatoService.saveContact(contactForm.value).subscribe((result) => { - if(result.message === "sucess") { - contactForm.reset(); + this.recaptchaV3Service.execute('importantAction') + .subscribe((token: string) => { + if (contactForm.valid) { + this.erroForm = false; + + const contact = contactForm.value; + contact.token = token; + console.log(contact); + this.contatoService.saveContact(contact).subscribe((result) => { + if(result.message === "sucess") { + contactForm.reset(); + this.messageService.add({ + key: "contact-message", + life: 2000, + severity: 'success', + summary: this.localizationService.translate('hotsite.contact.submit-message.success'), + detail: this.localizationService.translate('hotsite.contact.submit-message.success') + }) + } + }, (error)=>{ this.messageService.add({ key: "contact-message", life: 2000, - severity: 'success', - summary: this.localizationService.translate('hotsite.contact.submit-message.success'), - detail: this.localizationService.translate('hotsite.contact.submit-message.success') + severity: 'error', + summary: this.localizationService.translate('hotsite.contact.submit-message.fail'), + detail: this.localizationService.translate('hotsite.contact.submit-message.fail') }) - } - }, (error)=>{ - this.messageService.add({ - key: "contact-message", - life: 2000, - severity: 'error', - summary: this.localizationService.translate('hotsite.contact.submit-message.fail'), - detail: this.localizationService.translate('hotsite.contact.submit-message.fail') - }) - }); - } else { - this.erroForm = true; - } + }); + } else { + this.erroForm = true; + } + }); + + } getErroForm(): boolean { diff --git a/src/client/src/environments/environment.homolog.ts b/src/client/src/environments/environment.homolog.ts index 312499f..fdf0760 100755 --- a/src/client/src/environments/environment.homolog.ts +++ b/src/client/src/environments/environment.homolog.ts @@ -23,5 +23,8 @@ export const environment = { LAPIG_DOWNLOAD_API: 'https://download.lapig.iesa.ufg.br', S3: "https://s3.lapig.iesa.ufg.br/storage/", MAX_AREA: 9500, - COMMIT_ID:commitId + COMMIT_ID:commitId, + recaptcha: { + siteKey: '6Lf_jygpAAAAAO-8ArU28R6EszgO2WhCArk06nPm', + }, }; diff --git a/src/client/src/environments/environment.prod.ts b/src/client/src/environments/environment.prod.ts index 500feff..c0b6299 100755 --- a/src/client/src/environments/environment.prod.ts +++ b/src/client/src/environments/environment.prod.ts @@ -23,5 +23,8 @@ export const environment = { LAPIG_DOWNLOAD_API: 'https://download.lapig.iesa.ufg.br', S3: "https://s3.lapig.iesa.ufg.br/storage/", MAX_AREA: 9500, - COMMIT_ID:commitId + COMMIT_ID:commitId, + recaptcha: { + siteKey: '6Lf_jygpAAAAAO-8ArU28R6EszgO2WhCArk06nPm', + }, }; diff --git a/src/client/src/environments/environment.ts b/src/client/src/environments/environment.ts index 59c07a7..2074ae0 100755 --- a/src/client/src/environments/environment.ts +++ b/src/client/src/environments/environment.ts @@ -26,7 +26,10 @@ export const environment = { LAPIG_CONTENT_HUB: 'https://content-hub.lapig.iesa.ufg.br', S3: "https://s3.lapig.iesa.ufg.br/storage/", MAX_AREA: 9500, - COMMIT_ID:commitId + COMMIT_ID:commitId, + recaptcha: { + siteKey: '6Lf_jygpAAAAAO-8ArU28R6EszgO2WhCArk06nPm', + }, }; /* diff --git a/src/server/controllers/contact.js b/src/server/controllers/contact.js index ee617cc..f410778 100755 --- a/src/server/controllers/contact.js +++ b/src/server/controllers/contact.js @@ -1,15 +1,10 @@ module.exports = function (app) { var Controller = {} - var Internal = {} Controller.create = function (request, response) { - // var rows = request.queryResult['create']; - response.status(201).send({ message: "sucess" }); response.end(); - } return Controller; - } \ No newline at end of file diff --git a/src/server/database/queries/contact.js b/src/server/database/queries/contact.js index 242127d..7520f4b 100755 --- a/src/server/database/queries/contact.js +++ b/src/server/database/queries/contact.js @@ -1,23 +1,21 @@ module.exports = function(app) { - - var Internal = {} var Query = {}; Query.defaultParams = {} Query.create = function(params) { - const { name, email, subject, institution, message, status } = params['contact']; + const { name, email, subject, institution, message } = params['contact']; return [{ source: 'lapig', id: 'create', - sql: `INSERT INTO public.contato_atlas ("name", email, subject, message, institution, status) VALUES('${name}', '${email}', '${subject}', '${message}', '${institution}', '${status}');`, + sql: `INSERT INTO public.contato_atlas ("name", email, subject, message, institution, status) VALUES('${name}', '${email}', '${subject}', '${message}', '${institution}', 'RECEIVED');`, mantain: true } ] } return Query; - +z } \ No newline at end of file diff --git a/src/server/middleware/data-injector.js b/src/server/middleware/data-injector.js index 8db8d67..ef11660 100755 --- a/src/server/middleware/data-injector.js +++ b/src/server/middleware/data-injector.js @@ -19,7 +19,6 @@ module.exports = function(app) { } return function(request, response, next) { - var hasController = (request.route.stack.length > 1) var pathParts = request.path.split('/') var controller = pathParts[2] diff --git a/src/server/middleware/re-captcha.js b/src/server/middleware/re-captcha.js new file mode 100644 index 0000000..44af1db --- /dev/null +++ b/src/server/middleware/re-captcha.js @@ -0,0 +1,16 @@ +module.exports = function(app) { + var Internal = {} + + Internal.validate = function(token) { + return true; + } + + return function(request, response, next) { + console.log(request.body.contact) + if(Internal.validate()) { + next(); + } else { + return response.status(401).send({ message: "Unauthorized" }); + } + } +} \ No newline at end of file diff --git a/src/server/routes/contact.js b/src/server/routes/contact.js index f048d1e..96e273b 100755 --- a/src/server/routes/contact.js +++ b/src/server/routes/contact.js @@ -2,6 +2,7 @@ module.exports = function(app) { const dataInjector = app.middleware.dataInjector; const contactController = app.controllers.contact; + const reCaptcha = app.middleware.reCaptcha; - app.post('/service/contact/create', dataInjector, contactController.create); + app.post('/service/contact/create', reCaptcha, dataInjector, contactController.create); } \ No newline at end of file From ff9d87cb4b222e6c550148992ec6cda5525e1678 Mon Sep 17 00:00:00 2001 From: James-jamames Date: Mon, 11 Dec 2023 15:05:30 -0300 Subject: [PATCH 2/2] + Re-captcha working fine --- src/server/middleware/re-captcha.js | 32 ++++++++++++++-------- src/server/package-lock.json | 41 +++++++++++++++++++++++++++++ src/server/package.json | 1 + 3 files changed, 63 insertions(+), 11 deletions(-) diff --git a/src/server/middleware/re-captcha.js b/src/server/middleware/re-captcha.js index 44af1db..ec04a9d 100644 --- a/src/server/middleware/re-captcha.js +++ b/src/server/middleware/re-captcha.js @@ -1,16 +1,26 @@ -module.exports = function(app) { +const axios = require('axios') + +module.exports = function (app) { var Internal = {} - Internal.validate = function(token) { - return true; - } + var api = 'https://www.google.com/recaptcha/api/siteverify'; - return function(request, response, next) { - console.log(request.body.contact) - if(Internal.validate()) { - next(); - } else { - return response.status(401).send({ message: "Unauthorized" }); - } + return function (request, response, next) { + axios({ + method: 'post', + url: api, + headers: { "Content-Type": "application/x-www-form-urlencoded" }, + data: `secret=${process.env.RECAPTCHA_KEY}&response=${request.body.contact.token}`, + }).then(recaptcha => { + if(recaptcha.data.success) { + next(); + } else { + response.status(401) + .send({ message: "You are a robot" }) + } + }).catch(error => { + response.status(501) + .send({ message: "Sever error" }) + }); } } \ No newline at end of file diff --git a/src/server/package-lock.json b/src/server/package-lock.json index ef4e79f..282c296 100755 --- a/src/server/package-lock.json +++ b/src/server/package-lock.json @@ -15,6 +15,7 @@ "app-root-path": "^3.0.0", "archiver": "^5.3.0", "async": "~3.2.2", + "axios": "^0.24.0", "body-parser": "^1.19.0", "bson": ">=4.6.0", "compression": "^1.7.4", @@ -1381,6 +1382,14 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" }, + "node_modules/axios": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz", + "integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==", + "dependencies": { + "follow-redirects": "^1.14.4" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -2640,6 +2649,25 @@ "resolved": "https://registry.npmjs.org/findit/-/findit-2.0.0.tgz", "integrity": "sha512-ENZS237/Hr8bjczn5eKuBohLgaD0JyUd0arxretR1f9RO46vZHA1b2y0VorgGV3WaOT3c+78P8h7v4JGJ1i/rg==" }, + "node_modules/follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -5832,6 +5860,14 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" }, + "axios": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz", + "integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==", + "requires": { + "follow-redirects": "^1.14.4" + } + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -6802,6 +6838,11 @@ "resolved": "https://registry.npmjs.org/findit/-/findit-2.0.0.tgz", "integrity": "sha512-ENZS237/Hr8bjczn5eKuBohLgaD0JyUd0arxretR1f9RO46vZHA1b2y0VorgGV3WaOT3c+78P8h7v4JGJ1i/rg==" }, + "follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==" + }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", diff --git a/src/server/package.json b/src/server/package.json index 769c87c..c38c1fe 100755 --- a/src/server/package.json +++ b/src/server/package.json @@ -10,6 +10,7 @@ "app-root-path": "^3.0.0", "archiver": "^5.3.0", "async": "~3.2.2", + "axios": "^0.24.0", "body-parser": "^1.19.0", "bson": ">=4.6.0", "compression": "^1.7.4",