Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

用户注册功能添加及页面美化

  • Loading branch information...
commit f762e19e3de2d42fb3f92ab21c75ded5bc26b351 1 parent f9b636b
dgunzi authored October 30, 2012

Showing 31 changed files with 3,553 additions and 110 deletions. Show diff stats Hide diff stats

  1. 21  app.js
  2. 110  controllers/user.js
  3. 2  models/index.js
  4. 22  models/user.js
  5. 1  node_modules/validator/.npmignore
  6. 20  node_modules/validator/LICENSE
  7. 220  node_modules/validator/README.md
  8. 15  node_modules/validator/index.html
  9. 1  node_modules/validator/index.js
  10. 291  node_modules/validator/lib/entities.js
  11. 102  node_modules/validator/lib/filter.js
  12. 15  node_modules/validator/lib/index.js
  13. 314  node_modules/validator/lib/validator.js
  14. 203  node_modules/validator/lib/xss.js
  15. 65  node_modules/validator/package.json
  16. 4  node_modules/validator/test.js
  17. 145  node_modules/validator/test/filter.test.js
  18. 8  node_modules/validator/test/run.js
  19. 604  node_modules/validator/test/validator.test.js
  20. 22  node_modules/validator/validator-min.js
  21. 861  node_modules/validator/validator.js
  22. 2  public/css/bootstrap.css
  23. 133  public/css/custom.css
  24. 9  routes.js
  25. BIN  tmp/62d78420-199c-11e2-ac41-797333fe0698
  26. 1  views/common/header.html
  27. 50  views/cookbookview.html
  28. 96  views/index.html
  29. 62  views/user_add.html
  30. 177  views/user_view.html
  31. 87  views/user_views.html
21  app.js
@@ -10,16 +10,20 @@ var express = require('express'),
10 10
 	path = require('path');
11 11
 
12 12
 app.configure(function(){
  13
+	
13 14
 	app.set('views', __dirname + '/views');
  15
+	
14 16
 	app.use(express.bodyParser());
15 17
   	app.use(express.methodOverride());
16  
-	//app.use(express.static(__dirname + '/public'));
  18
+  	
  19
+	app.use(express.cookieParser());
  20
+	app.use(express.session({
  21
+	    secret: config.session_secret
  22
+	}));
  23
+	
17 24
 	app.set('view engine', 'html');
18 25
 	app.engine('html', ejs.renderFile);
19  
-	
20  
-	/*app.use(express.session({
21  
-    	secret: config.session_secret
22  
-  	}));*/
  26
+
23 27
 });
24 28
 
25 29
 var staticDir = path.join(__dirname, 'public');
@@ -35,12 +39,6 @@ app.configure('production', function(){
35 39
   app.use(express.errorHandler());
36 40
   app.use('view cache',true);
37 41
   
38  
-  app.use(express.csrf());
39  
-
40  
-  app.use(function(req, res, next) {
41  
-    res.locals.csrf = req.session ? req.session._csrf : '';
42  
-    next();
43  
-  });
44 42
 });
45 43
 
46 44
 //定义locals变量
@@ -49,7 +47,6 @@ app.locals({
49 47
     site : site
50 48
 });
51 49
 
52  
-
53 50
 // Routes
54 51
 routes(app);
55 52
 
110  controllers/user.js
... ...
@@ -0,0 +1,110 @@
  1
+/*
  2
+ * user.js 用户编辑和添加
  3
+ * 
  4
+ * */
  5
+
  6
+var config = require('../config/config').config;
  7
+var crypto = require('crypto');
  8
+var models = require('../models');
  9
+var User = models.User;
  10
+var check = require('validator').check,
  11
+    sanitize = require('validator').sanitize;
  12
+
  13
+
  14
+//设置缓存函数
  15
+function gen_session(user, res, req){
  16
+    var auth_token = encrypt(user._id + '\t' + user.user_name + '\t' + user.password + '\t' + user.email, config.session_secret);
  17
+    res.cookie(config.auth_cookie_name, auth_token, {path: '/',maxAge: 1000 * 60 * 60}); //cookie 有效期1个小时
  18
+    req.session.user = user;
  19
+    req.session.cookie.maxAge = 1000 * 60 * 60;
  20
+}
  21
+
  22
+//对称加密函数
  23
+function encrypt(str, secret){
  24
+    var cipher = crypto.createCipher('aes192', secret);
  25
+    var enc = cipher.update(str, 'utf8', 'hex');
  26
+    enc += cipher.final('hex');
  27
+    return enc;
  28
+}
  29
+
  30
+function decrypt(str, secret){
  31
+    var decipher = crypto.createDecipher('aes192', secret);
  32
+    var dec = decipher.update(str, 'hex', 'utf8');
  33
+    dec += decipher.final('utf8');
  34
+    return dec;
  35
+}
  36
+
  37
+function md5(str) {
  38
+  var md5sum = crypto.createHash('md5');
  39
+  md5sum.update(str);
  40
+  str = md5sum.digest('hex');
  41
+  return str;
  42
+}
  43
+
  44
+//add view
  45
+exports.add_html = function(req, res, next){
  46
+    res.render('user_add');
  47
+};
  48
+
  49
+//add user action
  50
+exports.add_action = function(req, res, next){
  51
+    var user_name = sanitize(req.body.user_name).trim();
  52
+    user_name = sanitize(user_name).xss();
  53
+    var password = sanitize(req.body.password).trim();
  54
+    password = sanitize(password).xss();
  55
+    var email = sanitize(req.body.email).trim();
  56
+    email = sanitize(email).xss();
  57
+    if(user_name == '' || email == '' || password == ''){
  58
+    	res.render('user_add', {error: '信息不能为空', user_name: user_name, email: email});
  59
+    	return;
  60
+    }
  61
+    //验证用户名
  62
+    try{
  63
+    	check(user_name, '用户名只能使用字母和数字').isAlphanumeric();
  64
+    }catch(e){
  65
+    	res.render('user_add',{error: e.message, user_name: user_name, email: email});
  66
+    	return;
  67
+    }
  68
+    //验证电子邮箱
  69
+    try{
  70
+    	check(email, '不正确的电子邮箱').isEmail();
  71
+    }catch(e){
  72
+    	res.render('user_add',{error: e.message, user_name: user_name, email: email});
  73
+    	return;
  74
+    }
  75
+    
  76
+    User.find({'$or':[{'user_name': user_name},{'email': email}]}, function(err, userRow){
  77
+		if(err){
  78
+		    return next(err);
  79
+		}
  80
+		if(userRow.length > 0){
  81
+		    res.render('user_add', {error: '用户名或邮箱已被使用,请重新输入',user_name: user_name,email: email});
  82
+		    return;
  83
+		}
  84
+		
  85
+		password = md5(password);
  86
+		user = new User();
  87
+		user.user_name = user_name;
  88
+		user.password = password;
  89
+		user.email = email;
  90
+		user.create_time = Date.now();
  91
+		
  92
+		user.save(function(err){
  93
+			if(err) return next(err);
  94
+			
  95
+			User.findOne({'user_name': user_name}, function(err, userRow){
  96
+				if(err) return next(err);
  97
+				
  98
+				if(userRow){
  99
+					gen_session(userRow, res, req);
  100
+					
  101
+					res.redirect('/');
  102
+				}else{
  103
+					res.render('login',{error: '没有此用户,或已被删除'});
  104
+	    			return;
  105
+				}
  106
+			});
  107
+		});
  108
+    });
  109
+
  110
+}
2  models/index.js
@@ -13,5 +13,7 @@ mongoose.connect(config.db, function(err){
13 13
 
14 14
 //models
15 15
 require('./cookbook');
  16
+require('./user');
16 17
 
17 18
 exports.cookbook = mongoose.model('cookbook');
  19
+exports.User = mongoose.model('User');
22  models/user.js
... ...
@@ -0,0 +1,22 @@
  1
+/*
  2
+ * user.js 用户管理数据库
  3
+ * author: moskito
  4
+ * create time: 2012-07-14
  5
+ * */
  6
+
  7
+var mongoose = require('mongoose');
  8
+var Schema = mongoose.Schema;
  9
+var ObjectId = Schema.ObjectId;
  10
+
  11
+var userSchema = new Schema({
  12
+    user_name : {type : String},
  13
+    password : {type : String},
  14
+    create_time : {type : Date, default : Date.now},
  15
+    update_at : {type: Date, default : Date.now},
  16
+    email : {type : String},
  17
+    edit_id: {type : ObjectId},
  18
+    reply_count: {type : Number, default : 0},
  19
+    article_count: {type : Number, default : 0}
  20
+});
  21
+
  22
+mongoose.model('User',userSchema);
1  node_modules/validator/.npmignore
... ...
@@ -0,0 +1 @@
  1
+.DS_Store
20  node_modules/validator/LICENSE
... ...
@@ -0,0 +1,20 @@
  1
+Copyright (c) 2010 Chris O'Hara <cohara87@gmail.com>
  2
+
  3
+Permission is hereby granted, free of charge, to any person obtaining
  4
+a copy of this software and associated documentation files (the
  5
+"Software"), to deal in the Software without restriction, including
  6
+without limitation the rights to use, copy, modify, merge, publish,
  7
+distribute, sublicense, and/or sell copies of the Software, and to
  8
+permit persons to whom the Software is furnished to do so, subject to
  9
+the following conditions:
  10
+
  11
+The above copyright notice and this permission notice shall be
  12
+included in all copies or substantial portions of the Software.
  13
+
  14
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  15
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  16
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  17
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  18
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  19
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  20
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
220  node_modules/validator/README.md
Source Rendered
... ...
@@ -0,0 +1,220 @@
  1
+**node-validator is a library of string validation, filtering and sanitization methods.**
  2
+
  3
+To install node-validator, use [npm](http://github.com/isaacs/npm):
  4
+
  5
+```bash
  6
+$ npm install validator
  7
+```
  8
+
  9
+To use the library in the browser, include `validator-min.js`
  10
+
  11
+## Example
  12
+
  13
+```javascript
  14
+var check = require('validator').check,
  15
+    sanitize = require('validator').sanitize
  16
+
  17
+//Validate
  18
+check('test@email.com').len(6, 64).isEmail();        //Methods are chainable
  19
+check('abc').isInt();                                //Throws 'Invalid integer'
  20
+check('abc', 'Please enter a number').isInt();       //Throws 'Please enter a number'
  21
+check('abcdefghijklmnopzrtsuvqxyz').is(/^[a-z]+$/);
  22
+
  23
+//Sanitize / Filter
  24
+var int = sanitize('0123').toInt();                  //123
  25
+var bool = sanitize('true').toBoolean();             //true
  26
+var str = sanitize(' \s\t\r hello \n').trim();       //'hello'
  27
+var str = sanitize('aaaaaaaaab').ltrim('a');         //'b'
  28
+var str = sanitize(large_input_str).xss();
  29
+var str = sanitize('&lt;a&gt;').entityDecode();      //'<a>'
  30
+```
  31
+
  32
+## Web development
  33
+
  34
+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.
  35
+
  36
+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.
  37
+
  38
+Example `http://localhost:8080/?zip=12345&foo=1&textarea=large_string`
  39
+
  40
+```javascript
  41
+get('/', function (req, res) {
  42
+    req.onValidationError(function (msg) {
  43
+        //Redirect the user with error 'msg'
  44
+    });
  45
+
  46
+    //Validate user input
  47
+    req.check('zip', 'Please enter a valid ZIP code').len(4,5).isInt();
  48
+    req.check('email', 'Please enter a valid email').len(6,64).isEmail();
  49
+    req.checkHeader('referer').contains('localhost');
  50
+
  51
+    //Sanitize user input
  52
+    req.sanitize('textarea').xss();
  53
+    req.sanitize('foo').toBoolean();
  54
+
  55
+    //etc.
  56
+});
  57
+```
  58
+
  59
+## List of validation methods
  60
+
  61
+```javascript
  62
+is()                            //Alias for regex()
  63
+not()                           //Alias for notRegex()
  64
+isEmail()
  65
+isUrl()                         //Accepts http, https, ftp
  66
+isIP()
  67
+isAlpha()
  68
+isAlphanumeric()
  69
+isNumeric()
  70
+isInt()                         //isNumeric accepts zero padded numbers, e.g. '001', isInt doesn't
  71
+isLowercase()
  72
+isUppercase()
  73
+isDecimal()
  74
+isFloat()                       //Alias for isDecimal
  75
+notNull()
  76
+isNull()
  77
+notEmpty()                      //i.e. not just whitespace
  78
+equals(equals)
  79
+contains(str)
  80
+notContains(str)
  81
+regex(pattern, modifiers)       //Usage: regex(/[a-z]/i) or regex('[a-z]','i')
  82
+notRegex(pattern, modifiers)
  83
+len(min, max)                   //max is optional
  84
+isUUID(version)                 //Version can be 3 or 4 or empty, see http://en.wikipedia.org/wiki/Universally_unique_identifier
  85
+isDate()                        //Uses Date.parse() - regex is probably a better choice
  86
+isAfter(date)                   //Argument is optional and defaults to today
  87
+isBefore(date)                  //Argument is optional and defaults to today
  88
+isIn(options)                   //Accepts an array or string
  89
+notIn(options)
  90
+max(val)
  91
+min(val)
  92
+isArray()
  93
+isCreditCard()                  //Will work against Visa, MasterCard, American Express, Discover, Diners Club, and JCB card numbering formats
  94
+```
  95
+
  96
+## List of sanitization / filter methods
  97
+
  98
+```javascript
  99
+trim(chars)                     //Trim optional `chars`, default is to trim whitespace (\r\n\t\s)
  100
+ltrim(chars)
  101
+rtrim(chars)
  102
+ifNull(replace)
  103
+toFloat()
  104
+toInt()
  105
+toBoolean()                     //True unless str = '0', 'false', or str.length == 0
  106
+toBooleanStrict()               //False unless str = '1' or 'true'
  107
+entityDecode()                  //Decode HTML entities
  108
+entityEncode()
  109
+xss()                           //Remove common XSS attack vectors from text (default)
  110
+xss(true)                       //Remove common XSS attack vectors from images
  111
+```
  112
+
  113
+## Extending the library
  114
+
  115
+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
  116
+
  117
+```javascript
  118
+var Validator = require('validator').Validator;
  119
+Validator.prototype.contains = function(str) {
  120
+    if (!~this.str.indexOf(str)) {
  121
+        this.error(this.msg || this.str + ' does not contain ' + str);
  122
+    }
  123
+    return this; //Allow method chaining
  124
+}
  125
+```
  126
+
  127
+When adding to the Filter (sanitize) prototype, use `this.str` to access the string and `this.modify(new_str)` to update it
  128
+
  129
+```javascript
  130
+var Filter = require('filter').Filter;
  131
+Filter.prototype.removeNumbers = function() {
  132
+    this.modify(this.str.replace(/[0-9]+/g, ''));
  133
+    return this.str;
  134
+}
  135
+```
  136
+
  137
+## Error handling
  138
+
  139
+By default, the validation methods throw an exception when a check fails
  140
+
  141
+```javascript
  142
+try {
  143
+    check('abc').notNull().isInt()
  144
+} catch (e) {
  145
+    console.log(e.message); //Invalid integer
  146
+}
  147
+```
  148
+
  149
+To set a custom error message, set the second param of `check()`
  150
+
  151
+```javascript
  152
+try {
  153
+    check('abc', 'Please enter a valid integer').notNull().isInt()
  154
+} catch (e) {
  155
+    console.log(e.message); //Please enter a valid integer
  156
+}
  157
+```
  158
+
  159
+To attach a custom error handler, set the `error` method of the validator instance
  160
+
  161
+```javascript
  162
+var Validator = require('validator').Validator;
  163
+var v = new Validator();
  164
+v.error = function(msg) {
  165
+    console.log('Fail');
  166
+}
  167
+v.check('abc').isInt(); //'Fail'
  168
+```
  169
+
  170
+You might want to collect errors instead of throwing each time
  171
+
  172
+```javascript
  173
+Validator.prototype.error = function (msg) {
  174
+    this._errors.push(msg);
  175
+}
  176
+
  177
+Validator.prototype.getErrors = function () {
  178
+    return this._errors;
  179
+}
  180
+
  181
+var validator = new Validator();
  182
+
  183
+validator.check('abc').isEmail();
  184
+validator.check('hello').len(10,30);
  185
+
  186
+var errors = validator.getErrors(); // ['Invalid email', 'String is too small']
  187
+```
  188
+
  189
+## Contributors
  190
+
  191
+- [PING](https://github.com/PlNG) - Fixed entity encoding
  192
+- [Dan VerWeire](https://github.com/wankdanker) - Modified the behaviour of the error handler
  193
+- [ctavan](https://github.com/ctavan) - Added isArray and isUUID()
  194
+- [foxbunny](https://github.com/foxbunny) - Added min(), max(), isAfter(), isBefore(), and improved isDate()
  195
+- [oris](https://github.com/orls) - Addded in()
  196
+
  197
+## LICENSE
  198
+
  199
+(MIT License)
  200
+
  201
+Copyright (c) 2010 Chris O'Hara <cohara87@gmail.com>
  202
+
  203
+Permission is hereby granted, free of charge, to any person obtaining
  204
+a copy of this software and associated documentation files (the
  205
+"Software"), to deal in the Software without restriction, including
  206
+without limitation the rights to use, copy, modify, merge, publish,
  207
+distribute, sublicense, and/or sell copies of the Software, and to
  208
+permit persons to whom the Software is furnished to do so, subject to
  209
+the following conditions:
  210
+
  211
+The above copyright notice and this permission notice shall be
  212
+included in all copies or substantial portions of the Software.
  213
+
  214
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  215
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  216
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  217
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  218
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  219
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  220
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15  node_modules/validator/index.html
... ...
@@ -0,0 +1,15 @@
  1
+<html>
  2
+<head>
  3
+<script type="text/javascript" src="validator-min.js"></script>
  4
+</head>
  5
+<body>
  6
+<script type="text/javascript">
  7
+try {
  8
+    check('ad>dfds@fsdfsd.com').isEmail();
  9
+} catch (e) {
  10
+    console.log('ok');
  11
+}
  12
+console.log(sanitize('aaa<a>bbb</a>').xss());
  13
+</script>
  14
+</body>
  15
+</html>
1  node_modules/validator/index.js
... ...
@@ -0,0 +1 @@
  1
+exports = module.exports = require('./lib');
291  node_modules/validator/lib/entities.js
... ...
@@ -0,0 +1,291 @@
  1
+var entities = {
  2
+    '&nbsp;': '\u00a0',
  3
+    '&iexcl;': '\u00a1',
  4
+    '&cent;': '\u00a2',
  5
+    '&pound;': '\u00a3',
  6
+    '&curren;': '\u20ac',
  7
+    '&yen;': '\u00a5',
  8
+    '&brvbar;': '\u0160',
  9
+    '&sect;': '\u00a7',
  10
+    '&uml;': '\u0161',
  11
+    '&copy;': '\u00a9',
  12
+    '&ordf;': '\u00aa',
  13
+    '&laquo;': '\u00ab',
  14
+    '&not;': '\u00ac',
  15
+    '&shy;': '\u00ad',
  16
+    '&reg;': '\u00ae',
  17
+    '&macr;': '\u00af',
  18
+    '&deg;': '\u00b0',
  19
+    '&plusmn;': '\u00b1',
  20
+    '&sup2;': '\u00b2',
  21
+    '&sup3;': '\u00b3',
  22
+    '&acute;': '\u017d',
  23
+    '&micro;': '\u00b5',
  24
+    '&para;': '\u00b6',
  25
+    '&middot;': '\u00b7',
  26
+    '&cedil;': '\u017e',
  27
+    '&sup1;': '\u00b9',
  28
+    '&ordm;': '\u00ba',
  29
+    '&raquo;': '\u00bb',
  30
+    '&frac14;': '\u0152',
  31
+    '&frac12;': '\u0153',
  32
+    '&frac34;': '\u0178',
  33
+    '&iquest;': '\u00bf',
  34
+    '&Agrave;': '\u00c0',
  35
+    '&Aacute;': '\u00c1',
  36
+    '&Acirc;': '\u00c2',
  37
+    '&Atilde;': '\u00c3',
  38
+    '&Auml;': '\u00c4',
  39
+    '&Aring;': '\u00c5',
  40
+    '&AElig;': '\u00c6',
  41
+    '&Ccedil;': '\u00c7',
  42
+    '&Egrave;': '\u00c8',
  43
+    '&Eacute;': '\u00c9',
  44
+    '&Ecirc;': '\u00ca',
  45
+    '&Euml;': '\u00cb',
  46
+    '&Igrave;': '\u00cc',
  47
+    '&Iacute;': '\u00cd',
  48
+    '&Icirc;': '\u00ce',
  49
+    '&Iuml;': '\u00cf',
  50
+    '&ETH;': '\u00d0',
  51
+    '&Ntilde;': '\u00d1',
  52
+    '&Ograve;': '\u00d2',
  53
+    '&Oacute;': '\u00d3',
  54
+    '&Ocirc;': '\u00d4',
  55
+    '&Otilde;': '\u00d5',
  56
+    '&Ouml;': '\u00d6',
  57
+    '&times;': '\u00d7',
  58
+    '&Oslash;': '\u00d8',
  59
+    '&Ugrave;': '\u00d9',
  60
+    '&Uacute;': '\u00da',
  61
+    '&Ucirc;': '\u00db',
  62
+    '&Uuml;': '\u00dc',
  63
+    '&Yacute;': '\u00dd',
  64
+    '&THORN;': '\u00de',
  65
+    '&szlig;': '\u00df',
  66
+    '&agrave;': '\u00e0',
  67
+    '&aacute;': '\u00e1',
  68
+    '&acirc;': '\u00e2',
  69
+    '&atilde;': '\u00e3',
  70
+    '&auml;': '\u00e4',
  71
+    '&aring;': '\u00e5',
  72
+    '&aelig;': '\u00e6',
  73
+    '&ccedil;': '\u00e7',
  74
+    '&egrave;': '\u00e8',
  75
+    '&eacute;': '\u00e9',
  76
+    '&ecirc;': '\u00ea',
  77
+    '&euml;': '\u00eb',
  78
+    '&igrave;': '\u00ec',
  79
+    '&iacute;': '\u00ed',
  80
+    '&icirc;': '\u00ee',
  81
+    '&iuml;': '\u00ef',
  82
+    '&eth;': '\u00f0',
  83
+    '&ntilde;': '\u00f1',
  84
+    '&ograve;': '\u00f2',
  85
+    '&oacute;': '\u00f3',
  86
+    '&ocirc;': '\u00f4',
  87
+    '&otilde;': '\u00f5',
  88
+    '&ouml;': '\u00f6',
  89
+    '&divide;': '\u00f7',
  90
+    '&oslash;': '\u00f8',
  91
+    '&ugrave;': '\u00f9',
  92
+    '&uacute;': '\u00fa',
  93
+    '&ucirc;': '\u00fb',
  94
+    '&uuml;': '\u00fc',
  95
+    '&yacute;': '\u00fd',
  96
+    '&thorn;': '\u00fe',
  97
+    '&yuml;': '\u00ff',
  98
+    '&quot;': '\u0022',
  99
+    '&lt;': '\u003c',
  100
+    '&gt;': '\u003e',
  101
+    '&apos;': '\u0027',
  102
+    '&minus;': '\u2212',
  103
+    '&circ;': '\u02c6',
  104
+    '&tilde;': '\u02dc',
  105
+    '&Scaron;': '\u0160',
  106
+    '&lsaquo;': '\u2039',
  107
+    '&OElig;': '\u0152',
  108
+    '&lsquo;': '\u2018',
  109
+    '&rsquo;': '\u2019',
  110
+    '&ldquo;': '\u201c',
  111
+    '&rdquo;': '\u201d',
  112
+    '&bull;': '\u2022',
  113
+    '&ndash;': '\u2013',
  114
+    '&mdash;': '\u2014',
  115
+    '&trade;': '\u2122',
  116
+    '&scaron;': '\u0161',
  117
+    '&rsaquo;': '\u203a',
  118
+    '&oelig;': '\u0153',
  119
+    '&Yuml;': '\u0178',
  120
+    '&fnof;': '\u0192',
  121
+    '&Alpha;': '\u0391',
  122
+    '&Beta;': '\u0392',
  123
+    '&Gamma;': '\u0393',
  124
+    '&Delta;': '\u0394',
  125
+    '&Epsilon;': '\u0395',
  126
+    '&Zeta;': '\u0396',
  127
+    '&Eta;': '\u0397',
  128
+    '&Theta;': '\u0398',
  129
+    '&Iota;': '\u0399',
  130
+    '&Kappa;': '\u039a',
  131
+    '&Lambda;': '\u039b',
  132
+    '&Mu;': '\u039c',
  133
+    '&Nu;': '\u039d',
  134
+    '&Xi;': '\u039e',
  135
+    '&Omicron;': '\u039f',
  136
+    '&Pi;': '\u03a0',
  137
+    '&Rho;': '\u03a1',
  138
+    '&Sigma;': '\u03a3',
  139
+    '&Tau;': '\u03a4',
  140
+    '&Upsilon;': '\u03a5',
  141
+    '&Phi;': '\u03a6',
  142
+    '&Chi;': '\u03a7',
  143
+    '&Psi;': '\u03a8',
  144
+    '&Omega;': '\u03a9',
  145
+    '&alpha;': '\u03b1',
  146
+    '&beta;': '\u03b2',
  147
+    '&gamma;': '\u03b3',
  148
+    '&delta;': '\u03b4',
  149
+    '&epsilon;': '\u03b5',
  150
+    '&zeta;': '\u03b6',
  151
+    '&eta;': '\u03b7',
  152
+    '&theta;': '\u03b8',
  153
+    '&iota;': '\u03b9',
  154
+    '&kappa;': '\u03ba',
  155
+    '&lambda;': '\u03bb',
  156
+    '&mu;': '\u03bc',
  157
+    '&nu;': '\u03bd',
  158
+    '&xi;': '\u03be',
  159
+    '&omicron;': '\u03bf',
  160
+    '&pi;': '\u03c0',
  161
+    '&rho;': '\u03c1',
  162
+    '&sigmaf;': '\u03c2',
  163
+    '&sigma;': '\u03c3',
  164
+    '&tau;': '\u03c4',
  165
+    '&upsilon;': '\u03c5',
  166
+    '&phi;': '\u03c6',
  167
+    '&chi;': '\u03c7',
  168
+    '&psi;': '\u03c8',
  169
+    '&omega;': '\u03c9',
  170
+    '&thetasym;': '\u03d1',
  171
+    '&upsih;': '\u03d2',
  172
+    '&piv;': '\u03d6',
  173
+    '&ensp;': '\u2002',
  174
+    '&emsp;': '\u2003',
  175
+    '&thinsp;': '\u2009',
  176
+    '&zwnj;': '\u200c',
  177
+    '&zwj;': '\u200d',
  178
+    '&lrm;': '\u200e',
  179
+    '&rlm;': '\u200f',
  180
+    '&sbquo;': '\u201a',
  181
+    '&bdquo;': '\u201e',
  182
+    '&dagger;': '\u2020',
  183
+    '&Dagger;': '\u2021',
  184
+    '&hellip;': '\u2026',
  185
+    '&permil;': '\u2030',
  186
+    '&prime;': '\u2032',
  187
+    '&Prime;': '\u2033',
  188
+    '&oline;': '\u203e',
  189
+    '&frasl;': '\u2044',
  190
+    '&euro;': '\u20ac',
  191
+    '&image;': '\u2111',
  192
+    '&weierp;': '\u2118',
  193
+    '&real;': '\u211c',
  194
+    '&alefsym;': '\u2135',
  195
+    '&larr;': '\u2190',
  196
+    '&uarr;': '\u2191',
  197
+    '&rarr;': '\u2192',
  198
+    '&darr;': '\u2193',
  199
+    '&harr;': '\u2194',
  200
+    '&crarr;': '\u21b5',
  201
+    '&lArr;': '\u21d0',
  202
+    '&uArr;': '\u21d1',
  203
+    '&rArr;': '\u21d2',
  204
+    '&dArr;': '\u21d3',
  205
+    '&hArr;': '\u21d4',
  206
+    '&forall;': '\u2200',
  207
+    '&part;': '\u2202',
  208
+    '&exist;': '\u2203',
  209
+    '&empty;': '\u2205',
  210
+    '&nabla;': '\u2207',
  211
+    '&isin;': '\u2208',
  212
+    '&notin;': '\u2209',
  213
+    '&ni;': '\u220b',
  214
+    '&prod;': '\u220f',
  215
+    '&sum;': '\u2211',
  216
+    '&lowast;': '\u2217',
  217
+    '&radic;': '\u221a',
  218
+    '&prop;': '\u221d',
  219
+    '&infin;': '\u221e',
  220
+    '&ang;': '\u2220',
  221
+    '&and;': '\u2227',
  222
+    '&or;': '\u2228',
  223
+    '&cap;': '\u2229',
  224
+    '&cup;': '\u222a',
  225
+    '&int;': '\u222b',
  226
+    '&there4;': '\u2234',
  227
+    '&sim;': '\u223c',
  228
+    '&cong;': '\u2245',
  229
+    '&asymp;': '\u2248',
  230
+    '&ne;': '\u2260',
  231
+    '&equiv;': '\u2261',
  232
+    '&le;': '\u2264',
  233
+    '&ge;': '\u2265',
  234
+    '&sub;': '\u2282',
  235
+    '&sup;': '\u2283',
  236
+    '&nsub;': '\u2284',
  237
+    '&sube;': '\u2286',
  238
+    '&supe;': '\u2287',
  239
+    '&oplus;': '\u2295',
  240
+    '&otimes;': '\u2297',
  241
+    '&perp;': '\u22a5',
  242
+    '&sdot;': '\u22c5',
  243
+    '&lceil;': '\u2308',
  244
+    '&rceil;': '\u2309',
  245
+    '&lfloor;': '\u230a',
  246
+    '&rfloor;': '\u230b',
  247
+    '&lang;': '\u2329',
  248
+    '&rang;': '\u232a',
  249
+    '&loz;': '\u25ca',
  250
+    '&spades;': '\u2660',
  251
+    '&clubs;': '\u2663',
  252
+    '&hearts;': '\u2665',
  253
+    '&diams;': '\u2666'
  254
+};
  255
+
  256
+exports.decode = function (str) {
  257
+    if (!~str.indexOf('&')) return str;
  258
+
  259
+    //Decode literal entities
  260
+    for (var i in entities) {
  261
+        str = str.replace(new RegExp(i, 'g'), entities[i]);
  262
+    }
  263
+
  264
+    //Decode hex entities
  265
+    str = str.replace(/&#x(0*[0-9a-f]{2,5});?/gi, function (m, code) {
  266
+        return String.fromCharCode(parseInt(+code, 16));
  267
+    });
  268
+
  269
+    //Decode numeric entities
  270
+    str = str.replace(/&#([0-9]{2,4});?/gi, function (m, code) {
  271
+        return String.fromCharCode(+code);
  272
+    });
  273
+
  274
+    str = str.replace(/&amp;/g, '&');
  275
+
  276
+    return str;
  277
+}
  278
+
  279
+exports.encode = function (str) {
  280
+    str = str.replace(/&/g, '&amp;');
  281
+
  282
+    //IE doesn't accept &apos;
  283
+    str = str.replace(/'/g, '&#39;');
  284
+
  285
+    //Encode literal entities
  286
+    for (var i in entities) {
  287
+        str = str.replace(new RegExp(entities[i], 'g'), i);
  288
+    }
  289
+
  290
+    return str;
  291
+}
102  node_modules/validator/lib/filter.js
... ...
@@ -0,0 +1,102 @@
  1
+var entities = require('./entities');
  2
+var xss = require('./xss');
  3
+
  4
+var Filter = exports.Filter = function() {}
  5
+
  6
+var whitespace = '\\r\\n\\t\\s';
  7
+
  8
+Filter.prototype.modify = function(str) {
  9
+    this.str = str;
  10
+}
  11
+
  12
+Filter.prototype.wrap = function (str) {
  13
+    return str;
  14
+}
  15
+
  16
+Filter.prototype.value = function () {
  17
+    return this.str;
  18
+}
  19
+
  20
+Filter.prototype.chain = function () {
  21
+    this.wrap = function () { return this };
  22
+    return this;
  23
+}
  24
+
  25
+//Create some aliases - may help code readability
  26
+Filter.prototype.convert = Filter.prototype.sanitize = function(str) {
  27
+    this.str = str;
  28
+    return this;
  29
+}
  30
+
  31
+Filter.prototype.xss = function(is_image) {
  32
+    this.modify(xss.clean(this.str, is_image));
  33
+    return this.wrap(this.str);
  34
+}
  35
+
  36
+Filter.prototype.entityDecode = function() {
  37
+    this.modify(entities.decode(this.str));
  38
+    return this.wrap(this.str);
  39
+}
  40
+
  41
+Filter.prototype.entityEncode = function() {
  42
+    this.modify(entities.encode(this.str));
  43
+    return this.wrap(this.str);
  44
+}
  45
+
  46
+Filter.prototype.ltrim = function(chars) {
  47
+    chars = chars || whitespace;
  48
+    this.modify(this.str.replace(new RegExp('^['+chars+']+', 'g'), ''));
  49
+    return this.wrap(this.str);
  50
+}
  51
+
  52
+Filter.prototype.rtrim = function(chars) {
  53
+    chars = chars || whitespace;
  54
+    this.modify(this.str.replace(new RegExp('['+chars+']+$', 'g'), ''));
  55
+    return this.wrap(this.str);
  56
+}
  57
+
  58
+Filter.prototype.trim = function(chars) {
  59
+    chars = chars || whitespace;
  60
+    this.modify(this.str.replace(new RegExp('^['+chars+']+|['+chars+']+$', 'g'), ''));
  61
+    return this.wrap(this.str);
  62
+}
  63
+
  64
+Filter.prototype.ifNull = function(replace) {
  65
+    if (!this.str || this.str === '') {
  66
+        this.modify(replace);
  67
+    }
  68
+    return this.wrap(this.str);
  69
+}
  70
+
  71
+Filter.prototype.toFloat = function() {
  72
+    this.modify(parseFloat(this.str));
  73
+    return this.wrap(this.str);
  74
+}
  75
+
  76
+Filter.prototype.toInt = function(radix) {
  77
+    radix = radix || 10;
  78
+    this.modify(parseInt(this.str, radix));
  79
+    return this.wrap(this.str);
  80
+}
  81
+
  82
+//Any strings with length > 0 (except for '0' and 'false') are considered true,
  83
+//all other strings are false
  84
+Filter.prototype.toBoolean = function() {
  85
+    if (!this.str || this.str == '0' || this.str == 'false' || this.str == '') {
  86
+        this.modify(false);
  87
+    } else {
  88
+        this.modify(true);
  89
+    }
  90
+    return this.wrap(this.str);
  91
+}
  92
+
  93
+//String must be equal to '1' or 'true' to be considered true, all other strings
  94
+//are false
  95
+Filter.prototype.toBooleanStrict = function() {
  96
+    if (this.str == '1' || this.str == 'true') {
  97
+        this.modify(true);
  98
+    } else {
  99
+        this.modify(false);
  100
+    }
  101
+    return this.wrap(this.str);
  102
+}
15  node_modules/validator/lib/index.js
... ...
@@ -0,0 +1,15 @@
  1
+exports.Validator = require('./validator').Validator;
  2
+exports.Filter = require('./filter').Filter;
  3
+
  4
+exports.entities = require('./entities');
  5
+
  6
+//Quick access methods
  7
+exports.sanitize = exports.convert = function(str) {
  8
+    var filter = new exports.Filter();
  9
+    return filter.sanitize(str);
  10
+}
  11
+
  12
+exports.check = exports.validate = exports.assert = function(str, fail_msg) {
  13
+    var validator = new exports.Validator();
  14
+    return validator.check(str, fail_msg);
  15
+}
314  node_modules/validator/lib/validator.js
... ...
@@ -0,0 +1,314 @@
  1
+var net = require('net');
  2
+
  3
+var Validator = exports.Validator = function() {}
  4
+
  5
+Validator.prototype.check = function(str, fail_msg) {
  6
+    this.str = (str == null || (isNaN(str) && str.length == undefined)) ? '' : str;
  7
+    // Convert numbers to strings but keep arrays/objects
  8
+    if (typeof this.str == 'number') {
  9
+      this.str += '';
  10
+    }
  11
+    this.msg = fail_msg;
  12
+    this._errors = this._errors || [];
  13
+    return this;
  14
+}
  15
+
  16
+// Helper function to avoid duplication of code
  17
+function toDateTime(date) {
  18
+    if (date instanceof Date) {
  19
+      return date;
  20
+    }
  21
+    var intDate = Date.parse(date);
  22
+    if (isNaN(intDate)) {
  23
+        return null;
  24
+    } 
  25
+    return new Date(intDate);
  26
+}
  27
+
  28
+// Convert to date without the time component
  29
+function toDate(date) {
  30
+    if (!(date instanceof Date)) {
  31
+      date = toDateTime(date);
  32
+    }
  33
+    if (!date) {
  34
+      return null;
  35
+    }
  36
+    date.setHours(0);
  37
+    date.setMinutes(0);
  38
+    date.setSeconds(0);
  39
+    date.setMilliseconds(0);
  40
+    return date;
  41
+}
  42
+
  43
+//Create some aliases - may help code readability
  44
+Validator.prototype.validate = Validator.prototype.check;
  45
+Validator.prototype.assert = Validator.prototype.check;
  46
+
  47
+Validator.prototype.error = function(msg) {
  48
+    throw new Error(msg);
  49
+    return this;
  50
+}
  51
+
  52
+Validator.prototype.isEmail = function() {
  53
+    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])\]))$/)) {
  54
+       return this.error(this.msg || 'Invalid email');
  55
+    }
  56
+    return this;
  57
+}
  58
+
  59
+Validator.prototype.isUrl = function() {
  60
+    if (!this.str.match(/^(?:(?:ht|f)tp(?:s?)\:\/\/|~\/|\/)?(?:\w+:\w+@)?((?:(?:[-\w\d{1-3}]+\.)+(?:com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|edu|co\.uk|ac\.uk|it|fr|tv|museum|asia|local|travel|[a-z]{2}))|((\b25[0-5]\b|\b[2][0-4][0-9]\b|\b[0-1]?[0-9]?[0-9]\b)(\.(\b25[0-5]\b|\b[2][0-4][0-9]\b|\b[0-1]?[0-9]?[0-9]\b)){3}))(?::[\d]{1,5})?(?:(?:(?:\/(?:[-\w~!$+|.,=]|%[a-f\d]{2})+)+|\/)+|\?|#)?(?:(?:\?(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=?(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)(?:&(?:[-\w~!$+|.,*:]|%[a-f\d{2}])+=?(?:[-\w~!$+|.,*:=]|%[a-f\d]{2})*)*)*(?:#(?:[-\w~!$ |\/.,*:;=]|%[a-f\d]{2})*)?$/i)) {
  61
+       return this.error(this.msg || 'Invalid URL');
  62
+    }
  63
+    return this;
  64
+}
  65
+
  66
+Validator.prototype.isIP = function() {
  67
+    //net.isIP is in node >= 0.3.0
  68
+    if (typeof net.isIP === 'function') {
  69
+        if (net.isIP(this.str) === 0) {
  70
+           return this.error(this.msg || 'Invalid IP');
  71
+        }
  72
+    } else {
  73
+        if (!this.str.match(/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/)) {
  74
+           return this.error(this.msg || 'Invalid IP');
  75
+        }
  76
+    }
  77
+    return this;
  78
+}
  79
+
  80
+Validator.prototype.isAlpha = function() {
  81
+    if (!this.str.match(/^[a-zA-Z]+$/)) {
  82
+       return this.error(this.msg || 'Invalid characters');
  83
+    }
  84
+    return this;
  85
+}
  86
+
  87
+Validator.prototype.isAlphanumeric = function() {
  88
+    if (!this.str.match(/^[a-zA-Z0-9]+$/)) {
  89
+       return this.error(this.msg || 'Invalid characters');
  90
+    }
  91
+    return this;
  92
+}
  93
+
  94
+Validator.prototype.isNumeric = function() {
  95
+    if (!this.str.match(/^-?[0-9]+$/)) {
  96
+       return this.error(this.msg || 'Invalid number');
  97
+    }
  98
+    return this;
  99
+}
  100
+
  101
+Validator.prototype.isLowercase = function() {
  102
+    if (!this.str.match(/^[a-z0-9]+$/)) {
  103
+       return this.error(this.msg || 'Invalid characters');
  104
+    }
  105
+    return this;
  106
+}
  107
+
  108
+Validator.prototype.isUppercase = function() {
  109
+    if (!this.str.match(/^[A-Z0-9]+$/)) {
  110
+       return this.error(this.msg || 'Invalid characters');
  111
+    }
  112
+    return this;
  113
+}
  114
+
  115
+Validator.prototype.isInt = function() {
  116
+    if (!this.str.match(/^(?:-?(?:[0-9][0-9]*)(?:\.?0+)?)$/)) {
  117
+       return this.error(this.msg || 'Invalid integer');
  118
+    }
  119
+    return this;
  120
+}
  121
+
  122
+Validator.prototype.isDecimal = function() {
  123
+    if (this.str === '' || !this.str.match(/^(?:-?(?:[0-9]+))?(?:\.[0-9]*)?(?:[eE][\+\-]?(?:[0-9]+))?$/)) {
  124
+       return this.error(this.msg || 'Invalid decimal');
  125
+    }
  126
+    return this;
  127
+}
  128
+
  129
+Validator.prototype.isFloat = function() {
  130
+    return this.isDecimal();
  131
+}
  132
+
  133
+Validator.prototype.isDivisibleBy = function(n) {
  134
+    if (parseFloat(this.str) % n) {
  135
+      return this.error(this.msg || 'Not divisible by ' + n);
  136
+    }
  137
+    return this;
  138
+}
  139
+
  140
+Validator.prototype.notNull = function() {
  141
+    if (this.str === '') {
  142
+       return this.error(this.msg || 'Invalid characters');
  143
+    }
  144
+    return this;
  145
+}
  146
+
  147
+Validator.prototype.isNull = function() {
  148
+    if (this.str !== '') {
  149
+       return this.error(this.msg || 'Invalid characters');
  150
+    }
  151
+    return this;
  152
+}
  153
+
  154
+Validator.prototype.notEmpty = function() {
  155
+    if (this.str.match(/^[\s\t\r\n]*$/)) {
  156
+       return this.error(this.msg || 'String is empty');
  157
+    }
  158
+    return this;
  159
+}
  160
+
  161
+Validator.prototype.equals = function(equals) {
  162
+    if (this.str != equals) {
  163
+       return this.error(this.msg || 'Not equal');
  164
+    }
  165
+    return this;
  166
+}
  167
+
  168
+Validator.prototype.contains = function(str) {
  169
+    if (this.str.indexOf(str) === -1) {
  170
+       return this.error(this.msg || 'Invalid characters');
  171
+    }
  172
+    return this;
  173
+}
  174
+
  175
+Validator.prototype.notContains = function(str) {
  176
+    if (this.str.indexOf(str) >= 0) {
  177
+       return this.error(this.msg || 'Invalid characters');
  178
+    }
  179
+    return this;
  180
+}
  181
+
  182
+Validator.prototype.regex = Validator.prototype.is = function(pattern, modifiers) {
  183
+    if (typeof pattern !== 'function') {
  184
+        pattern = new RegExp(pattern, modifiers);
  185
+    }
  186
+    if (! this.str.match(pattern)) {
  187
+       return this.error(this.msg || 'Invalid characters');
  188
+    }
  189
+    return this;
  190
+}
  191
+
  192
+Validator.prototype.notRegex = Validator.prototype.not = function(pattern, modifiers) {
  193
+    if (typeof pattern !== 'function') {
  194
+        pattern = new RegExp(pattern, modifiers);
  195
+    }
  196
+    if (this.str.match(pattern)) {
  197
+       return this.error(this.msg || 'Invalid characters');
  198
+    }
  199
+    return this;
  200
+}
  201
+
  202
+Validator.prototype.len = function(min, max) {
  203
+    if (this.str.length < min) {
  204
+       return this.error(this.msg || 'String is too small');
  205
+    }
  206
+    if (typeof max !== undefined && this.str.length > max) {
  207
+       return this.error(this.msg || 'String is too large');
  208
+    }
  209
+    return this;
  210
+}
  211
+
  212
+//Thanks to github.com/sreuter for the idea.
  213
+Validator.prototype.isUUID = function(version) {
  214
+    if (version == 3 || version == 'v3') {
  215
+        pattern = /[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i;
  216
+    } else if (version == 4 || version == 'v4') {
  217
+        pattern = /[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i;
  218
+    } else {
  219
+        pattern = /[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i;
  220
+    }
  221
+    if (!this.str.match(pattern)) {
  222
+       return this.error(this.msg || 'Not a UUID');
  223
+    }
  224
+    return this;
  225
+}
  226
+
  227
+Validator.prototype.isDate = function() {
  228
+    var intDate = Date.parse(this.str);
  229
+    if (isNaN(intDate)) { 
  230
+        return this.error(this.msg || 'Not a date'); 
  231
+    }
  232
+    return this;
  233
+}
  234
+
  235
+Validator.prototype.isAfter = function(date) {
  236
+    date = date || new Date();
  237
+    var origDate = toDate(this.str);
  238
+    var compDate = toDate(date);
  239
+
  240
+    if (origDate && compDate && origDate < compDate) {
  241
+        return this.error(this.msg || 'Invalid date');
  242
+    }
  243
+    
  244
+    return this;
  245
+}
  246
+
  247
+Validator.prototype.isBefore = function(date) {
  248
+    date = date || new Date();
  249
+    var origDate = toDate(this.str);
  250
+    var compDate = toDate(date);
  251
+
  252