mirror of
https://github.com/matt-fidd/stratos.git
synced 2026-01-01 15:59:25 +00:00
Added validator module and tests
This commit is contained in:
@@ -15,7 +15,10 @@
|
||||
"rules": {
|
||||
"indent": [
|
||||
"error",
|
||||
"tab"
|
||||
"tab",
|
||||
{
|
||||
"SwitchCase": 1
|
||||
}
|
||||
],
|
||||
"linebreak-style": [
|
||||
"error",
|
||||
|
||||
238
lib/__tests__/validator.test.js
Normal file
238
lib/__tests__/validator.test.js
Normal file
@@ -0,0 +1,238 @@
|
||||
'use strict';
|
||||
|
||||
const validator = require('../validator');
|
||||
|
||||
describe('validEmail', () => {
|
||||
test('Valid email address', () => {
|
||||
const email = 'bob@bob.com';
|
||||
|
||||
expect(validator.validEmail(email)).toBeTrue();
|
||||
});
|
||||
|
||||
test('Invalid email address', () => {
|
||||
const email = 'bobbobcom';
|
||||
|
||||
expect(validator.validEmail(email)).toBeFalse();
|
||||
});
|
||||
|
||||
test('Invalid email address with @', () => {
|
||||
const email = 'bob@bobcom';
|
||||
|
||||
expect(validator.validEmail(email)).toBeFalse();
|
||||
});
|
||||
|
||||
test('Obscure valid email address', () => {
|
||||
const email = 'jimmy.bob+joe@google.edu.gov.uk';
|
||||
|
||||
expect(validator.validEmail(email)).toBeTrue();
|
||||
});
|
||||
|
||||
test('Even more obscure valid email address', () => {
|
||||
// TODO more obscure email address
|
||||
const email = 'bob@bob.com';
|
||||
|
||||
expect(validator.validEmail(email)).toBeTrue();
|
||||
});
|
||||
});
|
||||
|
||||
describe('passwordsMatch', () => {
|
||||
test('Passwords match', () => {
|
||||
const p1 = 'password123';
|
||||
|
||||
expect(validator.passwordsMatch(p1, p1)).toBeTrue();
|
||||
});
|
||||
|
||||
test('Passwords do not match', () => {
|
||||
const p1 = 'bobby';
|
||||
const p2 = 'jimmy';
|
||||
|
||||
expect(validator.passwordsMatch(p1, p2)).toBeFalse();
|
||||
});
|
||||
|
||||
test('Passwords match and contain special characters', () => {
|
||||
const p1 = 'p2 ssw_0 rd&--1 t3';
|
||||
|
||||
expect(validator.passwordsMatch(p1, p1)).toBeTrue();
|
||||
});
|
||||
|
||||
test('Passwords do not match and contain special characters', () => {
|
||||
const p1 = 'p2ssw_0rd&--1t3';
|
||||
const p2 = 'this-is.././really 99(not) +the+[same';
|
||||
|
||||
expect(validator.passwordsMatch(p1, p2)).toBeFalse();
|
||||
});
|
||||
|
||||
test('Passwords match but are not strings', () => {
|
||||
const p1 = { password: 'password123' };
|
||||
|
||||
expect(validator.passwordsMatch(p1, p1)).toBeFalse();
|
||||
});
|
||||
|
||||
test('Passwords do not match and are not strings', () => {
|
||||
const p1 = { password: 'password123' };
|
||||
const p2 = { password: 'this is not the same' };
|
||||
|
||||
expect(validator.passwordsMatch(p1, p2)).toBeFalse();
|
||||
});
|
||||
|
||||
test('Passwords do not match but differ by whitespace', () => {
|
||||
const p1 = 'password123';
|
||||
const p2 = 'password 123';
|
||||
|
||||
expect(validator.passwordsMatch(p1, p2)).toBeFalse();
|
||||
});
|
||||
});
|
||||
|
||||
describe('validate', () => {
|
||||
test('All required fields filled in', () => {
|
||||
const body = {
|
||||
name: 'Bob',
|
||||
message: 'Hi Jim!'
|
||||
};
|
||||
|
||||
const fields = [
|
||||
'name',
|
||||
'message'
|
||||
];
|
||||
|
||||
const result = validator.validate(body, fields);
|
||||
|
||||
expect(result).toBeObject();
|
||||
expect(result).toContainKey('fields');
|
||||
expect(result.fields.get('name')).toBe('Bob');
|
||||
expect(result.fields.get('message')).toBe('Hi Jim!');
|
||||
});
|
||||
|
||||
test('Required fields missing', () => {
|
||||
const body = {
|
||||
dob: '01/01/01'
|
||||
};
|
||||
|
||||
const fields = [
|
||||
'name',
|
||||
'message'
|
||||
];
|
||||
|
||||
expect(() => {
|
||||
validator.validate(body, fields);
|
||||
}).toThrow('missing');
|
||||
});
|
||||
|
||||
test('Valid email validation', () => {
|
||||
const body = {
|
||||
name: 'Bob',
|
||||
message: 'Hi Jim!',
|
||||
email: 'bob@bob.com'
|
||||
};
|
||||
|
||||
const fields = [
|
||||
'name',
|
||||
'message',
|
||||
'email'
|
||||
];
|
||||
|
||||
const validation = {
|
||||
email: 'email'
|
||||
};
|
||||
|
||||
const result = validator.validate(body, fields, validation);
|
||||
|
||||
expect(result).toBeObject();
|
||||
expect(result).toContainKey('fields');
|
||||
expect(result.fields.get('email')).toBe('bob@bob.com');
|
||||
});
|
||||
|
||||
test('Invalid email validation', () => {
|
||||
const body = {
|
||||
name: 'Bob',
|
||||
message: 'Hi Jim!',
|
||||
email: 'bobbobcom'
|
||||
};
|
||||
|
||||
const fields = [
|
||||
'name',
|
||||
'message',
|
||||
'email'
|
||||
];
|
||||
|
||||
const validation = {
|
||||
email: 'email'
|
||||
};
|
||||
|
||||
expect(() => {
|
||||
validator.validate(body, fields, validation);
|
||||
}).toThrow('Invalid');
|
||||
});
|
||||
|
||||
test('Valid password validation', () => {
|
||||
const body = {
|
||||
name: 'Bob',
|
||||
message: 'Hi Jim!',
|
||||
p1: 'bob',
|
||||
p2: 'bob'
|
||||
};
|
||||
|
||||
const fields = [
|
||||
'name',
|
||||
'message',
|
||||
'p1',
|
||||
'p2'
|
||||
];
|
||||
|
||||
const validation = {
|
||||
password: [ 'p1', 'p2' ]
|
||||
};
|
||||
|
||||
const result = validator.validate(body, fields, validation);
|
||||
|
||||
expect(result).toBeObject();
|
||||
expect(result).toContainKey('fields');
|
||||
expect(result.fields.get('p1')).toBe('bob');
|
||||
expect(result.fields.get('p2')).toBe('bob');
|
||||
});
|
||||
|
||||
test('Invalid password validation', () => {
|
||||
const body = {
|
||||
name: 'Bob',
|
||||
message: 'Hi Jim!',
|
||||
p1: 'bob',
|
||||
p2: 'jim'
|
||||
};
|
||||
|
||||
const fields = [
|
||||
'name',
|
||||
'message',
|
||||
'p1',
|
||||
'p2'
|
||||
];
|
||||
|
||||
const validation = {
|
||||
password: [ 'p1', 'p2' ]
|
||||
};
|
||||
|
||||
expect(() => {
|
||||
validator.validate(body, fields, validation);
|
||||
}).toThrow('Invalid');
|
||||
});
|
||||
|
||||
test('Invalid validation type', () => {
|
||||
const body = {
|
||||
name: 'Bob',
|
||||
message: 'Hi Jim!'
|
||||
};
|
||||
|
||||
const fields = [
|
||||
'name',
|
||||
'message'
|
||||
];
|
||||
|
||||
const validation = {
|
||||
joeseph: []
|
||||
};
|
||||
|
||||
expect(() => {
|
||||
validator.validate(body, fields, validation);
|
||||
}).toThrow('Invalid validation type');
|
||||
});
|
||||
});
|
||||
|
||||
88
lib/validator.js
Normal file
88
lib/validator.js
Normal file
@@ -0,0 +1,88 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* validEmail() Check that an email email matches a simple valid email regex
|
||||
*
|
||||
* @param {string} email - The email address to be validated
|
||||
* @param {RegExp} [emailRegex] - RegExp to use for validation
|
||||
*
|
||||
* @return {boolean} - If the email address is valid
|
||||
*/
|
||||
function validEmail(email, emailRegex) {
|
||||
if (typeof emailRegex === 'undefined')
|
||||
emailRegex = /\S+@\S+\.\S+/;
|
||||
|
||||
return emailRegex.test(email);
|
||||
}
|
||||
|
||||
/**
|
||||
* passwordsMatch() Check that two password fields match
|
||||
*
|
||||
* @param {string} password1 - The first password
|
||||
* @param {string} password2 - The second password
|
||||
*
|
||||
* @return {boolean} - If the passwords match
|
||||
*/
|
||||
function passwordsMatch(password1, password2) {
|
||||
if (typeof password1 !== 'string' || typeof password2 !== 'string')
|
||||
return false;
|
||||
|
||||
return password1 === password2;
|
||||
}
|
||||
|
||||
/**
|
||||
* validate() Main validation wrapper function to validate full POST form body
|
||||
*
|
||||
* @param {Object} body - The body of an express request
|
||||
* @param {Array<string>} fields - Fields to check
|
||||
* @param {Object} [validation] - Fields to run special validation against
|
||||
*
|
||||
* @return {Object} results
|
||||
* @return {Map<string, string>} results.fields - Sanitised and validated fields
|
||||
*/
|
||||
function validate(body, fields, validation = {}) {
|
||||
const fieldsMap = new Map();
|
||||
|
||||
// Check all required fields are not empty, and sanitise them
|
||||
for (const field of fields) {
|
||||
const cleanField = body[field]?.trim() ?? false;
|
||||
|
||||
if (cleanField === false || cleanField.length < 1)
|
||||
throw new Error(`${field} is missing`);
|
||||
|
||||
fieldsMap.set(field, cleanField);
|
||||
}
|
||||
|
||||
// Handle validation as required in options
|
||||
for (const [ check, checkOpts ] of Object.entries(validation)) {
|
||||
let valid;
|
||||
|
||||
// Handlers for validation types go here
|
||||
switch (check) {
|
||||
case 'email':
|
||||
valid = validEmail(fieldsMap.get(checkOpts));
|
||||
break;
|
||||
case 'password':
|
||||
valid = passwordsMatch(
|
||||
fieldsMap.get(checkOpts[0]),
|
||||
fieldsMap.get(checkOpts[1])
|
||||
);
|
||||
break;
|
||||
default:
|
||||
throw new Error('Invalid validation type');
|
||||
}
|
||||
|
||||
if (!valid)
|
||||
throw new Error(`Invalid ${check}`);
|
||||
}
|
||||
|
||||
return {
|
||||
fields: fieldsMap
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
validEmail: validEmail,
|
||||
passwordsMatch: passwordsMatch,
|
||||
validate: validate
|
||||
};
|
||||
Reference in New Issue
Block a user