File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
/*!
* Copyright (c) 2010 Chris O'Hara <cohara87@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
// follow Universal Module Definition (UMD) pattern for defining module as AMD, CommonJS, and Browser compatible
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['exports'], factory);
} else if (typeof exports === 'object') {
// CommonJS
factory(exports);
} else {
// Browser globals
// N.B. Here is a slight difference to regular UMD as the current API for node-validator in browser adds each export directly to the window
// rather than to a namespaced object such as window.nodeValidator, which would be better practice, but would break backwards compatibility
// as such unable to use build tools like grunt-umd
factory(root);
}
}(this, function(exports) {
var entities = {
' ': '\u00a0',
'¡': '\u00a1',
'¢': '\u00a2',
'£': '\u00a3',
'¤': '\u20ac',
'¥': '\u00a5',
'¦': '\u0160',
'§': '\u00a7',
'¨': '\u0161',
'©': '\u00a9',
'ª': '\u00aa',
'«': '\u00ab',
'¬': '\u00ac',
'­': '\u00ad',
'®': '\u00ae',
'¯': '\u00af',
'°': '\u00b0',
'±': '\u00b1',
'²': '\u00b2',
'³': '\u00b3',
'´': '\u017d',
'µ': '\u00b5',
'¶': '\u00b6',
'·': '\u00b7',
'¸': '\u017e',
'¹': '\u00b9',
'º': '\u00ba',
'»': '\u00bb',
'¼': '\u0152',
'½': '\u0153',
'¾': '\u0178',
'¿': '\u00bf',
'À': '\u00c0',
'Á': '\u00c1',
'Â': '\u00c2',
'Ã': '\u00c3',
'Ä': '\u00c4',
'Å': '\u00c5',
'Æ': '\u00c6',
'Ç': '\u00c7',
'È': '\u00c8',
'É': '\u00c9',
'Ê': '\u00ca',
'Ë': '\u00cb',
'Ì': '\u00cc',
'Í': '\u00cd',
'Î': '\u00ce',
'Ï': '\u00cf',
'Ð': '\u00d0',
'Ñ': '\u00d1',
'Ò': '\u00d2',
'Ó': '\u00d3',
'Ô': '\u00d4',
'Õ': '\u00d5',
'Ö': '\u00d6',
'×': '\u00d7',
'Ø': '\u00d8',
'Ù': '\u00d9',
'Ú': '\u00da',
'Û': '\u00db',
'Ü': '\u00dc',
'Ý': '\u00dd',
'Þ': '\u00de',
'ß': '\u00df',
'à': '\u00e0',
'á': '\u00e1',
'â': '\u00e2',
'ã': '\u00e3',
'ä': '\u00e4',
'å': '\u00e5',
'æ': '\u00e6',
'ç': '\u00e7',
'è': '\u00e8',
'é': '\u00e9',
'ê': '\u00ea',
'ë': '\u00eb',
'ì': '\u00ec',
'í': '\u00ed',
'î': '\u00ee',
'ï': '\u00ef',
'ð': '\u00f0',
'ñ': '\u00f1',
'ò': '\u00f2',
'ó': '\u00f3',
'ô': '\u00f4',
'õ': '\u00f5',
'ö': '\u00f6',
'÷': '\u00f7',
'ø': '\u00f8',
'ù': '\u00f9',
'ú': '\u00fa',
'û': '\u00fb',
'ü': '\u00fc',
'ý': '\u00fd',
'þ': '\u00fe',
'ÿ': '\u00ff',
'"': '\u0022',
'<': '\u003c',
'>': '\u003e',
''': '\u0027',
'−': '\u2212',
'ˆ': '\u02c6',
'˜': '\u02dc',
'Š': '\u0160',
'‹': '\u2039',
'Œ': '\u0152',
'‘': '\u2018',
'’': '\u2019',
'“': '\u201c',
'”': '\u201d',
'•': '\u2022',
'–': '\u2013',
'—': '\u2014',
'™': '\u2122',
'š': '\u0161',
'›': '\u203a',
'œ': '\u0153',
'Ÿ': '\u0178',
'ƒ': '\u0192',
'Α': '\u0391',
'Β': '\u0392',
'Γ': '\u0393',
'Δ': '\u0394',
'Ε': '\u0395',
'Ζ': '\u0396',
'Η': '\u0397',
'Θ': '\u0398',
'Ι': '\u0399',
'Κ': '\u039a',
'Λ': '\u039b',
'Μ': '\u039c',
'Ν': '\u039d',
'Ξ': '\u039e',
'Ο': '\u039f',
'Π': '\u03a0',
'Ρ': '\u03a1',
'Σ': '\u03a3',
'Τ': '\u03a4',
'Υ': '\u03a5',
'Φ': '\u03a6',
'Χ': '\u03a7',
'Ψ': '\u03a8',
'Ω': '\u03a9',
'α': '\u03b1',
'β': '\u03b2',
'γ': '\u03b3',
'δ': '\u03b4',
'ε': '\u03b5',
'ζ': '\u03b6',
'η': '\u03b7',
'θ': '\u03b8',
'ι': '\u03b9',
'κ': '\u03ba',
'λ': '\u03bb',
'μ': '\u03bc',
'ν': '\u03bd',
'ξ': '\u03be',
'ο': '\u03bf',
'π': '\u03c0',
'ρ': '\u03c1',
'ς': '\u03c2',
'σ': '\u03c3',
'τ': '\u03c4',
'υ': '\u03c5',
'φ': '\u03c6',
'χ': '\u03c7',
'ψ': '\u03c8',
'ω': '\u03c9',
'ϑ': '\u03d1',
'ϒ': '\u03d2',
'ϖ': '\u03d6',
' ': '\u2002',
' ': '\u2003',
' ': '\u2009',
'‌': '\u200c',
'‍': '\u200d',
'‎': '\u200e',
'‏': '\u200f',
'‚': '\u201a',
'„': '\u201e',
'†': '\u2020',
'‡': '\u2021',
'…': '\u2026',
'‰': '\u2030',
'′': '\u2032',
'″': '\u2033',
'‾': '\u203e',
'⁄': '\u2044',
'€': '\u20ac',
'ℑ': '\u2111',
'℘': '\u2118',
'ℜ': '\u211c',
'ℵ': '\u2135',
'←': '\u2190',
'↑': '\u2191',
'→': '\u2192',
'↓': '\u2193',
'↔': '\u2194',
'↵': '\u21b5',
'⇐': '\u21d0',
'⇑': '\u21d1',
'⇒': '\u21d2',
'⇓': '\u21d3',
'⇔': '\u21d4',
'∀': '\u2200',
'∂': '\u2202',
'∃': '\u2203',
'∅': '\u2205',
'∇': '\u2207',
'∈': '\u2208',
'∉': '\u2209',
'∋': '\u220b',
'∏': '\u220f',
'∑': '\u2211',
'∗': '\u2217',
'√': '\u221a',
'∝': '\u221d',
'∞': '\u221e',
'∠': '\u2220',
'∧': '\u2227',
'∨': '\u2228',
'∩': '\u2229',
'∪': '\u222a',
'∫': '\u222b',
'∴': '\u2234',
'∼': '\u223c',
'≅': '\u2245',
'≈': '\u2248',
'≠': '\u2260',
'≡': '\u2261',
'≤': '\u2264',
'≥': '\u2265',
'⊂': '\u2282',
'⊃': '\u2283',
'⊄': '\u2284',
'⊆': '\u2286',
'⊇': '\u2287',
'⊕': '\u2295',
'⊗': '\u2297',
'⊥': '\u22a5',
'⋅': '\u22c5',
'⌈': '\u2308',
'⌉': '\u2309',
'⌊': '\u230a',
'⌋': '\u230b',
'⟨': '\u2329',
'⟩': '\u232a',
'◊': '\u25ca',
'♠': '\u2660',
'♣': '\u2663',
'♥': '\u2665',
'♦': '\u2666'
};
var decode = function (str) {
if (!~str.indexOf('&')) return str;
//Decode literal entities
for (var i in entities) {
str = str.replace(new RegExp(i, 'g'), entities[i]);
}
//Decode hex entities
str = str.replace(/&#x(0*[0-9a-f]{2,5});?/gi, function (m, code) {
return String.fromCharCode(parseInt(+code, 16));
});
//Decode numeric entities
str = str.replace(/&#([0-9]{2,4});?/gi, function (m, code) {
return String.fromCharCode(+code);
});
str = str.replace(/&/g, '&');
return str;
}
var encode = function (str) {
str = str.replace(/&/g, '&');
//IE doesn't accept '
str = str.replace(/'/g, ''');
//Encode literal entities
for (var i in entities) {
str = str.replace(new RegExp(entities[i], 'g'), i);
}
return str;
}
exports.entities = {
encode: encode,
decode: decode
}
//This module is adapted from the CodeIgniter framework
//The license is available at http://codeigniter.com/
var never_allowed_str = {
'document.cookie': '',
'document.write': '',
'.parentNode': '',
'.innerHTML': '',
'window.location': '',
'-moz-binding': '',
'<!--': '<!--',
'-->': '-->',
'<![CDATA[': '<![CDATA['
};
var never_allowed_regex = {
'javascript\\s*:': '',
'expression\\s*(\\(|&\\#40;)': '',
'vbscript\\s*:': '',
'Redirect\\s+302': ''
};
var non_displayables = [
/%0[0-8bcef]/g, // url encoded 00-08, 11, 12, 14, 15
/%1[0-9a-f]/g, // url encoded 16-31
/[\x00-\x08]/g, // 00-08
/\x0b/g, /\x0c/g, // 11,12
/[\x0e-\x1f]/g // 14-31
];
var compact_words = [
'javascript', 'expression', 'vbscript',
'script', 'applet', 'alert', 'document',
'write', 'cookie', 'window'
];
exports.xssClean = function(str, is_image) {
//Recursively clean objects and arrays
if (typeof str === 'object') {
for (var i in str) {
str[i] = exports.xssClean(str[i]);
}
return str;
}
//Remove invisible characters
str = remove_invisible_characters(str);
//Protect query string variables in URLs => 901119URL5918AMP18930PROTECT8198
str = str.replace(/\&([a-z\_0-9]+)\=([a-z\_0-9]+)/i, xss_hash() + '$1=$2');
//Validate standard character entities - add a semicolon if missing. We do this to enable
//the conversion of entities to ASCII later.
str = str.replace(/(&\#?[0-9a-z]{2,})([\x00-\x20])*;?/i, '$1;$2');
//Validate UTF16 two byte encoding (x00) - just as above, adds a semicolon if missing.
str = str.replace(/(&\#x?)([0-9A-F]+);?/i, '$1;$2');
//Un-protect query string variables
str = str.replace(xss_hash(), '&');
//Decode just in case stuff like this is submitted:
//<a href="http://%77%77%77%2E%67%6F%6F%67%6C%65%2E%63%6F%6D">Google</a>
//Convert character entities to ASCII - this permits our tests below to work reliably.
//We only convert entities that are within tags since these are the ones that will pose security problems.
str = str.replace(/[a-z]+=([\'\"]).*?\1/gi, function(m, match) {
return m.replace(match, convert_attribute(match));
});
//Remove invisible characters again
str = remove_invisible_characters(str);
//Convert tabs to spaces
str = str.replace('\t', ' ');
//Captured the converted string for later comparison
var converted_string = str;
//Remove strings that are never allowed
for (var i in never_allowed_str) {
str = str.replace(i, never_allowed_str[i]);
}
//Remove regex patterns that are never allowed
for (var i in never_allowed_regex) {
str = str.replace(new RegExp(i, 'i'), never_allowed_regex[i]);
}
//Compact any exploded words like: j a v a s c r i p t
// We only want to do this when it is followed by a non-word character
for (var i in compact_words) {
var spacified = compact_words[i].split('').join('\\s*')+'\\s*';
str = str.replace(new RegExp('('+spacified+')(\\s)', 'ig'), function(m, compat, after) {
return compat.replace(/\s+/g, '') + after;
});
}
//Remove disallowed Javascript in links, img tags or video tags
do {
var original = str;
if (str.match(/<a/i)) {
str = str.replace(/<a\s+([^>]*?)(>|$)/gi, function(m, attributes, end_tag) {
attributes = filter_attributes(attributes.replace('<','').replace('>',''));
return m.replace(attributes, attributes.replace(/href=.*?(alert\(|alert&\#40;|javascript\:|charset\=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)/gi, ''));
});
}
if (str.match(/<img/i)) {
str = str.replace(/<img\s+([^>]*?)(\s?\/?>|$)/gi, function(m, attributes, end_tag) {
attributes = filter_attributes(attributes.replace('<','').replace('>',''));
return m.replace(attributes, attributes.replace(/src=.*?(alert\(|alert&\#40;|javascript\:|charset\=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)/gi, ''));
});
}
if (str.match(/<video/i)) {
str = str.replace(/<video\s+([^>]*?)(\s?\/?>|$)/gi, function(m, attributes, end_tag) {
attributes = filter_attributes(attributes.replace('<','').replace('>',''));
return m.replace(attributes, attributes.replace(/poster=.*?(alert\(|alert&\#40;|javascript\:|charset\=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)/gi, ''));
});
}
if (str.match(/script/i) || str.match(/xss/i)) {
str = str.replace(/<(\/*)(script|xss)(.*?)\>/gi, '');
}
} while(original != str);
//Remove JavaScript Event Handlers - Note: This code is a little blunt. It removes the event
//handler and anything up to the closing >, but it's unlikely to be a problem.
event_handlers = ['[^a-z_\-]on\\w*'];
//Adobe Photoshop puts XML metadata into JFIF images, including namespacing,
//so we have to allow this for images
if (!is_image) {
event_handlers.push('xmlns');
}
str = str.replace(new RegExp("<([^><]+?)("+event_handlers.join('|')+")(\\s*=\\s*[^><]*)([><]*)", 'i'), '<$1$4');
//Sanitize naughty HTML elements
//If a tag containing any of the words in the list
//below is found, the tag gets converted to entities.
//So this: <blink>
//Becomes: <blink>
naughty = 'alert|applet|audio|basefont|base|behavior|bgsound|blink|body|embed|expression|form|frameset|frame|head|html|ilayer|iframe|input|isindex|layer|link|meta|object|plaintext|style|script|textarea|title|xml|xss';
str = str.replace(new RegExp('<(/*\\s*)('+naughty+')([^><]*)([><]*)', 'gi'), function(m, a, b, c, d) {
return '<' + a + b + c + d.replace('>','>').replace('<','<');
});
//Sanitize naughty scripting elements Similar to above, only instead of looking for
//tags it looks for PHP and JavaScript commands that are disallowed. Rather than removing the
//code, it simply converts the parenthesis to entities rendering the code un-executable.
//For example: eval('some code')
//Becomes: eval('some code')
str = str.replace(/(alert|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)/gi, '$1$2($3)');
//This adds a bit of extra precaution in case something got through the above filters
for (var i in never_allowed_str) {
str = str.replace(i, never_allowed_str[i]);
}
for (var i in never_allowed_regex) {
str = str.replace(new RegExp(i, 'i'), never_allowed_regex[i]);
}
//Images are handled in a special way
if (is_image && str !== converted_string) {
throw new Error('Image may contain XSS');
}
return str;
}
function remove_invisible_characters(str) {
for (var i in non_displayables) {
str = str.replace(non_displayables[i], '');
}
return str;
}
function xss_hash() {
//TODO: Create a random hash
return '!*$^#(@*#&';
}
function convert_attribute(str) {
return str.replace('>','>').replace('<','<').replace('\\','\\\\');
}
//Filter Attributes - filters tag attributes for consistency and safety
function filter_attributes(str) {
var comments = /\/\*.*?\*\//g;
return str.replace(/\s*[a-z-]+\s*=\s*'[^']*'/gi, function (m) {
return m.replace(comments, '');
}).replace(/\s*[a-z-]+\s*=\s*"[^"]*"/gi, function (m) {
return m.replace(comments, '');
}).replace(/\s*[a-z-]+\s*=\s*[^\s]+/gi, function (m) {
return m.replace(comments, '');
});
}
var Validator = exports.Validator = function() {}
Validator.prototype.check = function(str, fail_msg) {
this.str = typeof( str ) === 'undefined' || str === null || (isNaN(str) && str.length === undefined) ? '' : str+'';
this.msg = fail_msg;
this._errors = this._errors || [];
return this;
}
function internal_is_ipv4(str) {
if (/^(\d?\d?\d)\.(\d?\d?\d)\.(\d?\d?\d)\.(\d?\d?\d)$/.test(str)) {
var parts = str.split('.').sort();
// no need to check for < 0 as regex won't match in that case
if (parts[3] > 255) {
return false;
}
return true;
}
return false;
}
function internal_is_ipv6(str) {
if (/^::|^::1|^([a-fA-F0-9]{1,4}::?){1,7}([a-fA-F0-9]{1,4})$/.test(str)) {
return true;
}
return false;
}
//Create some aliases - may help code readability
Validator.prototype.validate = Validator.prototype.check;
Validator.prototype.assert = Validator.prototype.check;
Validator.prototype.error = function(msg) {
throw new Error(msg);
}
function toDate(date) {
if (date instanceof Date) {
return date;
}
var intDate = Date.parse(date);
if (isNaN(intDate)) {
return null;
}
return new Date(intDate);
}
Validator.prototype.isAfter = function(date) {
date = date || new Date();
var origDate = toDate(this.str)
, compDate = toDate(date);
if (!(origDate && compDate && origDate >= compDate)) {
return this.error(this.msg || 'Invalid date');
}
return this;
};
Validator.prototype.isBefore = function(date) {
date = date || new Date();
var origDate = toDate(this.str)
, compDate = toDate(date);
if (!(origDate && compDate && origDate <= compDate)) {
return this.error(this.msg || 'Invalid date');
}
return this;
};
Validator.prototype.isEmail = function() {
if (!this.str.match(/^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!\.)){0,61}[a-zA-Z0-9]?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!$)){0,61}[a-zA-Z0-9]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/)) {
return this.error(this.msg || 'Invalid email');
}
return this;
}
//Will work against Visa, MasterCard, American Express, Discover, Diners Club, and JCB card numbering formats
Validator.prototype.isCreditCard = function() {
this.str = this.str.replace(/[^0-9]+/g, ''); //remove all dashes, spaces, etc.
if (!this.str.match(/^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$/)) {
return this.error(this.msg || 'Invalid credit card');
}
// Doing Luhn check
var sum = 0;
var digit;
var tmpNum;
var shouldDouble = false;
for (var i = this.length - 1; i >= 0; i--) {
digit = this.substring(i, (i + 1));
tmpNum = parseInt(digit, 10);
if (shouldDouble) {
tmpNum *= 2;
if (tmpNum >= 10) {
sum += ((tmpNum % 10) + 1);
}
else {
sum += tmpNum;
}
}
else {
sum += tmpNum;
}
if (shouldDouble) {
shouldDouble = false;
}
else {
shouldDouble = true;
}
}
if ((sum % 10) !== 0) {
return this.error(this.msg || 'Invalid credit card');
}
return this;
}
Validator.prototype.isUrl = function() {
if (!this.str.match(/^(?!mailto:)(?:(?:https?|ftp):\/\/)?(?:\S+(?::\S*)?@)?(?:(?:(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))|localhost)(?::\d{2,5})?(?:\/[^\s]*)?$/i) || this.str.length > 2083) {
return this.error(this.msg || 'Invalid URL');
}
return this;
}
Validator.prototype.isIPv4 = function() {
if (internal_is_ipv4(this.str)) {
return this;
}
return this.error(this.msg || 'Invalid IP');
}
Validator.prototype.isIPv6 = function() {
if (internal_is_ipv6(this.str)) {
return this;
}
return this.error(this.msg || 'Invalid IP');
}
Validator.prototype.isIP = function() {
if (internal_is_ipv4(this.str) || internal_is_ipv6(this.str)) {
return this;
}
return this.error(this.msg || 'Invalid IP');
}
Validator.prototype.isAlpha = function() {
if (!this.str.match(/^[a-zA-Z]+$/)) {
return this.error(this.msg || 'Invalid characters');
}
return this;
}
Validator.prototype.isAlphanumeric = function() {
if (!this.str.match(/^[a-zA-Z0-9]+$/)) {
return this.error(this.msg || 'Invalid characters');
}
return this;
}
Validator.prototype.isNumeric = function() {
if (!this.str.match(/^-?[0-9]+$/)) {
return this.error(this.msg || 'Invalid number');
}
return this;
}
Validator.prototype.isHexadecimal = function() {
if (!this.str.match(/^[0-9a-fA-F]+$/)) {
return this.error(this.msg || 'Invalid hexadecimal');
}
return this;
}
Validator.prototype.isHexColor = function() {
if (!this.str.match(/^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/)) {
return this.error(this.msg || 'Invalid hexcolor');
}
return this;
}
Validator.prototype.isLowercase = function() {
if (this.str !== this.str.toLowerCase()) {
return this.error(this.msg || 'Invalid characters');
}
return this;
}
Validator.prototype.isUppercase = function() {
if (this.str !== this.str.toUpperCase()) {
return this.error(this.msg || 'Invalid characters');
}
return this;
}
Validator.prototype.isInt = function() {
if (!this.str.match(/^(?:-?(?:0|[1-9][0-9]*))$/)) {
return this.error(this.msg || 'Invalid integer');
}
return this;
}
Validator.prototype.isDecimal = function() {
if (!this.str.match(/^(?:-?(?:0|[1-9][0-9]*))?(?:\.[0-9]*)?$/)) {
return this.error(this.msg || 'Invalid decimal');
}
return this;
}
Validator.prototype.isDivisibleBy = function(n) {
return (parseFloat(this.str) % parseInt(n, 10)) === 0;
}
Validator.prototype.isFloat = function() {
return this.isDecimal();
}
Validator.prototype.notNull = function() {
if (this.str === '') {
return this.error(this.msg || 'String is empty');
}
return this;
}
Validator.prototype.isNull = function() {
if (this.str !== '') {
return this.error(this.msg || 'String is not empty');
}
return this;
}
Validator.prototype.notEmpty = function() {
if (this.str.match(/^[\s\t\r\n]*$/)) {
return this.error(this.msg || 'String is whitespace');
}
return this;
}
Validator.prototype.equals = function(equals) {
if (this.str != equals) {
return this.error(this.msg || 'Not equal');
}
return this;
}
Validator.prototype.contains = function(str) {
if (this.str.indexOf(str) === -1 || !str) {
return this.error(this.msg || 'Invalid characters');
}
return this;
}
Validator.prototype.notContains = function(str) {
if (this.str.indexOf(str) >= 0) {
return this.error(this.msg || 'Invalid characters');
}
return this;
}
Validator.prototype.regex = Validator.prototype.is = function(pattern, modifiers) {
if (Object.prototype.toString.call(pattern).slice(8, -1) !== 'RegExp') {
pattern = new RegExp(pattern, modifiers);
}
if (! this.str.match(pattern)) {
return this.error(this.msg || 'Invalid characters');
}
return this;
}
Validator.prototype.notRegex = Validator.prototype.not = function(pattern, modifiers) {
if (Object.prototype.toString.call(pattern).slice(8, -1) !== 'RegExp') {
pattern = new RegExp(pattern, modifiers);
}
if (this.str.match(pattern)) {
this.error(this.msg || 'Invalid characters');
}
return this;
}
Validator.prototype.len = function(min, max) {
if (this.str.length < min) {
return this.error(this.msg || 'String is too small');
}
if (typeof max !== undefined && this.str.length > max) {
return this.error(this.msg || 'String is too large');
}
return this;
}
//Thanks to github.com/sreuter for the idea.
Validator.prototype.isUUID = function(version) {
var pattern;
if (version == 3 || version == 'v3') {
pattern = /[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i;
} else if (version == 4 || version == 'v4') {
pattern = /[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i;
} else if (version == 5 || version == 'v5') {
pattern = /^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i;
} else {
pattern = /[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i;
}
if (!this.str.match(pattern)) {
return this.error(this.msg || 'Not a UUID');
}
return this;
}
Validator.prototype.isUUIDv3 = function() {
return this.isUUID(3);
}
Validator.prototype.isUUIDv4 = function() {
return this.isUUID(4);
}
Validator.prototype.isUUIDv5 = function() {
return this.isUUID(5);
}
Validator.prototype.isDate = function() {
var intDate = Date.parse(this.str);
if (isNaN(intDate)) {
return this.error(this.msg || 'Not a date');
}
return this;
}
Validator.prototype.isIn = function(options) {
if (options && typeof options.indexOf === 'function') {
if (!~options.indexOf(this.str)) {
return this.error(this.msg || 'Unexpected value');
}
return this;
} else {
return this.error(this.msg || 'Invalid in() argument');
}
}
Validator.prototype.notIn = function(options) {
if (options && typeof options.indexOf === 'function') {
if (options.indexOf(this.str) !== -1) {
return this.error(this.msg || 'Unexpected value');
}
return this;
} else {
return this.error(this.msg || 'Invalid notIn() argument');
}
}
Validator.prototype.min = function(val) {
var number = parseFloat(this.str);
if (!isNaN(number) && number < val) {
return this.error(this.msg || 'Invalid number');
}
return this;
}
Validator.prototype.max = function(val) {
var number = parseFloat(this.str);
if (!isNaN(number) && number > val) {
return this.error(this.msg || 'Invalid number');
}
return this;
}
var Filter = exports.Filter = function() {}
var whitespace = '\\r\\n\\t\\s';
Filter.prototype.modify = function(str) {
this.str = str;
}
//Create some aliases - may help code readability
Filter.prototype.convert = Filter.prototype.sanitize = function(str) {
this.str = str == null ? '' : str + '';
return this;
}
Filter.prototype.xss = function(is_image) {
this.modify(exports.xssClean(this.str, is_image));
return this.str;
}
Filter.prototype.defence = function(str) {
return this.sanitize(str).xss();
}
Filter.prototype.entityDecode = function() {
this.modify(decode(this.str));
return this.str;
}
Filter.prototype.entityEncode = function() {
this.modify(encode(this.str));
return this.str;
}
Filter.prototype.escape = function() {
this.modify(this.str.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(/</g, '<')
.replace(/>/g, '>'));
return this.str;
};
Filter.prototype.ltrim = function(chars) {
chars = chars || whitespace;
this.modify(this.str.replace(new RegExp('^['+chars+']+', 'g'), ''));
return this.str;
}
Filter.prototype.rtrim = function(chars) {
chars = chars || whitespace;
this.modify(this.str.replace(new RegExp('['+chars+']+$', 'g'), ''));
return this.str;
}
Filter.prototype.trim = function(chars) {
chars = chars || whitespace;
this.modify(this.str.replace(new RegExp('^['+chars+']+|['+chars+']+$', 'g'), ''));
return this.str;
}
Filter.prototype.ifNull = function(replace) {
if (!this.str || this.str === '') {
this.modify(replace);
}
return this.str;
}
Filter.prototype.toFloat = function() {
this.modify(parseFloat(this.str));
return this.str;
}
Filter.prototype.toInt = function(radix) {
radix = radix || 10;
this.modify(parseInt(this.str, radix));
return this.str;
}
//Any strings with length > 0 (except for '0' and 'false') are considered true,
//all other strings are false
Filter.prototype.toBoolean = function() {
if (!this.str || this.str == '0' || this.str == 'false' || this.str == '') {
this.modify(false);
} else {
this.modify(true);
}
return this.str;
}
//String must be equal to '1' or 'true' to be considered true, all other strings
//are false
Filter.prototype.toBooleanStrict = function() {
if (this.str == '1' || this.str == 'true') {
this.modify(true);
} else {
this.modify(false);
}
return this.str;
}
//Quick access methods
exports.sanitize = exports.convert = function(str) {
var filter = new exports.Filter();
return filter.sanitize(str);
}
exports.check = exports.validate = exports.assert = function(str, fail_msg) {
var validator = new exports.Validator();
return validator.check(str, fail_msg);
}
return exports;
}));