/*! * Copyright (c) 2010 Chris O'Hara * * 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': '', '': '-->', ' 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: //Google //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(/]*?)(>|$)/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|]*?)(\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|]*?)(\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|/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: //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, '>')); 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; }));