Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 19 additions & 119 deletions api/controllers/ViewController.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
*/
const Boom = require('@hapi/boom');
const Hoek = require('@hapi/hoek');
const Recaptcha = require('recaptcha2');
const Client = require('../models/Client');
const User = require('../models/User');
const EmailService = require('../services/EmailService');
Expand All @@ -17,8 +16,9 @@ const config = require('../../config/env');
const { logger } = config;

function _getRegisterLink(args) {
// Registrations disabled. No register page link.
const params = HelperService.getOauthParams(args);
let registerLink = '/register';
let registerLink = '/';
if (params) {
registerLink += `?${params}`;
}
Expand All @@ -27,11 +27,11 @@ function _getRegisterLink(args) {

function _getPasswordLink(args) {
const params = HelperService.getOauthParams(args);
let registerLink = '/password';
let passwordLink = '/password';
if (params) {
registerLink += `?${params}`;
passwordLink += `?${params}`;
}
return registerLink;
return passwordLink;
}

function _buildRequestUrl(request, url) {
Expand Down Expand Up @@ -216,125 +216,25 @@ module.exports = {
},

register(request, reply) {
const requestUrl = _buildRequestUrl(request, 'verify');
return reply.view('register', {
title: 'Register a Humanitarian ID account',
formEmail: '',
formGivenName: '',
formFamilyName: '',
requestUrl,
recaptcha_site_key: process.env.RECAPTCHA_PUBLIC_KEY,
// Early return, no registration allowed.
return reply.view('login', {
alert: {
type: 'error',
message: 'No new registrations are accepted.',
},
query: request.query,
});
},

async registerPost(request, reply) {
// Check recaptcha
const recaptcha = new Recaptcha({
siteKey: process.env.RECAPTCHA_PUBLIC_KEY,
secretKey: process.env.RECAPTCHA_PRIVATE_KEY,
// Early return, no registration allowed.
return reply.view('login', {
alert: {
type: 'error',
message: 'No new registrations are accepted.',
},
query: request.query,
});
const registerLink = _getRegisterLink(request.payload);
const passwordLink = _getPasswordLink(request.payload);
let requestUrl = _buildRequestUrl(request, 'verify');

// Validate the visitor's response to reCAPTCHA challenge.
try {
await recaptcha.validate(request.payload['g-recaptcha-response']);
} catch (err) {
const errorType = 'RECAPTCHA';

logger.warn(
'[ViewController->registerPost] Failure during reCAPTCHA validation.',
{
request,
security: true,
fail: true,
stack_trace: err.stack,
error_type: errorType,
},
);

return reply.view('register', {
alert: {
type: 'error',
message: `
<p>Our system detected your registration attempt as spam. We apologize for the inconvenience.</p>
<p>For more information on why this problem may be occurring, <a href="https://about.humanitarian.id/faqs">please see our FAQs</a></p>
`,
error_type: errorType,
},
formEmail: request.payload.email,
formGivenName: request.payload.given_name,
formFamilyName: request.payload.family_name,
query: request.query,
registerLink,
passwordLink,
requestUrl,
recaptcha_site_key: process.env.RECAPTCHA_PUBLIC_KEY,
});
}

// reCAPTCHA validation was successful. Proceed.
try {
// Attempt to create a new HID account.
await UserController.create(request);

// Render login form with success message.
return reply.view('login', {
alert: {
type: 'status',
message: 'Thank you for creating an account. You will soon receive a confirmation email to confirm your account.',
},
query: request.query,
registerLink,
passwordLink,
});
} catch (err) {
// Check if we have an error worth telling the user about.
const errorMessage = err.output && err.output.payload && err.output.payload.message;
let userMessage = 'There is an error in your registration. You may have already registered. If so, simply reset your password at https://auth.humanitarian.id/password.';

// If the error says the email already exists, we'll redirect to login.
if (errorMessage && errorMessage.indexOf('is already registered') !== -1) {
userMessage = 'That email address is already registered. Please login, or if you\'ve forgotten your password, reset using the link below.';

return reply.view('login', {
alert: {
type: 'error',
message: userMessage,
},
query: request.query,
registerLink,
passwordLink,
});
}

// Check the error for a few special cases to provide better user feedback.
// All of these will render the registration form.
if (errorMessage && errorMessage.indexOf('password does not meet') !== -1) {
userMessage = 'Your password was not strong enough. Please check the requirements and try again.';
}
if (errorMessage && errorMessage.indexOf('fields do not match') !== -1) {
userMessage = 'Your password fields did not match. Please try again and carefully confirm the password.';
}

// Add a domain from the allow-list.
requestUrl = _buildRequestUrl(request, 'register');

// Render registration form.
return reply.view('register', {
alert: {
type: 'warning',
message: userMessage,
},
query: request.query,
formEmail: request.payload.email,
formGivenName: request.payload.given_name,
formFamilyName: request.payload.family_name,
requestUrl,
recaptcha_site_key: process.env.RECAPTCHA_PUBLIC_KEY,
});
}
},

async verify(request, reply) {
Expand Down
5 changes: 4 additions & 1 deletion config/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ module.exports = [
* Public-facing pages
*
* None of these routes require a session. Account setup/recovery actions are
* all included here: registration, verify, password reset, API docs, etc.
* all included here: verify, password reset, API docs, etc.
* Registration is disabled - https://humanitarian.atlassian.net/browse/HID-2438
*/
{
method: 'GET',
Expand All @@ -46,6 +47,7 @@ module.exports = [
},
},

/*
{
method: 'GET',
path: '/register',
Expand All @@ -63,6 +65,7 @@ module.exports = [
auth: false,
},
},
*/

{
method: 'GET',
Expand Down
1 change: 0 additions & 1 deletion config/web.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@ const config = {
'/',
'/login',
'/oauth/authorize',
'/register',
Copy link
Contributor

Choose a reason for hiding this comment

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

Note: since the register route is removed here, the "No new registrations are accepted." doesn't appear and a 404 is shown instead:

Image

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can live with that :-)

'/verify',
'/password',
'/new-password',
Expand Down
1 change: 0 additions & 1 deletion templates/login.html
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ <h1 class="cd-page-title page-header__heading">Log in</h1>
</div>
</form>

<p><a href="<%= registerLink %>">Register a new Humanitarian ID Account</a></p>
<p><a href="<%= passwordLink %>">Forgot/Reset password</a></p>
</div>

Expand Down
66 changes: 15 additions & 51 deletions templates/register.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,61 +4,25 @@
<script src="https://www.google.com/recaptcha/api.js" async defer></script>

<main aria-label="Page content" id="main-content" class=" cd-layout cd-container">
<%- include('includes/alert') %>
<div class="cd-layout__content [ cd-flow ]">
<h1 class="cd-page-title page-header__heading">Register a Humanitarian ID account</h1>

<%- include('includes/alert') %>

<form id="passwordForm" name="register" action="/register" method="POST" class="[ cd-flow ]">
<div class="form-field">
<label for="email" translate>Email</label>
<input type="email" name="email" id="email" value="<%= formEmail %>" placeholder="you@example.com" required>
</div>
<div class="form-field">
<label for="given_name">First Name</label>
<input type="text" name="given_name" id="given_name" value="<%= formGivenName %>" placeholder="Your first name" required>
</div>
<div class="form-field">
<label for="family_name">Last Name</label>
<input type="text" name="family_name" id="family_name" value="<%= formFamilyName %>" placeholder="Your last name" required>
</div>
<div class="form-field">
<label for="password">Password</label>
<input
type="password"
name="password"
id="password"
autocomplete="off"
required
minlength="12"
pattern="<%- include('includes/password-regex') %>"
title="See password requirements below.">
<button type="button" class="password__viz-toggle viz-toggle viz-toggle--see">
<span class="visually-hidden">Toggle password visibility</span>
</button>
<div class="cd-alert">
<div role="status" aria-label="Info message">
<svg class="cd-icon cd-icon--about" aria-hidden="true" focusable="false" width="16" height="16">
<use xlink:href="#cd-icon--about">
<symbol viewBox="0 0 42 42" id="cd-icon--about" xmlns="http://www.w3.org/2000/svg">
<path d="M38 0H4a4 4 0 0 0-4 4v34a4 4 0 0 0 4 4h34a4 4 0 0 0 4-4V4a4 4 0 0 0-4-4ZM24 35h-4a2 2 0 0 1-2-2V18h4a2 2 0 0 1 2 2Zm-3-22a3 3 0 1 1 3-3 3 3 0 0 1-3 3Z"></path>
</symbol>
</use>
</svg>
<div class="cd-alert__container cd-max-width">
After careful review, the Humanitarian ID project will be decommissioned as of 31 December 2025. New account registrations are disabled.
</div>
</div>
<div class="form-field">
<label for="confirm_password">Confirm password</label>
<input
type="password"
name="confirm_password"
id="confirm_password"
autocomplete="off"
required
minlength="12"
pattern="<%- include('includes/password-regex') %>"
title="See password requirements below.">
<button type="button" class="password__viz-toggle viz-toggle viz-toggle--see">
<span class="visually-hidden">Toggle password visibility</span>
</button>
</div>
<div class="form-field">
<%- include('includes/password-requirements') %>
</div>
<div class="g-recaptcha" data-sitekey="<%= recaptcha_site_key %>"></div>
<input type="hidden" name="crumb" value="<%= crumb %>" />
<button type="submit" class="cd-button cd-button--bold cd-button--wide cd-button--uppercase t-btn--register">Register</button>
</form>
</div>

</div>
</main>

Expand Down