Roo/bootstrap/SecurePass.js
[roojs1] / Roo / bootstrap / SecurePass.js
1 /*
2  * - LGPL
3  *
4  * Input
5  * 
6  */
7
8 /**
9  * @class Roo.bootstrap.SecurePass
10  * @extends Roo.bootstrap.Input
11  * Bootstrap SecurePass class
12  *
13  * 
14  * @constructor
15  * Create a new SecurePass
16  * @param {Object} config The config object
17  */
18  
19 Roo.bootstrap.SecurePass = function (config) {
20     // these go here, so the translation tool can replace them..
21     this.errors = {
22         PwdEmpty: "Please type a password, and then retype it to confirm.",
23         PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
24         PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
25         PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
26         IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
27         FNInPwd: "Your password can't contain your first name. Please type a different password.",
28         LNInPwd: "Your password can't contain your last name. Please type a different password.",
29         TooWeak: "Your password is Too Weak."
30     },
31     this.meterLabel = "Password strength:";
32     this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
33     this.meterClass = ["roo-password-meter-tooweak", 
34                        "roo-password-meter-weak", 
35                        "roo-password-meter-medium", 
36                        "roo-password-meter-strong", 
37                        "roo-password-meter-grey"],    
38     Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
39 }
40
41 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
42     /**
43      * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
44      * {
45      *  PwdEmpty: "Please type a password, and then retype it to confirm.",
46      *  PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
47      *  PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
48      *  PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
49      *  IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
50      *  FNInPwd: "Your password can't contain your first name. Please type a different password.",
51      *  LNInPwd: "Your password can't contain your last name. Please type a different password."
52      * })
53      */
54     // private
55     
56     meterWidth: 300,
57     errorMsg :'',    
58     errors: {},
59     imageRoot: '/',
60     /**
61      * @cfg {String/Object} Label for the strength meter (defaults to
62      * 'Password strength:')
63      */
64     // private
65     meterLabel: '',
66     /**
67      * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
68      * ['Weak', 'Medium', 'Strong'])
69      */
70     // private    
71     pwdStrengths: [],    
72     // private
73     strength: 0,
74     // private
75     _lastPwd: null,
76     // private
77     kCapitalLetter: 0,
78     kSmallLetter: 1,
79     kDigit: 2,
80     kPunctuation: 3,
81     
82     insecure: false,
83     // private
84     initEvents: function () {
85         Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
86
87         if (this.el.is('input[type=password]') && Roo.isSafari) {
88             this.el.on('keydown', this.SafariOnKeyDown, this);
89         }
90
91         this.el.on('keyup', this.checkStrength, this, {buffer: 50});
92     },
93     // private
94     onRender: function (ct, position) {
95         Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
96         this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
97         this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
98
99         this.trigger.createChild({
100                    cn: [
101                     {
102                     //id: 'PwdMeter',
103                     tag: 'div',
104                     cls: 'roo-password-meter-grey col-xs-12',
105                     style: {
106                         //width: 0,
107                         //width: this.meterWidth + 'px'                                                
108                         }
109                     },
110                     {                            
111                          cls: 'roo-password-meter-text'                          
112                     }
113                 ]            
114         });
115
116         /*
117         this.trigger.createChild({
118             tag: 'div',
119             cls: 'roo-password-meter-container col-xs-12',
120             style: {               
121                 //width: this.meterWidth + 'px'
122             },
123             cn: {
124                 tag: 'div',
125                 cls: 'roo-password-meter-grey',
126                 style: {
127                     //width: this.meterWidth + 'px'                                        
128                 },
129                 cn: [
130                     {
131                     //id: 'PwdMeter',
132                     tag: 'div',
133                     cls: 'roo-password-meter-grey col-xs-12',
134                     style: {
135                         //width: 0,
136                         //width: this.meterWidth + 'px'                                                
137                         }
138                     },
139                     {                            
140                          cls: 'roo-password-meter-text'                          
141                     }
142                 ]                
143             }
144         });
145         */
146         if (this.hideTrigger) {
147             this.trigger.setDisplayed(false);
148         }
149         this.setSize(this.width || '', this.height || '');
150     },
151     // private
152     onDestroy: function () {
153         if (this.trigger) {
154             this.trigger.removeAllListeners();
155             this.trigger.remove();
156         }
157         if (this.wrap) {
158             this.wrap.remove();
159         }
160         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
161     },
162     // private
163     checkStrength: function () {
164         var pwd = this.inputEl().getValue();
165         if (pwd == this._lastPwd) {
166             return;
167         }
168
169         var strength;
170         if (this.ClientSideStrongPassword(pwd)) {
171             strength = 3;
172         } else if (this.ClientSideMediumPassword(pwd)) {
173             strength = 2;
174         } else if (this.ClientSideWeakPassword(pwd)) {
175             strength = 1;
176         } else {
177             strength = 0;
178         }
179         
180         console.log('strength1: ' + strength);
181         
182         //var pm = this.trigger.child('div/div/div').dom;
183         var pm = this.trigger.child('div/div');
184         pm.removeClass(this.meterClass);
185         pm.addClass(this.meterClass[strength]);
186                 
187         
188         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
189                 
190         pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
191         
192         this._lastPwd = pwd;
193     },
194     reset: function () {
195         Roo.bootstrap.SecurePass.superclass.reset.call(this);
196         
197         this._lastPwd = '';
198         
199         var pm = this.trigger.child('div/div');
200         pm.removeClass(this.meterClass);
201         pm.addClass('roo-password-meter-grey');        
202         
203         
204         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
205         
206         pt.innerHTML = '';
207         this.inputEl().dom.type='password';
208     },
209     // private
210     validateValue: function (value) {
211         
212         if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
213             return false;
214         }
215         if (value.length == 0) {
216             if (this.allowBlank) {
217                 this.clearInvalid();
218                 return true;
219             }
220
221             this.markInvalid(this.errors.PwdEmpty);
222             this.errorMsg = this.errors.PwdEmpty;
223             return false;
224         }
225         
226         if(this.insecure){
227             return true;
228         }
229         
230         if ('[\x21-\x7e]*'.match(value)) {
231             this.markInvalid(this.errors.PwdBadChar);
232             this.errorMsg = this.errors.PwdBadChar;
233             return false;
234         }
235         if (value.length < 6) {
236             this.markInvalid(this.errors.PwdShort);
237             this.errorMsg = this.errors.PwdShort;
238             return false;
239         }
240         if (value.length > 16) {
241             this.markInvalid(this.errors.PwdLong);
242             this.errorMsg = this.errors.PwdLong;
243             return false;
244         }
245         var strength;
246         if (this.ClientSideStrongPassword(value)) {
247             strength = 3;
248         } else if (this.ClientSideMediumPassword(value)) {
249             strength = 2;
250         } else if (this.ClientSideWeakPassword(value)) {
251             strength = 1;
252         } else {
253             strength = 0;
254         }
255
256         
257         if (strength < 2) {
258             //this.markInvalid(this.errors.TooWeak);
259             this.errorMsg = this.errors.TooWeak;
260             //return false;
261         }
262         
263         
264         console.log('strength2: ' + strength);
265         
266         //var pm = this.trigger.child('div/div/div').dom;
267         
268         var pm = this.trigger.child('div/div');
269         pm.removeClass(this.meterClass);
270         pm.addClass(this.meterClass[strength]);
271                 
272         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
273                 
274         pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
275         
276         this.errorMsg = ''; 
277         return true;
278     },
279     // private
280     CharacterSetChecks: function (type) {
281         this.type = type;
282         this.fResult = false;
283     },
284     // private
285     isctype: function (character, type) {
286         switch (type) { //why needed break after return in js ? very odd bug
287             case this.kCapitalLetter:
288                 if (character >= 'A' && character <= 'Z') {
289                     return true;
290                 }
291                 break;
292             case this.kSmallLetter:
293                 if (character >= 'a' && character <= 'z') {
294                     return true;
295                 }
296                 break;
297             case this.kDigit:
298                 if (character >= '0' && character <= '9') {
299                     return true;
300                 }
301                 break;
302             case this.kPunctuation:
303                 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
304                     return true;
305                 }
306                 break;
307             default:
308                 return false;
309         }
310
311     },
312     // private
313     IsLongEnough: function (pwd, size) {
314         return !(pwd == null || isNaN(size) || pwd.length < size);
315     },
316     // private
317     SpansEnoughCharacterSets: function (word, nb) {
318         if (!this.IsLongEnough(word, nb))
319         {
320             return false;
321         }
322
323         var characterSetChecks = new Array(
324                 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
325                 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation));
326         for (var index = 0; index < word.length; ++index) {
327             for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
328                 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
329                     characterSetChecks[nCharSet].fResult = true;
330                     break;
331                 }
332             }
333         }
334
335         var nCharSets = 0;
336         for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
337             if (characterSetChecks[nCharSet].fResult) {
338                 ++nCharSets;
339             }
340         }
341
342         if (nCharSets < nb) {
343             return false;
344         }
345         return true;
346     },
347     // private
348     ClientSideStrongPassword: function (pwd) {
349         return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
350     },
351     // private
352     ClientSideMediumPassword: function (pwd) {
353         return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
354     },
355     // private
356     ClientSideWeakPassword: function (pwd) {
357         return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
358     }
359           
360 })