Skip to content

Commit

Permalink
- Breaking change: Rename auto-set pass_ver to passVer
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
brettz9 committed Feb 21, 2020
1 parent 1e2792f commit ceba6d5
Show file tree
Hide file tree
Showing 15 changed files with 101 additions and 180 deletions.
3 changes: 3 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const jmlEngine = require('./app/server/modules/jmlEngine.js');
* @returns {Promise<void>}
*/
exports.createServer = async function (options) {
// We can't add an internationaalized log that we are awaiting the loggers!
const [log, errorLog] = await Promise.all([
getLogger(options),
getLogger({...options, errorLog: true})
Expand Down Expand Up @@ -145,6 +146,7 @@ exports.createServer = async function (options) {

app.use(session(sess));

log('BeginningRoutes');
await routes(app, {
log,
loggerLocale,
Expand All @@ -165,6 +167,7 @@ exports.createServer = async function (options) {
fromURL
});

log('BeginningServer');
http.createServer(app).listen(app.get('port'), () => {
// Todo: Add more (i18nized) logging messages
// also make i18n tool for `optionDefinitions` definitions?
Expand Down
15 changes: 10 additions & 5 deletions app/public/js/controllers/loginController.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* globals LoginValidator, EmailValidator, LoginView */
/* globals LoginValidator, EmailValidator, LoginView, LoginValidatorView */
'use strict';

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

const retrievePasswordModal = LoginView.retrievePasswordModal();

const retrievePasswordEmail = LoginView.retrieveLostPasswordEmail(
retrievePasswordModal
);
Expand Down Expand Up @@ -74,7 +75,10 @@ const ev = new EmailValidator();
retrievePasswordForm.ajaxForm({
url: '/lost-password',
beforeSubmit (formData, jqForm, options) {
if (EmailValidator.validateEmail(retrievePasswordEmail[0])) {
const emailInput = retrievePasswordEmail[0];
if (EmailValidator.validateEmail(emailInput)) {
// Reset for future attempts
emailInput.setCustomValidity('');
ev.hideEmailAlert();
return true;
}
Expand All @@ -83,15 +87,16 @@ retrievePasswordForm.ajaxForm({
success (responseText, status, xhr, $form) {
LoginView.switchConfirmToAlert(retrievePasswordModal);
retrievePasswordSubmit.hide();
ev.showEmailSuccess(LoginView.messages.LinkToResetPasswordMailed);
ev.showEmailSuccess(LoginValidatorView.messages.LinkToResetPasswordMailed);
},
error (e) {
if (e.responseText === 'email-not-found') {
ev.showEmailAlert(LoginView.messages.EmailNotFound);
ev.showEmailAlert(LoginValidatorView.messages.EmailNotFound);
} else {
console.log(e);
LoginView.switchConfirmToAlert(retrievePasswordModal);
retrievePasswordSubmit.hide();
ev.showEmailAlert(LoginView.messages.ProblemTryAgainLater);
ev.showEmailAlert(LoginValidatorView.messages.ProblemTryAgainLater);
}
}
});
Expand Down
2 changes: 1 addition & 1 deletion app/public/js/form-validators/AccountValidator.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ window.AccountValidator = class AccountValidator {
if (name.validity.tooShort) {
name.setCustomValidity(this.errorMessages.name.PleaseEnterName);
}
if (email.validityMismatch) {
if (email.validity.patternMismatch) {
email.setCustomValidity(this.errorMessages.email.PleaseEnterValidEmail);
}
if (user.validity.tooShort) {
Expand Down
9 changes: 6 additions & 3 deletions app/public/js/form-validators/EmailValidator.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ window.EmailValidator = class EmailValidator {
* @returns {boolean} Whether valid
*/
static validateEmail (input) {
input.setCustomValidity(
EmailValidatorView.messages.PleaseEnterValidEmailAddress
);
input.setCustomValidity('');
if (input.validity.patternMismatch) {
input.setCustomValidity(
EmailValidatorView.messages.PleaseEnterValidEmailAddress
);
}
return input.form.reportValidity();
}

Expand Down
3 changes: 3 additions & 0 deletions app/public/js/form-validators/LoginValidator.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ window.LoginValidator = class LoginValidator {
* @returns {boolean}
*/
static validateForm () {
[user, pass].forEach((field) => {
field.setCustomValidity('');
});
if (user.validity.valueMissing) {
user.setCustomValidity(
LoginValidatorView.errorMessages.PleaseEnterValidUserName
Expand Down
9 changes: 6 additions & 3 deletions app/public/js/form-validators/ResetPasswordValidator.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ window.ResetPasswordValidator = class ResetPasswordValidator {
* @returns {boolean}
*/
static validatePassword (pass) {
pass.setCustomValidity(
ResetPasswordValidatorView.messages.ShouldBeMinimumLength
);
pass.setCustomValidity('');
if (pass.validity.tooShort) {
pass.setCustomValidity(
ResetPasswordValidatorView.messages.ShouldBeMinimumLength
);
}
return pass[0].form.reportValidity();
}

Expand Down
12 changes: 12 additions & 0 deletions app/server/_locales/en-US/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,18 @@
"RecordNotFound": {
"message": "Record not found"
},
"BeginningRoutes": {
"message": "Beginning routes..."
},
"BeginningServer": {
"message": "Beginning server..."
},
"AwaitingI18NAndLogging": {
"message": "Awaiting internationalization and logging..."
},
"AwaitingDatabaseAccountConnection": {
"message": "Awaiting database account connection..."
},

"COUNTRIES (BUSINESS LOGIC)": true,
"PleaseSelectACountry": {
Expand Down
6 changes: 5 additions & 1 deletion app/server/modules/account-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,11 @@ class AccountManager {
if (o && !isNullish(o.value)) {
return o.value;
}
throw (e || new Error('account not found'));
// Todo: Either i18nize these in the UI or if better to avoid sniffing
// existence of hidden user accounts, avoid this specific message,
// or avoid throwing at all
throw e ||
new Error('account not found');
}

/* eslint-disable require-await */
Expand Down
16 changes: 8 additions & 8 deletions app/server/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,22 @@ const setI18n = require('./modules/i18n.js')();
const getLogger = require('./modules/getLogger.js');
const layoutView = require('./views/layout.js');

const nonSpecialChars = '[^<>()[\\]\\\\.,;:\\s@"]+';
const ipv4Address = '\\[\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\]';

const emailPattern = '^(' +
'(' +
// 1+ initial chars. excluding special chars.
'[^<>()[\\]\\\\.,;:\\s@"]+' +
nonSpecialChars +
// (Optional) dot followed by 1+ chars., excluding
// any special chars.
'(\\.' +
'[^<>()[\\]\\\\.,;:\\s@"]+' +
')*' +
'(\\.' + nonSpecialChars + ')*' +
')|' +
// Or quoted value
'(".+")' +
')@(' +
'(' +
// IPv4 address
'\\[\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\]' +
ipv4Address +
')|' +
'(' +
// 1+ sequences of:
Expand Down Expand Up @@ -80,6 +80,7 @@ module.exports = async function (app, config) {
});
};

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

log('AwaitingDatabaseAccountConnection');
const am = await (new AccountManager(adapter, {
DB_URL,
DB_NAME,
Expand Down Expand Up @@ -286,7 +288,6 @@ module.exports = async function (app, config) {
const title = _('Activation');
if (req.query.c) {
try {
console.log('req.query.c', req.query.c);
await am.activateAccount(req.query.c);
} catch (e) {
res.render(
Expand Down Expand Up @@ -439,7 +440,6 @@ module.exports = async function (app, config) {
'bootstrap',
'font-awesome',
'github-fork-ribbon-css',
'hyperhtml',
'intl-dom',
'jamilih',
'jquery',
Expand Down
6 changes: 4 additions & 2 deletions app/server/views/modals/lost-password.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,15 @@ module.exports = function ({_, emailPattern}) {
id: 'retrieve-password-cancel',
'data-name': 'retrieve-password-cancel',
class: 'btn btn-outline-dark',
'data-dismiss': 'modal'
'data-dismiss': 'modal',
form: 'retrieve-password-form'
}, [_('Cancel')]],
['button', {
type: 'submit',
id: 'retrieve-password-submit',
'data-name': 'retrieve-password-submit',
class: 'btn btn-primary'
class: 'btn btn-primary',
form: 'retrieve-password-form'
}, [_('Submit')]]
]]
]]
Expand Down
Loading

0 comments on commit ceba6d5

Please sign in to comment.