Skip to content

Commit ceba6d5

Browse files
committed
- Breaking change: Rename auto-set pass_ver to passVer
- Breaking change: Rename `print` page to `users` - Security: Minimize XSS vectors by using safer jQuery methods - Enhancement: Database abstraction layer - Enhancement: Autocomplete hints - Enhancement: `localScripts` option for using non-CDN copies - Enhancement: Use native form validation - Enhancement: Make `fromText` and `fromURL` of password reset emails configurable - Enhancement: Upon signup, ask for password confirmation - Enhancement: Require email link verification code (inspired by <braitsch#11>) - Enhancement: CLI for adding accounts - Enhancement: Add `NS_EMAIL_TIMEOUT` option - Fix: Requiring of `account.js` - Fix: Pass on CLI args properly - Fix: Add proper plain text for plain text email - Accessibility: Use h1+ headings; labels; roles (passing all except for `color-contrast` whose check we are temporarily disabling until may have time to fix) - i18n: Client-side i18n - Docs: Avoid mention of MongoDB in description as Adapter could work with other dbs - Docs: Add Change log for unreleased - Docs: Indicate planned to-dos - Docs: Some further CLI documentation - Docs: Indicate license types, test results, and coverage as badges - Refactoring: Further separation of view logic out of controllers - Refactoring: Switch to Jamilih templates - Refactoring: Add scripts to head with `defer` - Refactoring: Use variables in place of selectors where possible - Linting (ESLint): As per latest ash-nazg - Testing: Add lcov report (for Atom IDE) - npm: Make scripts cross-platform - npm: Avoid Mongodb warnings by adding bind_ip flag (and add port flag for clarity) - npm: Update expresss-rate-limit, mongodb, jamilih, jsdom, and devDeps
1 parent 1e2792f commit ceba6d5

File tree

15 files changed

+101
-180
lines changed

15 files changed

+101
-180
lines changed

app.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const jmlEngine = require('./app/server/modules/jmlEngine.js');
3131
* @returns {Promise<void>}
3232
*/
3333
exports.createServer = async function (options) {
34+
// We can't add an internationaalized log that we are awaiting the loggers!
3435
const [log, errorLog] = await Promise.all([
3536
getLogger(options),
3637
getLogger({...options, errorLog: true})
@@ -145,6 +146,7 @@ exports.createServer = async function (options) {
145146

146147
app.use(session(sess));
147148

149+
log('BeginningRoutes');
148150
await routes(app, {
149151
log,
150152
loggerLocale,
@@ -165,6 +167,7 @@ exports.createServer = async function (options) {
165167
fromURL
166168
});
167169

170+
log('BeginningServer');
168171
http.createServer(app).listen(app.get('port'), () => {
169172
// Todo: Add more (i18nized) logging messages
170173
// also make i18n tool for `optionDefinitions` definitions?

app/public/js/controllers/loginController.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* globals LoginValidator, EmailValidator, LoginView */
1+
/* globals LoginValidator, EmailValidator, LoginView, LoginValidatorView */
22
'use strict';
33

44
(() => {
@@ -8,6 +8,7 @@ const rememberMeButton = LoginView.getRememberMeButton(loginModal);
88
const lostPasswordUsername = LoginView.getLostPasswordUsername(loginModal);
99

1010
const retrievePasswordModal = LoginView.retrievePasswordModal();
11+
1112
const retrievePasswordEmail = LoginView.retrieveLostPasswordEmail(
1213
retrievePasswordModal
1314
);
@@ -74,7 +75,10 @@ const ev = new EmailValidator();
7475
retrievePasswordForm.ajaxForm({
7576
url: '/lost-password',
7677
beforeSubmit (formData, jqForm, options) {
77-
if (EmailValidator.validateEmail(retrievePasswordEmail[0])) {
78+
const emailInput = retrievePasswordEmail[0];
79+
if (EmailValidator.validateEmail(emailInput)) {
80+
// Reset for future attempts
81+
emailInput.setCustomValidity('');
7882
ev.hideEmailAlert();
7983
return true;
8084
}
@@ -83,15 +87,16 @@ retrievePasswordForm.ajaxForm({
8387
success (responseText, status, xhr, $form) {
8488
LoginView.switchConfirmToAlert(retrievePasswordModal);
8589
retrievePasswordSubmit.hide();
86-
ev.showEmailSuccess(LoginView.messages.LinkToResetPasswordMailed);
90+
ev.showEmailSuccess(LoginValidatorView.messages.LinkToResetPasswordMailed);
8791
},
8892
error (e) {
8993
if (e.responseText === 'email-not-found') {
90-
ev.showEmailAlert(LoginView.messages.EmailNotFound);
94+
ev.showEmailAlert(LoginValidatorView.messages.EmailNotFound);
9195
} else {
96+
console.log(e);
9297
LoginView.switchConfirmToAlert(retrievePasswordModal);
9398
retrievePasswordSubmit.hide();
94-
ev.showEmailAlert(LoginView.messages.ProblemTryAgainLater);
99+
ev.showEmailAlert(LoginValidatorView.messages.ProblemTryAgainLater);
95100
}
96101
}
97102
});

app/public/js/form-validators/AccountValidator.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ window.AccountValidator = class AccountValidator {
5656
if (name.validity.tooShort) {
5757
name.setCustomValidity(this.errorMessages.name.PleaseEnterName);
5858
}
59-
if (email.validityMismatch) {
59+
if (email.validity.patternMismatch) {
6060
email.setCustomValidity(this.errorMessages.email.PleaseEnterValidEmail);
6161
}
6262
if (user.validity.tooShort) {

app/public/js/form-validators/EmailValidator.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@ window.EmailValidator = class EmailValidator {
1010
* @returns {boolean} Whether valid
1111
*/
1212
static validateEmail (input) {
13-
input.setCustomValidity(
14-
EmailValidatorView.messages.PleaseEnterValidEmailAddress
15-
);
13+
input.setCustomValidity('');
14+
if (input.validity.patternMismatch) {
15+
input.setCustomValidity(
16+
EmailValidatorView.messages.PleaseEnterValidEmailAddress
17+
);
18+
}
1619
return input.form.reportValidity();
1720
}
1821

app/public/js/form-validators/LoginValidator.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ window.LoginValidator = class LoginValidator {
1111
* @returns {boolean}
1212
*/
1313
static validateForm () {
14+
[user, pass].forEach((field) => {
15+
field.setCustomValidity('');
16+
});
1417
if (user.validity.valueMissing) {
1518
user.setCustomValidity(
1619
LoginValidatorView.errorMessages.PleaseEnterValidUserName

app/public/js/form-validators/ResetPasswordValidator.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@ window.ResetPasswordValidator = class ResetPasswordValidator {
1010
* @returns {boolean}
1111
*/
1212
static validatePassword (pass) {
13-
pass.setCustomValidity(
14-
ResetPasswordValidatorView.messages.ShouldBeMinimumLength
15-
);
13+
pass.setCustomValidity('');
14+
if (pass.validity.tooShort) {
15+
pass.setCustomValidity(
16+
ResetPasswordValidatorView.messages.ShouldBeMinimumLength
17+
);
18+
}
1619
return pass[0].form.reportValidity();
1720
}
1821

app/server/_locales/en-US/messages.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,18 @@
373373
"RecordNotFound": {
374374
"message": "Record not found"
375375
},
376+
"BeginningRoutes": {
377+
"message": "Beginning routes..."
378+
},
379+
"BeginningServer": {
380+
"message": "Beginning server..."
381+
},
382+
"AwaitingI18NAndLogging": {
383+
"message": "Awaiting internationalization and logging..."
384+
},
385+
"AwaitingDatabaseAccountConnection": {
386+
"message": "Awaiting database account connection..."
387+
},
376388

377389
"COUNTRIES (BUSINESS LOGIC)": true,
378390
"PleaseSelectACountry": {

app/server/modules/account-manager.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,11 @@ class AccountManager {
142142
if (o && !isNullish(o.value)) {
143143
return o.value;
144144
}
145-
throw (e || new Error('account not found'));
145+
// Todo: Either i18nize these in the UI or if better to avoid sniffing
146+
// existence of hidden user accounts, avoid this specific message,
147+
// or avoid throwing at all
148+
throw e ||
149+
new Error('account not found');
146150
}
147151

148152
/* eslint-disable require-await */

app/server/routes.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,22 @@ const setI18n = require('./modules/i18n.js')();
1818
const getLogger = require('./modules/getLogger.js');
1919
const layoutView = require('./views/layout.js');
2020

21+
const nonSpecialChars = '[^<>()[\\]\\\\.,;:\\s@"]+';
22+
const ipv4Address = '\\[\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\]';
23+
2124
const emailPattern = '^(' +
2225
'(' +
2326
// 1+ initial chars. excluding special chars.
24-
'[^<>()[\\]\\\\.,;:\\s@"]+' +
27+
nonSpecialChars +
2528
// (Optional) dot followed by 1+ chars., excluding
2629
// any special chars.
27-
'(\\.' +
28-
'[^<>()[\\]\\\\.,;:\\s@"]+' +
29-
')*' +
30+
'(\\.' + nonSpecialChars + ')*' +
3031
')|' +
3132
// Or quoted value
3233
'(".+")' +
3334
')@(' +
3435
'(' +
35-
// IPv4 address
36-
'\\[\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\]' +
36+
ipv4Address +
3737
')|' +
3838
'(' +
3939
// 1+ sequences of:
@@ -80,6 +80,7 @@ module.exports = async function (app, config) {
8080
});
8181
};
8282

83+
log('AwaitingI18NAndLogging');
8384
const [globalI18n, errorLogger] = await Promise.all([
8485
setI18n({
8586
acceptsLanguages: () => loggerLocale
@@ -94,6 +95,7 @@ module.exports = async function (app, config) {
9495
}
9596
};
9697

98+
log('AwaitingDatabaseAccountConnection');
9799
const am = await (new AccountManager(adapter, {
98100
DB_URL,
99101
DB_NAME,
@@ -286,7 +288,6 @@ module.exports = async function (app, config) {
286288
const title = _('Activation');
287289
if (req.query.c) {
288290
try {
289-
console.log('req.query.c', req.query.c);
290291
await am.activateAccount(req.query.c);
291292
} catch (e) {
292293
res.render(
@@ -439,7 +440,6 @@ module.exports = async function (app, config) {
439440
'bootstrap',
440441
'font-awesome',
441442
'github-fork-ribbon-css',
442-
'hyperhtml',
443443
'intl-dom',
444444
'jamilih',
445445
'jquery',

app/server/views/modals/lost-password.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,15 @@ module.exports = function ({_, emailPattern}) {
3939
id: 'retrieve-password-cancel',
4040
'data-name': 'retrieve-password-cancel',
4141
class: 'btn btn-outline-dark',
42-
'data-dismiss': 'modal'
42+
'data-dismiss': 'modal',
43+
form: 'retrieve-password-form'
4344
}, [_('Cancel')]],
4445
['button', {
4546
type: 'submit',
4647
id: 'retrieve-password-submit',
4748
'data-name': 'retrieve-password-submit',
48-
class: 'btn btn-primary'
49+
class: 'btn btn-primary',
50+
form: 'retrieve-password-form'
4951
}, [_('Submit')]]
5052
]]
5153
]]

0 commit comments

Comments
 (0)