Skip to content

Commit

Permalink
#2697 captcha to feedback from submission (#2792)
Browse files Browse the repository at this point in the history
* opening and closing modal without functionality

* work in progress

* sending and reciving endpoint information

* pre google captcha

* pre secret stored captcha

* backend recaptcha secret key applied

* work in progress

* added captcha for signin, signup; yaml documentation for /feedback, removed captcha from feedback

* refactoring after CR

* fix for modal errors and feedback alert

* test fix

* CR fix

* test setup

* fix 1

* test fix

* CR fix number of clicking on btn in test

Co-authored-by: Oskar Kocjan <oskarkocjan@Oskar-Kocjan.local>
  • Loading branch information
OskarKocjan and Oskar Kocjan committed Sep 1, 2022
1 parent f72c52b commit 90898ec
Show file tree
Hide file tree
Showing 18 changed files with 457 additions and 48 deletions.
28 changes: 25 additions & 3 deletions verification/curator-service/api/openapi/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -957,19 +957,19 @@ paths:
description: The northing coordinate (UTMY)
required: true
schema:
type: number
type: number
- name: e
in: query
description: The easting coordinate (UTMX)
required: true
schema:
type: number
type: number
- name: z
in: query
required: true
description: The UTM zone.
schema:
type: number
type: number
responses:
'200':
$ref: '#/components/responses/200Position'
Expand Down Expand Up @@ -1121,6 +1121,28 @@ paths:
$ref: '#/components/responses/422'
'500':
$ref: '#/components/responses/500'
/feedback:
post:
summary: Sends feedback email to global.health
tags: [User]
operationId: feedback
requestBody:
description: Email and message of User
required: true
content:
application/json:
schema:
description: Message sent to global.health as feedback
type: object
properties:
message:
type: string
responses:
'200':
$ref: '#/components/responses/200'
'500':
$ref: '#/components/responses/500'

components:
schemas:
Parser:
Expand Down
33 changes: 31 additions & 2 deletions verification/curator-service/api/src/controllers/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import * as crypto from 'crypto';
import EmailClient from '../clients/email-client';
import { ObjectId } from 'mongodb';
import { baseURL, welcomeEmail } from '../util/instance-details';
import { validateRecaptchaToken } from '../util/validate-recaptcha-token';
import {
setupFailedAttempts,
handleCheckFailedAttempts,
Expand Down Expand Up @@ -206,7 +207,21 @@ export class AuthController {
this.router.post(
'/signup',
registerLimiter,
(req: Request, res: Response, next: NextFunction): void => {
async (
req: Request,
res: Response,
next: NextFunction,
): Promise<void> => {
const captchaResult = await validateRecaptchaToken(
req.body.token,
);

if (!captchaResult)
res.status(403).json({
message:
"Unfortunately, you didn't pass the captcha. Please, try again later.",
});

passport.authenticate(
'register',
(error: Error, user: IUser, info: any) => {
Expand All @@ -229,7 +244,21 @@ export class AuthController {
this.router.post(
'/signin',
loginLimiter,
(req: Request, res: Response, next: NextFunction): void => {
async (
req: Request,
res: Response,
next: NextFunction,
): Promise<void> => {
const captchaResult = await validateRecaptchaToken(
req.body.token,
);

if (!captchaResult)
res.status(403).json({
message:
"Unfortunately, you didn't pass the captcha. Please, try again later.",
});

passport.authenticate(
'login',
(
Expand Down
28 changes: 28 additions & 0 deletions verification/curator-service/api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,33 @@ async function makeApp() {

app.use('/api', apiRouter);

//Send feedback from user to global.health email
app.post(
'/feedback',
mustBeAuthenticated,
async (req: Request, res: Response) => {
const { message } = req.body;

try {
await emailClient.send(
[env.EMAIL_USER_ADDRESS],
'Feedback regarding Covid-19 curator portal',
message,
);
return res
.status(200)
.json({ message: 'Email sent successfully' });
} catch (err) {
const error = err as Error;
logger.error(error);
return res.status(500).json({
message:
'Unfortunately, an error occurred. Please, try again later.',
});
}
},
);

// Basic health check handler.
app.get('/health', async (req: Request, res: Response) => {
try {
Expand Down Expand Up @@ -483,6 +510,7 @@ async function makeApp() {
format: winston.format.json(),
}),
);

return app;
}

Expand Down
8 changes: 8 additions & 0 deletions verification/curator-service/api/src/util/validate-env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,5 +118,13 @@ export default function validateEnv(): Readonly<{
desc: 'Name of the disease that should be displayed in Curator UI',
devDefault: 'COVID-19',
}),
RECAPTCHA_SITE_KEY: str({
desc: 'Key for recaptcha component',
devDefault: '',
}),
RECAPTCHA_SECRET_KEY: str({
desc: 'Key to validate recaptcha request',
devDefault: '',
}),
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import axios from 'axios';
import validateEnv from './validate-env';

export const validateRecaptchaToken = async (
token: string,
): Promise<boolean> => {
const env = validateEnv();
const response = await axios.post(
`https://www.google.com/recaptcha/api/siteverify?secret=${env.RECAPTCHA_SECRET_KEY}&response=${token}`,
);

return response.data.success;
};
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ describe('<AcknowledgmentsPage />', function () {
response: 'fixture:acknowledgment_data.json',
delay: 3000,
}).as('fetchSources');

cy.visit('/data-acknowledgments');
cy.contains(/Data Acknowledgments/i);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,8 @@ describe('LandingPage', function () {
cy.get('#passwordConfirmation').type('tT$5aaaaak');
cy.get('#isAgreementChecked').check();
for (let i = 0; i < 5; i++) {
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(1500);
cy.get('button[data-testid="sign-up-button"]').click();
}
cy.contains(
Expand All @@ -229,6 +231,8 @@ describe('LandingPage', function () {
cy.get('#email').type('test@example.com');
cy.get('#password').type('test');
for (let i = 0; i < 5; i++) {
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(1500);
cy.get('button[data-testid="sign-in-button"]').click();
}
cy.contains(/Too many failed login attempts, please try again later/i);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe('New case form', function () {
});
cy.addSource('Test source', 'www.example.com');

cy.visit('/')
cy.visit('/');
cy.visit('/cases/new');
cy.contains('Create new COVID-19 line list case');
cy.get('div[data-testid="caseReference"]').type('www.example.com');
Expand Down Expand Up @@ -51,7 +51,7 @@ describe('New case form', function () {
geoResolution: 'Country',
});

cy.visit('/')
cy.visit('/');
cy.visit('/cases/new');
cy.contains('Create new COVID-19 line list case');
cy.get('div[data-testid="caseReference"]').type('www.new-source.com');
Expand All @@ -74,7 +74,7 @@ describe('New case form', function () {
cy.contains('France');
cy.contains('2020-01-01');

cy.visit('/')
cy.visit('/');
cy.visit('/sources');
cy.contains('www.new-source.com');
cy.contains('New source');
Expand All @@ -90,7 +90,7 @@ describe('New case form', function () {
});
cy.addSource('Test source', 'www.example.com');

cy.visit('/')
cy.visit('/');
cy.visit('/cases/new');
cy.contains('Create new COVID-19 line list case');
cy.get('div[data-testid="caseReference"]').type('www.example.com');
Expand All @@ -111,7 +111,7 @@ describe('New case form', function () {
});

it('Can submit events without dates', function () {
cy.visit('/')
cy.visit('/');
cy.visit('/cases');
cy.contains('No records to display');
cy.seedLocation({
Expand All @@ -122,7 +122,7 @@ describe('New case form', function () {
});
cy.addSource('Test source', 'www.example.com');

cy.visit('/')
cy.visit('/');
cy.visit('/cases/new');
cy.get('div[data-testid="caseReference"]').type('www.example.com');
cy.contains('li', 'www.example.com').click();
Expand Down Expand Up @@ -164,7 +164,7 @@ describe('New case form', function () {
});
cy.addSource('Test source', 'www.example.com');

cy.visit('/')
cy.visit('/');
cy.visit('/cases/new');
cy.contains('Create new COVID-19 line list case');
cy.get('div[data-testid="caseReference"]').type('www.example.com');
Expand Down Expand Up @@ -246,7 +246,7 @@ describe('New case form', function () {
symptoms: ['fever', 'cough'],
});

cy.visit('/')
cy.visit('/');
cy.visit('/cases/new');
cy.contains('Create new COVID-19 line list case');
cy.get('div[data-testid="caseReference"]').type('www.example.com');
Expand Down Expand Up @@ -301,11 +301,11 @@ describe('New case form', function () {
geoResolution: 'Country',
});
cy.addSource('Test source', 'www.example.com');
cy.visit('/')
cy.visit('/');
cy.visit('/cases');
cy.contains('No records to display');

cy.visit('/')
cy.visit('/');
cy.visit('/cases/new');
cy.get('div[data-testid="caseReference"]').type('www.example.com');
cy.contains('li', 'www.example.com').click();
Expand All @@ -330,7 +330,7 @@ describe('New case form', function () {
});

it('Can change source URL without changing source name', function () {
cy.visit('/')
cy.visit('/');
cy.visit('/cases/new');

cy.get('div[data-testid="caseReference"]').type('www.example.com');
Expand All @@ -345,14 +345,14 @@ describe('New case form', function () {
});

it('Check for required fields', function () {
cy.visit('/')
cy.visit('/');
cy.visit('/cases/new');

cy.get('p:contains("Required")').should('have.length', 3);
});

it('Shows checkbox on field completion', function () {
cy.visit('/')
cy.visit('/');
cy.visit('/cases/new');
cy.get('svg[data-testid="check-icon"]').should('not.exist');
cy.get('div[data-testid="gender"]').click();
Expand All @@ -361,7 +361,7 @@ describe('New case form', function () {
});

it('Shows error icon on field submission error', function () {
cy.visit('/')
cy.visit('/');
cy.visit('/cases/new');
cy.get('svg[data-testid="error-icon"]').should('not.exist');
cy.get('svg[data-testid="check-icon"]').should('not.exist');
Expand Down
Loading

0 comments on commit 90898ec

Please sign in to comment.