@@ -12,7 +12,7 @@ var UserSchema = new Schema({
1212    type : String , 
1313    default : 'user' 
1414  } , 
15-   hashedPassword : String , 
15+   password : String , 
1616  provider : String , 
1717  salt : String < %  if  ( filters . oauth )  {  % > , < %  if  ( filters . facebookAuth )  {  % > 
1818  facebook : { } , < %  }  % > < %  if  ( filters . twitterAuth )  {  % > 
@@ -24,16 +24,6 @@ var UserSchema = new Schema({
2424/** 
2525 * Virtuals 
2626 */ 
27- UserSchema 
28-   . virtual ( 'password' ) 
29-   . set ( function ( password )  { 
30-     this . _password  =  password ; 
31-     this . salt  =  this . makeSalt ( ) ; 
32-     this . hashedPassword  =  this . encryptPassword ( password ) ; 
33-   } ) 
34-   . get ( function ( )  { 
35-     return  this . _password ; 
36-   } ) ; 
3727
3828// Public profile information 
3929UserSchema 
@@ -69,10 +59,10 @@ UserSchema
6959
7060// Validate empty password 
7161UserSchema 
72-   . path ( 'hashedPassword ' ) 
73-   . validate ( function ( hashedPassword )  { < %  if  ( filters . oauth )  {  % > 
62+   . path ( 'password ' ) 
63+   . validate ( function ( password )  { < %  if  ( filters . oauth )  {  % > 
7464    if  ( authTypes . indexOf ( this . provider )  !==  - 1 )  return  true ; < %  }  % > 
75-     return  hashedPassword . length ; 
65+     return  password . length ; 
7666  } ,  'Password cannot be blank' ) ; 
7767
7868// Validate email is not taken 
@@ -99,12 +89,26 @@ var validatePresenceOf = function(value) {
9989 */ 
10090UserSchema 
10191  . pre ( 'save' ,  function ( next )  { 
102-     if  ( ! this . isNew )  return  next ( ) ; 
103- 
104-     if  ( ! validatePresenceOf ( this . hashedPassword ) < %  if  ( filters . oauth )  {  % >  &&  authTypes . indexOf ( this . provider )  ===  - 1 < %  }  % > ) 
105-       next ( new  Error ( 'Invalid password' ) ) ; 
106-     else 
92+     // Handle new/update passwords 
93+     if  ( this . password )  { 
94+       if  ( ! validatePresenceOf ( this . password ) < %  if  ( filters . oauth )  {  % >  &&  authTypes . indexOf ( this . provider )  ===  - 1 < %  }  % > ) 
95+         next ( new  Error ( 'Invalid password' ) ) ; 
96+ 
97+       // Make salt with a callback 
98+       var  _this  =  this ; 
99+       this . makeSalt ( function ( saltErr ,  salt )  { 
100+         if  ( saltErr )  next ( saltErr ) ; 
101+         _this . salt  =  salt ; 
102+         // Async hash 
103+         _this . encryptPassword ( _this . password ,  function ( encryptErr ,  hashedPassword )  { 
104+           if  ( encryptErr )  next ( encryptErr ) ; 
105+           _this . password  =  hashedPassword ; 
106+           next ( ) ; 
107+         } ) ; 
108+       } ) ; 
109+     }  else  { 
107110      next ( ) ; 
111+     } 
108112  } ) ; 
109113
110114/** 
@@ -115,34 +119,82 @@ UserSchema.methods = {
115119   * Authenticate - check if the passwords are the same 
116120   * 
117121   * @param  {String } plainText 
122+    * @callback  {callback } Optional callback 
118123   * @return  {Boolean } 
119124   * @api  public 
120125   */ 
121-   authenticate : function ( plainText )  { 
122-     return  this . encryptPassword ( plainText )  ===  this . hashedPassword ; 
126+   authenticate : function ( password ,  callback )  { 
127+     if  ( ! callback ) 
128+       return  this . password  ===  this . encryptPassword ( password ) ; 
129+ 
130+     var  _this  =  this ; 
131+     this . encryptPassword ( password ,  function ( err ,  pwdGen )  { 
132+       if  ( err )  callback ( err ) ; 
133+ 
134+       if  ( _this . password  ===  pwdGen )  { 
135+         callback ( null ,  true ) ; 
136+       }  else  { 
137+         callback ( null ,  false ) ; 
138+       } 
139+     } ) ; 
123140  } , 
124141
125142  /** 
126143   * Make salt 
127144   * 
145+    * @param  {Number } byteSize Optional salt byte size, default to 16 
146+    * @callback  {callback } Optional callback 
128147   * @return  {String } 
129148   * @api  public 
130149   */ 
131-   makeSalt : function ( )  { 
132-     return  crypto . randomBytes ( 16 ) . toString ( 'base64' ) ; 
150+   makeSalt : function ( byteSize ,  callback )  { 
151+     var  defaultByteSize  =  16 ; 
152+ 
153+     if  ( typeof  arguments [ 0 ]  ===  'function' )  { 
154+       callback  =  arguments [ 0 ] ; 
155+       byteSize  =  defaultByteSize ; 
156+     }  else  if  ( typeof  arguments [ 1 ]  ===  'function' )  { 
157+       callback  =  arguments [ 1 ] ; 
158+     } 
159+ 
160+     if  ( ! byteSize )  { 
161+       byteSize  =  defaultByteSize ; 
162+     } 
163+ 
164+     if  ( ! callback )  { 
165+       return  crypto . randomBytes ( byteSize ) . toString ( 'base64' ) ; 
166+     } 
167+ 
168+     return  crypto . randomBytes ( byteSize ,  function ( err ,  salt )  { 
169+       if  ( err )  callback ( err ) ; 
170+       return  callback ( null ,  salt . toString ( 'base64' ) ) ; 
171+     } ) ; 
133172  } , 
134173
135174  /** 
136175   * Encrypt password 
137176   * 
138177   * @param  {String } password 
178+    * @callback  {callback } Optional callback 
139179   * @return  {String } 
140180   * @api  public 
141181   */ 
142-   encryptPassword : function ( password )  { 
143-     if  ( ! password  ||  ! this . salt )  return  '' ; 
182+   encryptPassword : function ( password ,  callback )  { 
183+     if  ( ! password  ||  ! this . salt )  { 
184+       return  null ; 
185+     } 
186+ 
187+     var  defaultIterations  =  10000 ; 
188+     var  defaultKeyLength  =  64 ; 
144189    var  salt  =  new  Buffer ( this . salt ,  'base64' ) ; 
145-     return  crypto . pbkdf2Sync ( password ,  salt ,  10000 ,  64 ) . toString ( 'base64' ) ; 
190+ 
191+     if  ( ! callback ) 
192+       return  crypto . pbkdf2Sync ( password ,  salt ,  defaultIterations ,  defaultKeyLength ) . toString ( 'base64' ) ; 
193+ 
194+     return  crypto . pbkdf2 ( password ,  salt ,  defaultIterations ,  defaultKeyLength ,  function ( err ,  key )  { 
195+       if  ( err )  callback ( err ) ; 
196+       return  callback ( null ,  key . toString ( 'base64' ) ) ; 
197+     } ) ; 
146198  } 
147199} ; 
148200
0 commit comments