Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#2697 captcha to feedback from submission #2792

Merged
merged 18 commits into from
Sep 1, 2022
Merged
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 @@ -218,7 +218,9 @@ describe('LandingPage', function () {
cy.get('#password').type('tT$5aaaaak');
cy.get('#passwordConfirmation').type('tT$5aaaaak');
cy.get('#isAgreementChecked').check();
for (let i = 0; i < 5; i++) {
for (let i = 0; i < 7; i++) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is the Sign-in button being clicked so many times?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is clicked so many times to trigger the login/register limiter that will be used after 4 unsuccessful attempts. I will change the number of clicks to the previous commit which is 5 times.

// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(1500);
cy.get('button[data-testid="sign-up-button"]').click();
}
cy.contains(
Expand All @@ -228,7 +230,9 @@ describe('LandingPage', function () {
cy.contains('Sign in!').click();
cy.get('#email').type('test@example.com');
cy.get('#password').type('test');
for (let i = 0; i < 5; i++) {
for (let i = 0; i < 7; 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