From 45e79528b07cb546b77031219d2bae39e9e02e69 Mon Sep 17 00:00:00 2001 From: life Date: Mon, 26 Oct 2015 17:57:00 +0800 Subject: [PATCH] export evernote ok --- data/version | 2 +- node_modules/file.js | 100 +- node_modules/resanitize/LICENSE | 24 + node_modules/resanitize/README.md | 36 + .../node_modules/validator/.npmignore | 1 + .../resanitize/node_modules/validator/LICENSE | 20 + .../node_modules/validator/README.md | 249 ++++ .../node_modules/validator/index.html | 16 + .../node_modules/validator/index.js | 1 + .../validator/lib/defaultError.js | 37 + .../node_modules/validator/lib/entities.js | 290 +++++ .../node_modules/validator/lib/filter.js | 109 ++ .../node_modules/validator/lib/index.js | 20 + .../node_modules/validator/lib/validator.js | 76 ++ .../node_modules/validator/lib/validators.js | 240 ++++ .../node_modules/validator/lib/xss.js | 228 ++++ .../node_modules/validator/package.json | 78 ++ .../resanitize/node_modules/validator/test.js | 5 + .../node_modules/validator/test/built.test.js | 5 + .../validator/test/exports.test.js | 59 + .../validator/test/filter.test.js | 172 +++ .../node_modules/validator/test/index.test.js | 3 + .../validator/test/messages.test.js | 95 ++ .../node_modules/validator/test/run.js | 12 + .../validator/test/validator.test.js | 742 ++++++++++++ .../node_modules/validator/validator-min.js | 23 + .../node_modules/validator/validator.js | 1010 +++++++++++++++++ node_modules/resanitize/package.json | 67 ++ node_modules/resanitize/resanitize.js | 290 +++++ public/config.js | 1 + public/js/app/api.js | 14 + public/plugins/export_evernote/enml.js | 80 ++ public/plugins/export_evernote/enml2.dtd | 592 ++++++++++ public/plugins/export_evernote/plugin.js | 490 ++++++++ 34 files changed, 5185 insertions(+), 2 deletions(-) create mode 100644 node_modules/resanitize/LICENSE create mode 100644 node_modules/resanitize/README.md create mode 100644 node_modules/resanitize/node_modules/validator/.npmignore create mode 100755 node_modules/resanitize/node_modules/validator/LICENSE create mode 100755 node_modules/resanitize/node_modules/validator/README.md create mode 100644 node_modules/resanitize/node_modules/validator/index.html create mode 100755 node_modules/resanitize/node_modules/validator/index.js create mode 100644 node_modules/resanitize/node_modules/validator/lib/defaultError.js create mode 100755 node_modules/resanitize/node_modules/validator/lib/entities.js create mode 100755 node_modules/resanitize/node_modules/validator/lib/filter.js create mode 100755 node_modules/resanitize/node_modules/validator/lib/index.js create mode 100644 node_modules/resanitize/node_modules/validator/lib/validator.js create mode 100644 node_modules/resanitize/node_modules/validator/lib/validators.js create mode 100755 node_modules/resanitize/node_modules/validator/lib/xss.js create mode 100644 node_modules/resanitize/node_modules/validator/package.json create mode 100644 node_modules/resanitize/node_modules/validator/test.js create mode 100644 node_modules/resanitize/node_modules/validator/test/built.test.js create mode 100644 node_modules/resanitize/node_modules/validator/test/exports.test.js create mode 100755 node_modules/resanitize/node_modules/validator/test/filter.test.js create mode 100644 node_modules/resanitize/node_modules/validator/test/index.test.js create mode 100644 node_modules/resanitize/node_modules/validator/test/messages.test.js create mode 100644 node_modules/resanitize/node_modules/validator/test/run.js create mode 100644 node_modules/resanitize/node_modules/validator/test/validator.test.js create mode 100644 node_modules/resanitize/node_modules/validator/validator-min.js create mode 100644 node_modules/resanitize/node_modules/validator/validator.js create mode 100644 node_modules/resanitize/package.json create mode 100644 node_modules/resanitize/resanitize.js create mode 100755 public/plugins/export_evernote/enml.js create mode 100644 public/plugins/export_evernote/enml2.dtd create mode 100644 public/plugins/export_evernote/plugin.js diff --git a/data/version b/data/version index a6bf9a74..4eb01765 100644 --- a/data/version +++ b/data/version @@ -1 +1 @@ -{"version":"0.7.0.2","updatedTime":"2015-10-16T07:11:51.505Z"} \ No newline at end of file +{"version":"0.9","updatedTime":"2015-10-16T07:11:51.505Z"} \ No newline at end of file diff --git a/node_modules/file.js b/node_modules/file.js index 9adbb03e..a88677aa 100644 --- a/node_modules/file.js +++ b/node_modules/file.js @@ -1,5 +1,6 @@ var db = require('db'); var fs = require('fs'); +var crypto = require('crypto'); var needle = require('needle'); var path = require('path'); var Evt = require('evt'); @@ -133,6 +134,93 @@ var File = { console.error(e); } }, + + getFileBase64: function(filePath) { + try { + // read binary data + var bitmap = fs.readFileSync(filePath); + if (!bitmap) { + return ''; + } + return new Buffer(bitmap).toString('base64'); + } catch(e) { + return ''; + } + }, + + getFileBase64AndMd5: function(filePath) { + try { + // read binary data + var bitmap = fs.readFileSync(filePath); + if (!bitmap) { + return ''; + } + var base64 = new Buffer(bitmap).toString('base64'); + + var hash = crypto.createHash('md5'); + hash.setEncoding('hex'); + hash.write(bitmap); + hash.end(); + var md5 = hash.read(); + + return {base64: base64, md5: md5} + + } catch(e) { + return ''; + } + }, + + getFileMd5: function (filePath) { + try { + var bitmap = fs.readFileSync(filePath); + if (!bitmap) { + return; + } + var hash = crypto.createHash('md5'); + hash.setEncoding('hex'); + hash.write(bitmap); + hash.end(); + return hash.read(); + } catch(e) { + return ''; + } + }, + + mines: { + "gif": "image/gif", + "jpeg": "image/jpeg", + "jpg": "image/jpeg", + "png": "image/png", + + "css": "text/css", + "html": "text/html", + "ico": "image/x-icon", + "js": "text/javascript", + "json": "application/json", + "pdf": "application/pdf", + "svg": "image/svg+xml", + "swf": "application/x-shockwave-flash", + "tiff": "image/tiff", + "txt": "text/plain", + "wav": "audio/x-wav", + "wma": "audio/x-ms-wma", + "wmv": "video/x-ms-wmv", + "xml": "text/xml" + }, + + getFileType: function (ext) { + if (!ext) { + return; + } + + ext = ext.toLowerCase(); + var type = this.mines[ext]; + if (type) { + return type; + } + return ext; + }, + _addAttach: function(filePath, fileTitle, callback) { try { var fileStat = fs.statSync(filePath); @@ -326,6 +414,16 @@ var File = { }); }, + getImageInfo: function(fileId, callback) { + db.images.findOne({FileId: fileId}, function(err, doc) { + if(!err && doc && doc.Path) { + callback(true, doc); + } else { + callback(false, false); + } + }); + }, + // 得到fileIds所有的images, 为了发送到服务器上 getAllImages: function(fileIds, callback) { var me = this; @@ -612,4 +710,4 @@ var File = { } }; -module.exports = File; \ No newline at end of file +module.exports = File; diff --git a/node_modules/resanitize/LICENSE b/node_modules/resanitize/LICENSE new file mode 100644 index 00000000..32aa8097 --- /dev/null +++ b/node_modules/resanitize/LICENSE @@ -0,0 +1,24 @@ +---------------------------------------------------------------------- +resanitize is released under the MIT License +Copyright (c) 2012 Dan MacTough - http://yabfog.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. diff --git a/node_modules/resanitize/README.md b/node_modules/resanitize/README.md new file mode 100644 index 00000000..0308c4d6 --- /dev/null +++ b/node_modules/resanitize/README.md @@ -0,0 +1,36 @@ +# Resanitize - Regular expression-based HTML sanitizer and ad remover, geared toward RSS feed descriptions + +This node.js module provides functions for removing unsafe parts and ads from +HTML. I am using it for the <description> element of RSS feeds. + +## Installation + +npm install resanitize + +## Usage + +```javascript + + var resanitize = require('resanitize') + , html = '
Headline
' + ; + + resanitize(html); // => '
Headline
' +``` + +## Notes + +This module's opinion of "sanitized" might not meet your security requirements. +The mere fact that it uses regular expressions should make this disclaimer +unnecessary, but just to be clear: if you intend to display arbitrary user input +that includes HTML, you're going to want something more robust. + +As of v0.3.0, we've added [node-validator's](//github.com/chriso/node-validator) XSS +filter. It's certainly an improvement, but still -- be careful. Any concerns +about XSS attacks should be directered to [node-validator's issue tracker](//github.com/chriso/node-validator/issues). + +Note that the `stripUnsafeTags` method will loop over the strip an arbitrary +number of times (2) to try to strip maliciously nested html tags. After the +maximum number of iterations is reached, if the string still appears to contain +any unsafe tags, it is deemed unsafe and set to an empty string. If this seems +unexpected and/or is causing any problems, please raise an [issue](//github.com/danmactough/node-resanitize/issues). \ No newline at end of file diff --git a/node_modules/resanitize/node_modules/validator/.npmignore b/node_modules/resanitize/node_modules/validator/.npmignore new file mode 100644 index 00000000..496ee2ca --- /dev/null +++ b/node_modules/resanitize/node_modules/validator/.npmignore @@ -0,0 +1 @@ +.DS_Store \ No newline at end of file diff --git a/node_modules/resanitize/node_modules/validator/LICENSE b/node_modules/resanitize/node_modules/validator/LICENSE new file mode 100755 index 00000000..c1a825a5 --- /dev/null +++ b/node_modules/resanitize/node_modules/validator/LICENSE @@ -0,0 +1,20 @@ +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. diff --git a/node_modules/resanitize/node_modules/validator/README.md b/node_modules/resanitize/node_modules/validator/README.md new file mode 100755 index 00000000..7dd945bd --- /dev/null +++ b/node_modules/resanitize/node_modules/validator/README.md @@ -0,0 +1,249 @@ +**node-validator is a library of string validation, filtering and sanitization methods.** + +To install node-validator, use [npm](http://github.com/isaacs/npm): + +```bash +$ npm install validator +``` + +To use the library in the browser, include `validator-min.js` + +## Example + +```javascript +var check = require('validator').check, + sanitize = require('validator').sanitize + +//Validate +check('test@email.com').len(6, 64).isEmail(); //Methods are chainable +check('abc').isInt(); //Throws 'Invalid integer' +check('abc', 'Please enter a number').isInt(); //Throws 'Please enter a number' +check('abcdefghijklmnopzrtsuvqxyz').is(/^[a-z]+$/); + +//Set a message per validator +check('foo', { + isNumeric: 'This is not a number', + contains: 'The value doesn\'t have a 0 in it' +}).isNumeric().contains('0'); + +//Referencing validator args from the message +check('foo', 'The message needs to be between %1 and %2 characters long (you passed "%0")').len(2, 6); + +//Sanitize / Filter +var int = sanitize('0123').toInt(); //123 +var bool = sanitize('true').toBoolean(); //true +var str = sanitize(' \t\r hello \n').trim(); //'hello' +var str = sanitize('aaaaaaaaab').ltrim('a'); //'b' +var str = sanitize(large_input_str).xss(); +var str = sanitize('<a>').entityDecode(); //'' +``` + +## Web development + +Often it's more desirable to check or automatically sanitize parameters by name (rather than the actual string). See [this gist](https://gist.github.com/752126) for instructions on binding the library to the `request` prototype. + +If you are using the [express.js framework](https://github.com/visionmedia/express) you can use the [express-validator middleware](https://github.com/ctavan/express-validator) to seamlessly integrate node-validator. + +Example `http://localhost:8080/?zip=12345&foo=1&textarea=large_string` + +```javascript +get('/', function (req, res) { + req.onValidationError(function (msg) { + //Redirect the user with error 'msg' + }); + + //Validate user input + req.check('zip', 'Please enter a valid ZIP code').len(4,5).isInt(); + req.check('email', 'Please enter a valid email').len(6,64).isEmail(); + req.checkHeader('referer').contains('localhost'); + + //Sanitize user input + req.sanitize('textarea').xss(); + req.sanitize('foo').toBoolean(); + + //etc. +}); +``` + +## An important note + +This library validates **strings** only. If you pass something that's not a string as input it will be coerced to a string using the following rules: + +- Is it an object with a `toString` property? Call `input.toString()` +- Is it `null`, `undefined`, or `NaN`? Replace with an empty string +- All other input? Coerce to a string using `'' + input` + +## List of validation methods + +```javascript +is() //Alias for regex() +not() //Alias for notRegex() +isEmail() +isUrl() //Accepts http, https, ftp +isIP() //Combines isIPv4 and isIPv6 +isIPv4() +isIPv6() +isAlpha() +isAlphanumeric() +isNumeric() +isHexadecimal() +isHexColor() //Accepts valid hexcolors with or without # prefix +isInt() //isNumeric accepts zero padded numbers, e.g. '001', isInt doesn't +isLowercase() +isUppercase() +isDecimal() +isFloat() //Alias for isDecimal +notNull() //Check if length is 0 +isNull() +notEmpty() //Not just whitespace (input.trim().length !== 0) +equals(equals) +contains(str) +notContains(str) +regex(pattern, modifiers) //Usage: regex(/[a-z]/i) or regex('[a-z]','i') +notRegex(pattern, modifiers) +len(min, max) //max is optional +isUUID(version) //Version can be 3, 4 or 5 or empty, see http://en.wikipedia.org/wiki/Universally_unique_identifier +isUUIDv3() //Alias for isUUID(3) +isUUIDv4() //Alias for isUUID(4) +isUUIDv5() //Alias for isUUID(5) +isDate() //Uses Date.parse() - regex is probably a better choice +isAfter(date) //Argument is optional and defaults to today. Comparison is non-inclusive +isBefore(date) //Argument is optional and defaults to today. Comparison is non-inclusive +isIn(options) //Accepts an array or string +notIn(options) +max(val) +min(val) +isCreditCard() //Will work against Visa, MasterCard, American Express, Discover, Diners Club, and JCB card numbering formats +``` + +## List of sanitization / filter methods + +```javascript +trim(chars) //Trim optional `chars`, default is to trim whitespace (\r\n\t ) +ltrim(chars) +rtrim(chars) +ifNull(replace) +toFloat() +toInt() +toBoolean() //True unless str = '0', 'false', or str.length == 0 +toBooleanStrict() //False unless str = '1' or 'true' +entityDecode() //Decode HTML entities +entityEncode() +escape() //Escape &, <, >, and " +xss() //Remove common XSS attack vectors from user-supplied HTML +xss(true) //Remove common XSS attack vectors from images +``` + +## Extending the library + +When adding to the Validator prototype, use `this.str` to access the string and `this.error(this.msg || default_msg)` when the string is invalid + +```javascript +var Validator = require('validator').Validator; +Validator.prototype.contains = function(str) { + if (!~this.str.indexOf(str)) { + this.error(this.msg || this.str + ' does not contain ' + str); + } + return this; //Allow method chaining +} +``` + +When adding to the Filter (sanitize) prototype, use `this.str` to access the string and `this.modify(new_str)` to update it + +```javascript +var Filter = require('validator').Filter; +Filter.prototype.removeNumbers = function() { + this.modify(this.str.replace(/[0-9]+/g, '')); + return this.str; +} +``` + +## Error handling + +By default, the validation methods throw an exception when a check fails + +```javascript +try { + check('abc').notNull().isInt() +} catch (e) { + console.log(e.message); //Invalid integer +} +``` + +To set a custom error message, set the second param of `check()` + +```javascript +try { + check('abc', 'Please enter a valid integer').notNull().isInt() +} catch (e) { + console.log(e.message); //Please enter a valid integer +} +``` + +To attach a custom error handler, set the `error` method of the validator instance + +```javascript +var Validator = require('validator').Validator; +var v = new Validator(); +v.error = function(msg) { + console.log('Fail'); +} +v.check('abc').isInt(); //'Fail' +``` + +You might want to collect errors instead of throwing each time + +```javascript +Validator.prototype.error = function (msg) { + this._errors.push(msg); + return this; +} + +Validator.prototype.getErrors = function () { + return this._errors; +} + +var validator = new Validator(); + +validator.check('abc').isEmail(); +validator.check('hello').len(10,30); + +var errors = validator.getErrors(); // ['Invalid email', 'String is too small'] +``` + +## Contributors + +- [zero21xxx](https://github.com/zero21xxx) - Added per check messages +- [PING](https://github.com/PlNG) - Fixed entity encoding +- [Dan VerWeire](https://github.com/wankdanker) - Modified the behaviour of the error handler +- [ctavan](https://github.com/ctavan) - Added isArray (since removed) and isUUID +- [foxbunny](https://github.com/foxbunny) - Added min(), max(), isAfter(), isBefore(), and improved isDate() +- [oris](https://github.com/orls) - Added in() +- [mren](https://github.com/mren) - Decoupled rules +- [Thorsten Basse](https://github.com/tbasse) - Cleanup and refinement of existing validators +- [Neal Poole](https://github.com/nealpoole) - Port the latest xss() updates from CodeIgniter + +## LICENSE + +(MIT License) + +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. diff --git a/node_modules/resanitize/node_modules/validator/index.html b/node_modules/resanitize/node_modules/validator/index.html new file mode 100644 index 00000000..62944998 --- /dev/null +++ b/node_modules/resanitize/node_modules/validator/index.html @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/node_modules/resanitize/node_modules/validator/index.js b/node_modules/resanitize/node_modules/validator/index.js new file mode 100755 index 00000000..0f485b93 --- /dev/null +++ b/node_modules/resanitize/node_modules/validator/index.js @@ -0,0 +1 @@ +exports = module.exports = require('./lib'); diff --git a/node_modules/resanitize/node_modules/validator/lib/defaultError.js b/node_modules/resanitize/node_modules/validator/lib/defaultError.js new file mode 100644 index 00000000..2980ca89 --- /dev/null +++ b/node_modules/resanitize/node_modules/validator/lib/defaultError.js @@ -0,0 +1,37 @@ +var defaultError = module.exports = { + isEmail: 'Invalid email', + isUrl: 'Invalid URL', + isIP: 'Invalid IP', + isAlpha: 'Invalid characters', + isAlphanumeric: 'Invalid characters', + isHexadecimal: 'Invalid hexadecimal', + isHexColor: 'Invalid hexcolor', + isNumeric: 'Invalid number', + isLowercase: 'Invalid characters', + isUppercase: 'Invalid characters', + isInt: 'Invalid integer', + isDecimal: 'Invalid decimal', + isDivisibleBy: 'Not divisible', + notNull: 'String is empty', + isNull: 'String is not empty', + notEmpty: 'String is empty', + equals: 'Not equal', + contains: 'Invalid characters', + notContains: 'Invalid characters', + regex: 'Invalid characters', + notRegex: 'Invalid characters', + len: 'String is not in range', + isUUID: 'Not a UUID', + isUUIDv3: 'Not a UUID v3', + isUUIDv4: 'Not a UUID v4', + isUUIDv5: 'Not a UUID v5', + isDate: 'Not a date', + isAfter: 'Invalid date', + isBefore: 'Invalid date', + isIn: 'Unexpected value or invalid argument', + notIn: 'Unexpected value or invalid argument', + min: 'Invalid number', + max: 'Invalid number', + isCreditCard: 'Invalid credit card' +}; + diff --git a/node_modules/resanitize/node_modules/validator/lib/entities.js b/node_modules/resanitize/node_modules/validator/lib/entities.js new file mode 100755 index 00000000..ddfcf928 --- /dev/null +++ b/node_modules/resanitize/node_modules/validator/lib/entities.js @@ -0,0 +1,290 @@ +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', + '½': '\u00bd', + '¾': '\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', + 'ℑ': '\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' +}; + +exports.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; +} + +exports.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; +} diff --git a/node_modules/resanitize/node_modules/validator/lib/filter.js b/node_modules/resanitize/node_modules/validator/lib/filter.js new file mode 100755 index 00000000..f828c33e --- /dev/null +++ b/node_modules/resanitize/node_modules/validator/lib/filter.js @@ -0,0 +1,109 @@ +var entities = require('./entities'); +var xss = require('./xss'); + +var Filter = exports.Filter = function() {} + +var whitespace = '\\r\\n\\t\\s'; + +Filter.prototype.modify = function(str) { + this.str = str; +} + +Filter.prototype.wrap = function (str) { + return str; +} + +Filter.prototype.value = function () { + return this.str; +} + +Filter.prototype.chain = function () { + this.wrap = function () { return this }; + return this; +} + +//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(xss.clean(this.str, is_image)); + return this.wrap(this.str); +} + +Filter.prototype.entityDecode = function() { + this.modify(entities.decode(this.str)); + return this.wrap(this.str); +} + +Filter.prototype.entityEncode = function() { + this.modify(entities.encode(this.str)); + return this.wrap(this.str); +} + +Filter.prototype.ltrim = function(chars) { + chars = chars || whitespace; + this.modify(this.str.replace(new RegExp('^['+chars+']+', 'g'), '')); + return this.wrap(this.str); +} + +Filter.prototype.rtrim = function(chars) { + chars = chars || whitespace; + this.modify(this.str.replace(new RegExp('['+chars+']+$', 'g'), '')); + return this.wrap(this.str); +} + +Filter.prototype.trim = function(chars) { + chars = chars || whitespace; + this.modify(this.str.replace(new RegExp('^['+chars+']+|['+chars+']+$', 'g'), '')); + return this.wrap(this.str); +} + +Filter.prototype.escape = function() { + this.modify(this.str.replace(/&/g, '&') + .replace(/"/g, '"') + .replace(//g, '>')); + return this.wrap(this.str); +}; + +Filter.prototype.ifNull = function(replace) { + if (!this.str || this.str === '') { + this.modify(replace); + } + return this.wrap(this.str); +} + +Filter.prototype.toFloat = function() { + this.modify(parseFloat(this.str)); + return this.wrap(this.str); +} + +Filter.prototype.toInt = function(radix) { + this.modify(parseInt(this.str, radix || 10)); + return this.wrap(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.wrap(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.wrap(this.str); +} diff --git a/node_modules/resanitize/node_modules/validator/lib/index.js b/node_modules/resanitize/node_modules/validator/lib/index.js new file mode 100755 index 00000000..881e948a --- /dev/null +++ b/node_modules/resanitize/node_modules/validator/lib/index.js @@ -0,0 +1,20 @@ +var node_validator = require('./validator'); + +exports.Validator = node_validator.Validator; +exports.ValidatorError = node_validator.ValidatorError; +exports.Filter = require('./filter').Filter; +exports.validators = require('./validators'); +exports.defaultError = require('./defaultError'); + +exports.entities = require('./entities'); + +//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); +} diff --git a/node_modules/resanitize/node_modules/validator/lib/validator.js b/node_modules/resanitize/node_modules/validator/lib/validator.js new file mode 100644 index 00000000..fc6ed645 --- /dev/null +++ b/node_modules/resanitize/node_modules/validator/lib/validator.js @@ -0,0 +1,76 @@ +var util = require('util'); +var validators = require('./validators'); +exports.defaultError = require('./defaultError'); + +var ValidatorError = exports.ValidatorError = function(msg) { + Error.captureStackTrace(this, this); + this.name = 'ValidatorError'; + this.message = msg; +}; +util.inherits(ValidatorError, Error); + +var Validator = exports.Validator = function(options) { + options = options || {}; + this.options = options; + + this.options.messageBuilder = this.options.messageBuilder || function (msg, args) { + if (typeof msg === 'string') { + args.forEach(function(arg, i) { msg = msg.replace('%'+i, arg); }); + } + return msg; + }; +}; + +Validator.prototype.error = function (msg) { + throw new ValidatorError(msg); +}; + +Validator.prototype.check = function(str, fail_msg) { + if (typeof str === 'object' && str !== null && str.toString) { + str = str.toString(); + } + this.str = (str == null || (isNaN(str) && str.length == undefined)) ? '' : str; + this.str += ''; + + // This is a key, value pair of error messages to use + if (typeof fail_msg === 'object') { + this.errorDictionary = fail_msg; + this.msg = null + } + else { + this.errorDictionary = {}; + this.msg = fail_msg; + } + + this._errors = this._errors || []; + return this; +} + +for (var key in validators) { + if (validators.hasOwnProperty(key)) { + (function (key) { + Validator.prototype[key] = function() { + var args = Array.prototype.slice.call(arguments); + args.unshift(this.str); + if(!validators[key].apply(this, args)) { + var msg = exports.defaultError[key]; + if (key in this.errorDictionary) { + msg = this.errorDictionary[key]; + } else if (this.msg !== null && typeof this.msg !== 'undefined') { + msg = this.msg; + } + msg = this.options.messageBuilder(msg, args); + return this.error(msg); + } + return this; + }; + })(key); + } +} + +//Create some aliases - may help code readability +Validator.prototype.validate = Validator.prototype.check; +Validator.prototype.assert = Validator.prototype.check; +Validator.prototype.isFloat = Validator.prototype.isDecimal; +Validator.prototype.is = Validator.prototype.regex; +Validator.prototype.not = Validator.prototype.notRegex; diff --git a/node_modules/resanitize/node_modules/validator/lib/validators.js b/node_modules/resanitize/node_modules/validator/lib/validators.js new file mode 100644 index 00000000..7b66e195 --- /dev/null +++ b/node_modules/resanitize/node_modules/validator/lib/validators.js @@ -0,0 +1,240 @@ + +// Helper function to avoid duplication of code +function toDateTime(date) { + if (date instanceof Date) { + return date; + } + var intDate = Date.parse(date); + if (isNaN(intDate)) { + return null; + } + return new Date(intDate); +} + +// Convert to date without the time component +function toDate(date) { + if (!(date instanceof Date)) { + date = toDateTime(date); + } + if (!date) { + return null; + } + return date; +} + +var validators = module.exports = { + isEmail: function(str) { + return 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])\]))$/); + }, + isUrl: function(str) { + //A modified version of the validator from @diegoperini / https://gist.github.com/729294 + return str.length < 2083 && 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}(?:\.(?:[0-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); + }, + //node-js-core + isIP : function(str) { + if (validators.isIPv4(str)) { + return 4; + } else if (validators.isIPv6(str)) { + return 6; + } else { + return 0; + } + }, + //node-js-core + isIPv4 : function(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; + }, + //node-js-core + isIPv6 : function(str) { + if (/^::|^::1|^([a-fA-F0-9]{1,4}::?){1,7}([a-fA-F0-9]{1,4})$/.test(str)) { + return true; + } + return false; + }, + isIPNet: function(str) { + return validators.isIP(str) !== 0; + }, + isAlpha: function(str) { + return str.match(/^[a-zA-Z]+$/); + }, + isAlphanumeric: function(str) { + return str.match(/^[a-zA-Z0-9]+$/); + }, + isNumeric: function(str) { + return str.match(/^-?[0-9]+$/); + }, + isHexadecimal: function(str) { + return str.match(/^[0-9a-fA-F]+$/); + }, + isHexColor: function(str) { + return str.match(/^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/); + }, + isLowercase: function(str) { + return str === str.toLowerCase(); + }, + isUppercase: function(str) { + return str === str.toUpperCase(); + }, + isInt: function(str) { + return str.match(/^(?:-?(?:0|[1-9][0-9]*))$/); + }, + isDecimal: function(str) { + return str !== '' && str.match(/^(?:-?(?:[0-9]+))?(?:\.[0-9]*)?(?:[eE][\+\-]?(?:[0-9]+))?$/); + }, + isFloat: function(str) { + return validators.isDecimal(str); + }, + isDivisibleBy: function(str, n) { + return (parseFloat(str) % parseInt(n, 10)) === 0; + }, + notNull: function(str) { + return str !== ''; + }, + isNull: function(str) { + return str === ''; + }, + notEmpty: function(str) { + return !str.match(/^[\s\t\r\n]*$/); + }, + equals: function(a, b) { + return a == b; + }, + contains: function(str, elem) { + return str.indexOf(elem) >= 0 && !!elem; + }, + notContains: function(str, elem) { + return !validators.contains(str, elem); + }, + regex: function(str, pattern, modifiers) { + str += ''; + if (Object.prototype.toString.call(pattern).slice(8, -1) !== 'RegExp') { + pattern = new RegExp(pattern, modifiers); + } + return str.match(pattern); + }, + is: function(str, pattern, modifiers) { + return validators.regex(str, pattern, modifiers); + }, + notRegex: function(str, pattern, modifiers) { + return !validators.regex(str, pattern, modifiers); + }, + not: function(str, pattern, modifiers) { + return validators.notRegex(str, pattern, modifiers); + }, + len: function(str, min, max) { + return str.length >= min && (max === undefined || str.length <= max); + }, + //Thanks to github.com/sreuter for the idea. + isUUID: function(str, 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; + } + return pattern.test(str); + }, + isUUIDv3: function(str) { + return validators.isUUID(str, 3); + }, + isUUIDv4: function(str) { + return validators.isUUID(str, 4); + }, + isUUIDv5: function(str) { + return validators.isUUID(str, 5); + }, + isDate: function(str) { + var intDate = Date.parse(str); + return !isNaN(intDate); + }, + isAfter: function(str, date) { + date = date || new Date(); + var origDate = toDate(str); + var compDate = toDate(date); + return !(origDate && compDate && origDate <= compDate); + }, + isBefore: function(str, date) { + date = date || new Date(); + var origDate = toDate(str); + var compDate = toDate(date); + return !(origDate && compDate && origDate >= compDate); + }, + isIn: function(str, options) { + if (!options || typeof options.indexOf !== 'function') { + return false; + } + if (Array.isArray(options)) { + options = options.map(String); + } + return options.indexOf(str) >= 0; + }, + notIn: function(str, options) { + if (!options || typeof options.indexOf !== 'function') { + return false; + } + if (Array.isArray(options)) { + options = options.map(String); + } + return options.indexOf(str) < 0; + }, + min: function(str, val) { + var number = parseFloat(str); + return isNaN(number) || number >= val; + }, + max: function(str, val) { + var number = parseFloat(str); + return isNaN(number) || number <= val; + }, + //Will work against Visa, MasterCard, American Express, Discover, Diners Club, and JCB card numbering formats + isCreditCard: function(str) { + //remove all dashes, spaces, etc. + var sanitized = str.replace(/[^0-9]+/g, ''); + if (sanitized.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})$/) === null) { + return null; + } + // Doing Luhn check + var sum = 0; + var digit; + var tmpNum; + var shouldDouble = false; + for (var i = sanitized.length - 1; i >= 0; i--) { + digit = sanitized.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 sanitized; + } else { + return null; + } + } +}; diff --git a/node_modules/resanitize/node_modules/validator/lib/xss.js b/node_modules/resanitize/node_modules/validator/lib/xss.js new file mode 100755 index 00000000..4a2ed9e6 --- /dev/null +++ b/node_modules/resanitize/node_modules/validator/lib/xss.js @@ -0,0 +1,228 @@ +//This module is adapted from the CodeIgniter framework +//The license is available at http://codeigniter.com/ + +var html_entity_decode = require('./entities').decode; + +var never_allowed_str = { + 'document.cookie': '[removed]', + 'document.write': '[removed]', + '.parentNode': '[removed]', + '.innerHTML': '[removed]', + 'window.location': '[removed]', + '-moz-binding': '[removed]', + '': '-->', + '(': '<comment>' +}; + +var never_allowed_regex = { + 'javascript\\s*:': '[removed]', + 'expression\\s*(\\(|()': '[removed]', + 'vbscript\\s*:': '[removed]', + 'Redirect\\s+302': '[removed]', + "([\"'])?data\\s*:[^\\1]*?base64[^\\1]*?,[^\\1]*?\\1?": '[removed]' +}; + +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', 'base64', 'applet', 'alert', + 'document', 'write', 'cookie', 'window' +]; + +exports.clean = function(str, is_image) { + + //Remove invisible characters + str = remove_invisible_characters(str); + + //Protect query string variables in URLs => 901119URL5918AMP18930PROTECT8198 + var hash; + do { + // ensure str does not contain hash before inserting it + hash = xss_hash(); + } while(str.indexOf(hash) >= 0) + str = str.replace(/\&([a-z\_0-9\-]+)\=([a-z\_0-9\-]+)/ig, 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])*;?/ig, '$1;$2'); + + //Validate UTF16 two byte encoding (x00) - just as above, adds a semicolon if missing. + str = str.replace(/(&#x?)([0-9A-F]+);?/ig, '$1$2;'); + + //Un-protect query string variables + str = str.replace(new RegExp(hash, 'g'), '&'); + + //Decode just in case stuff like this is submitted: + //Google + try{ + str = decodeURIComponent(str); + } + catch(error){ + // str was not actually URI-encoded + } + + //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)); + }); + str = str.replace(/<\w+.*/gi, function(m) { + return m.replace(m, html_entity_decode(m)); + }); + + //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(new RegExp(i, "gi"), never_allowed_str[i]); + } + + //Remove regex patterns that are never allowed + for (var i in never_allowed_regex) { + str = str.replace(new RegExp(i, 'gi'), 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 = 0, l = compact_words.length; i < l; i++) { + var spacified = compact_words[i].split('').join('\\s*')+'\\s*'; + + str = str.replace(new RegExp('('+spacified+')(\\W)', 'ig'), function(m, compat, after) { + return compat.replace(/\s+/g, '') + after; + }); + } + + //Remove disallowed Javascript in links or img tags + do { + var original = str; + + if (str.match(/]*?)(>|$)/gi, function(m, attributes, end_tag) { + var filtered_attributes = filter_attributes(attributes.replace('<','').replace('>','')); + filtered_attributes = filtered_attributes.replace(/href=.*?(?:alert\(|alert(|javascript:|livescript:|mocha:|charset=|window\.|document\.|\.cookie|]*?)(\s?\/?>|$)/gi, function(m, attributes, end_tag) { + var filtered_attributes = filter_attributes(attributes.replace('<','').replace('>','')); + filtered_attributes = filtered_attributes.replace(/src=.*?(?:alert\(|alert(|javascript:|livescript:|mocha:|charset=|window\.|document\.|\.cookie|/gi, '[removed]'); + } + + } while(original !== str); + + // Remove Evil HTML Attributes (like event handlers and style) + var event_handlers = ['\\bon\\w*', '\\bstyle', '\\bformaction']; + + //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'); + } + + do { + var attribs = []; + var count = 0; + + attribs = attribs.concat(str.match(new RegExp("("+event_handlers.join('|')+")\\s*=\\s*(\\x22|\\x27)([^\\2]*?)(\\2)", 'ig'))); + attribs = attribs.concat(str.match(new RegExp("("+event_handlers.join('|')+")\\s*=\\s*([^\\s>]*)", 'ig'))); + attribs = attribs.filter(function(element) { return element !== null; }); + + if (attribs.length > 0) { + for (var i = 0; i < attribs.length; ++i) { + attribs[i] = attribs[i].replace(new RegExp('[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\-]', 'g'), '\\$&') + } + + str = str.replace(new RegExp("(<]+?)([^A-Za-z<>\\-])(.*?)("+attribs.join('|')+")(.*?)([\\s><]?)([><]*)", 'i'), function(m, a, b, c, d, e, f, g, h) { + ++count; + return a + b + ' ' + d + f + g + h; + }); + } + } while (count > 0); + + //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> + var 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|video|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(new RegExp(i, "gi"), never_allowed_str[i]); + } + for (var i in never_allowed_regex) { + str = str.replace(new RegExp(i, 'gi'), 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 = 0, l = non_displayables.length; i < l; i++) { + str = str.replace(non_displayables[i], ''); + } + return str; +} + +function xss_hash() { + var str = '', num = 10; + while (num--) str += String.fromCharCode(Math.random() * 25 | 97); + return str; +} + +function convert_attribute(str) { + return str.replace('>','>').replace('<','<').replace('\\','\\\\'); +} + +function filter_attributes(str) { + var result = ""; + + var match = str.match(/\s*[a-z-]+\s*=\s*(\x22|\x27)([^\1]*?)\1/ig); + if (match) { + for (var i = 0; i < match.length; ++i) { + result += match[i].replace(/\*.*?\*/g, ''); + } + } + + return result; +} + diff --git a/node_modules/resanitize/node_modules/validator/package.json b/node_modules/resanitize/node_modules/validator/package.json new file mode 100644 index 00000000..9c801cd0 --- /dev/null +++ b/node_modules/resanitize/node_modules/validator/package.json @@ -0,0 +1,78 @@ +{ + "name": "validator", + "description": "Data validation, filtering and sanitization for node.js", + "version": "1.5.1", + "homepage": "http://github.com/chriso/node-validator", + "keywords": [ + "validator", + "validation", + "assert", + "params", + "sanitization", + "xss", + "entities", + "sanitize", + "sanitisation", + "input" + ], + "author": { + "name": "Chris O'Hara", + "email": "cohara87@gmail.com" + }, + "main": "./lib", + "directories": { + "lib": "./lib" + }, + "bugs": { + "url": "http://github.com/chriso/node-validator/issues" + }, + "repository": { + "type": "git", + "url": "http://github.com/chriso/node-validator.git" + }, + "contributors": [ + { + "name": "PING" + }, + { + "name": "Dan VerWeire" + }, + { + "name": "Branko Vukelic" + }, + { + "name": "Mark Engel" + } + ], + "scripts": { + "test": "node test/run.js" + }, + "engines": { + "node": ">=0.2.2" + }, + "licenses": [ + { + "type": "MIT", + "url": "http://github.com/chriso/node-validator/raw/master/LICENSE" + } + ], + "_id": "validator@1.5.1", + "dist": { + "shasum": "7ab356cbbcbbb000ab85c43b8cda12621b1344c0", + "tarball": "http://registry.npmjs.org/validator/-/validator-1.5.1.tgz" + }, + "_from": "validator@>=1.5.1 <1.6.0", + "_npmVersion": "1.3.8", + "_npmUser": { + "name": "cohara87", + "email": "cohara87@gmail.com" + }, + "maintainers": [ + { + "name": "cohara87", + "email": "cohara87@gmail.com" + } + ], + "_shasum": "7ab356cbbcbbb000ab85c43b8cda12621b1344c0", + "_resolved": "https://registry.npmjs.org/validator/-/validator-1.5.1.tgz" +} diff --git a/node_modules/resanitize/node_modules/validator/test.js b/node_modules/resanitize/node_modules/validator/test.js new file mode 100644 index 00000000..0967a88b --- /dev/null +++ b/node_modules/resanitize/node_modules/validator/test.js @@ -0,0 +1,5 @@ +v = require('./'); + +//console.log(v.sanitize('prompt(1);').xss()); + +v.check('foo', 'The message needs to be between %1 and %2 characters long (you passed "%0")').len(4, 6); diff --git a/node_modules/resanitize/node_modules/validator/test/built.test.js b/node_modules/resanitize/node_modules/validator/test/built.test.js new file mode 100644 index 00000000..d43ca34f --- /dev/null +++ b/node_modules/resanitize/node_modules/validator/test/built.test.js @@ -0,0 +1,5 @@ +// tests exports of built validator.js file + +var node_validator = require('../validator.js'); + +module.exports = require('./exports.test.js')(node_validator); \ No newline at end of file diff --git a/node_modules/resanitize/node_modules/validator/test/exports.test.js b/node_modules/resanitize/node_modules/validator/test/exports.test.js new file mode 100644 index 00000000..e2b5b17b --- /dev/null +++ b/node_modules/resanitize/node_modules/validator/test/exports.test.js @@ -0,0 +1,59 @@ +// not to be run on its own... +// to be required in module that already has node_validator defined and passed as param to require +// that way it can be used to test the built versions too when they are compiled + +var assert = require('assert'); + +module.exports = function(node_validator) { + + return { + + 'test #Validator is exported when built': function () { + assert.equal(typeof node_validator.Validator, 'function'); + }, + + 'test #ValidatorError is exported when built': function () { + assert.equal(typeof node_validator.ValidatorError, 'function'); + }, + + 'test #Filter is exported when built': function () { + assert.equal(typeof node_validator.Filter, 'function'); + }, + + 'test #validators is exported when built': function () { + assert.equal(typeof node_validator.validators, 'object'); + }, + + 'test #defaultError is exported when built': function () { + assert.equal(typeof node_validator.defaultError, 'object'); + }, + + 'test #entities is exported when built': function () { + assert.equal(typeof node_validator.entities, 'object'); + }, + + 'test #sanitize is exported when built': function () { + assert.equal(typeof node_validator.sanitize, 'function'); + }, + + 'test #convert alias for #sanitize is exported when built': function () { + assert.equal(typeof node_validator.convert, 'function'); + assert.equal(node_validator.convert, node_validator.sanitize); + }, + + 'test #check is exported when built': function () { + assert.equal(typeof node_validator.check, 'function'); + }, + + 'test #validate alias for #check is exported when built': function () { + assert.equal(typeof node_validator.validate, 'function'); + assert.equal(node_validator.validate, node_validator.check); + }, + + 'test #assert alias for #check is exported when built': function () { + assert.equal(typeof node_validator.assert, 'function'); + assert.equal(node_validator.assert, node_validator.check); + } + } + +}; \ No newline at end of file diff --git a/node_modules/resanitize/node_modules/validator/test/filter.test.js b/node_modules/resanitize/node_modules/validator/test/filter.test.js new file mode 100755 index 00000000..65f3b68c --- /dev/null +++ b/node_modules/resanitize/node_modules/validator/test/filter.test.js @@ -0,0 +1,172 @@ +var node_validator = require('../lib'), + Filter = new node_validator.Filter(), + assert = require('assert'); + +module.exports = { + 'test #ifNull()': function () { + + //Make sure sanitize returns the new string + assert.equal(5, Filter.sanitize('').ifNull(5)); + assert.equal('abc', Filter.sanitize().ifNull('abc')); + + //Modify Filter.modify() to automatically replace a var with the sanitized version + var param = ''; + Filter.modify = function(str) { + this.str = str; + param = str; + } + Filter.sanitize(param).ifNull('foobar'); + assert.equal('foobar', param); + }, + + 'test #toBoolean()': function () { + assert.equal(true, Filter.sanitize('1').toBoolean()); + assert.equal(true, Filter.sanitize('true').toBoolean()); + assert.equal(true, Filter.sanitize('foobar').toBoolean()); + assert.equal(true, Filter.sanitize(5).toBoolean()); + assert.equal(true, Filter.sanitize(' ').toBoolean()); + + assert.equal(false, Filter.sanitize('0').toBoolean()); + assert.equal(false, Filter.sanitize('false').toBoolean()); + assert.equal(false, Filter.sanitize('').toBoolean()); + assert.equal(false, Filter.sanitize('false').toBoolean()); + }, + + 'test #toBooleanStrict()': function () { + assert.equal(true, Filter.sanitize('1').toBooleanStrict()); + assert.equal(true, Filter.sanitize('true').toBooleanStrict()); + + assert.equal(false, Filter.sanitize('foobar').toBooleanStrict()); + assert.equal(false, Filter.sanitize(5).toBooleanStrict()); + assert.equal(false, Filter.sanitize(' ').toBooleanStrict()); + assert.equal(false, Filter.sanitize('0').toBooleanStrict()); + assert.equal(false, Filter.sanitize('false').toBooleanStrict()); + assert.equal(false, Filter.sanitize('').toBooleanStrict()); + assert.equal(false, Filter.sanitize('false').toBooleanStrict()); + }, + + 'test #trim()': function () { + //Test trim() with spaces + assert.equal('abc', Filter.sanitize(' abc').trim()); + assert.equal('abc', Filter.sanitize('abc ').trim()); + assert.equal('abc', Filter.sanitize(' abc ').trim()); + + //Test trim() with \t + assert.equal('abc', Filter.sanitize(' abc').trim()); + assert.equal('abc', Filter.sanitize('abc ').trim()); + assert.equal('abc', Filter.sanitize(' abc ').trim()); + + //Test trim() with a mixture of \t, \s, \r and \n + assert.equal('abc', Filter.sanitize(' \r\n abc\r\n ').trim()); + + //Test trim() with custom chars + assert.equal('2', Filter.sanitize('000020000').trim('0')); + assert.equal('202', Filter.sanitize('01000202100101').trim('01')); + }, + + 'test #ltrim()': function () { + //Test ltrim() with spaces + assert.equal('abc', Filter.sanitize(' abc').ltrim()); + assert.equal('abc ', Filter.sanitize(' abc ').ltrim()); + + //Test ltrim() with \t + assert.equal('abc', Filter.sanitize(' abc').ltrim()); + assert.equal('abc ', Filter.sanitize(' abc ').ltrim()); + + //Test ltrim() with a mixture of \t, \s, \r and \n + assert.equal('abc\r\n', Filter.sanitize(' \r\n abc\r\n').ltrim()); + + //Test ltrim() with custom chars + assert.equal('20', Filter.sanitize('000020').ltrim('0')); + assert.equal('201', Filter.sanitize('010100201').ltrim('01')); + }, + + 'test #rtrim()': function () { + //Test rtrim() with spaces + assert.equal(' abc', Filter.sanitize(' abc ').rtrim()); + assert.equal('abc', Filter.sanitize('abc ').rtrim()); + + //Test rtrim() with \t + assert.equal(' abc', Filter.sanitize(' abc').rtrim()); + assert.equal('abc', Filter.sanitize('abc ').rtrim()); + + //Test rtrim() with a mixture of \t, \s, \r and \n + assert.equal(' \r\n abc', Filter.sanitize(' \r\n abc\r\n ').rtrim()); + + //Test rtrim() with custom chars + assert.equal('02', Filter.sanitize('02000').rtrim('0')); + assert.equal('012', Filter.sanitize('01201001').rtrim('01')); + }, + + 'test #toInt()': function () { + assert.ok(3 === Filter.sanitize('3').toInt()); + assert.ok(255 === Filter.sanitize('ff').toInt(16)); + assert.ok(3 === Filter.sanitize(' 3 ').toInt()); + }, + + 'test #toFloat()': function () { + assert.ok(3 === Filter.sanitize('3.').toFloat()); + assert.ok(3 === Filter.sanitize(' 3 ').toFloat()); + assert.ok(0 === Filter.sanitize('.0').toFloat()); + assert.ok(13.13 === Filter.sanitize('13.13').toFloat()); + }, + + 'test #entityDecode()': function () { + assert.equal('&', Filter.sanitize('&').entityDecode()); + assert.equal('&&', Filter.sanitize('&&').entityDecode()); + assert.equal('""', Filter.sanitize('""').entityDecode()); + assert.equal('€', Filter.sanitize('€').entityDecode()); + assert.equal("'", Filter.sanitize("'").entityDecode()); + assert.equal("'", Filter.sanitize("'").entityDecode()); + assert.equal('œ', Filter.sanitize('œ').entityDecode()); + assert.equal('½', Filter.sanitize('½').entityDecode()); + }, + + 'test #entityEncode()': function () { + assert.equal('&', Filter.sanitize('&').entityEncode()); + assert.equal('&&', Filter.sanitize('&&').entityEncode()); + assert.equal(''', Filter.sanitize("'").entityEncode()); + assert.equal('""', Filter.sanitize('""').entityEncode()); + assert.equal('€', Filter.sanitize('€').entityEncode()); + assert.equal('œ', Filter.sanitize('œ').entityEncode()); + assert.equal('½', Filter.sanitize('½').entityEncode()); + }, + + 'test #xss()': function () { + //Need more tests! + assert.equal('[removed] foobar', Filter.sanitize('javascript : foobar').xss()); + assert.equal('[removed] foobar', Filter.sanitize('j a vasc ri pt: foobar').xss()); + assert.equal('some text', Filter.sanitize('some text').xss()); + + assert.equal(' This is a test', Filter.sanitize(' This is a test').xss()); + assert.equal('">test', Filter.sanitize('">test').xss()); + assert.equal('

You have won

Please click the link and enter your login details: http://good.com
', Filter.sanitize('

You have won

Please click the link and enter your login details: http://good.com
').xss()); + assert.equal('prompt(1);', Filter.sanitize('prompt(1);').xss()); + assert.equal('', Filter.sanitize('').xss()); + assert.equal('', Filter.sanitize('').xss()); + assert.equal('