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     meterClass: [],
72     pwdStrengths: [],    
73     // private
74     strength: 0,
75     // private
76     _lastPwd: null,
77     // private
78     kCapitalLetter: 0,
79     kSmallLetter: 1,
80     kDigit: 2,
81     kPunctuation: 3,
82     
83     insecure: false,
84     // private
85     initEvents: function () {
86         Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
87
88         if (this.el.is('input[type=password]') && Roo.isSafari) {
89             this.el.on('keydown', this.SafariOnKeyDown, this);
90         }
91
92         this.el.on('keyup', this.checkStrength, this, {buffer: 50});
93     },
94     // private
95     onRender: function (ct, position) {
96         Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
97         this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
98         this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
99
100         this.trigger.createChild({
101             tag: 'div',
102             cls: 'roo-password-meter-container col-xs-12',
103             style: {               
104                 //width: this.meterWidth + 'px'
105             },
106             cn: {
107                 tag: 'div',
108                 cls: 'roo-password-meter-grey',
109                 style: {
110                     //width: this.meterWidth + 'px'                                        
111                 },
112                 cn: [
113                     {
114                     //id: 'PwdMeter',
115                     tag: 'div',
116                     cls: 'roo-password-meter-grey col-xs-12',
117                     style: {
118                         //width: 0,
119                         //width: this.meterWidth + 'px'                                                
120                         }
121                     },
122                     {                            
123                          cls: 'roo-password-meter-text'                          
124                     }
125                 ]                
126             }
127         });
128         if (this.hideTrigger) {
129             this.trigger.setDisplayed(false);
130         }
131         this.setSize(this.width || '', this.height || '');
132     },
133     // private
134     onDestroy: function () {
135         if (this.trigger) {
136             this.trigger.removeAllListeners();
137             this.trigger.remove();
138         }
139         if (this.wrap) {
140             this.wrap.remove();
141         }
142         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
143     },
144     // private
145     checkStrength: function () {
146         var pwd = this.inputEl().getValue();
147         if (pwd == this._lastPwd) {
148             return;
149         }
150
151         var strength;
152         if (this.ClientSideStrongPassword(pwd)) {
153             strength = 3;
154         } else if (this.ClientSideMediumPassword(pwd)) {
155             strength = 2;
156         } else if (this.ClientSideWeakPassword(pwd)) {
157             strength = 1;
158         } else {
159             strength = 0;
160         }
161         
162         console.log('strength1: ' + strength);
163         
164         //var pm = this.trigger.child('div/div/div').dom;
165         var pm = this.trigger.child('div/div/div');
166         pm.removeClass(this.meterClass);
167         pm.addClass(this.meterClass[strength]);
168                 
169         //pm.style.width = (this.meterWidth / 3) * strength + 'px';
170                
171         
172         var pt = this.trigger.child('/div/div/').child('>*[class=roo-password-meter-text]').dom;        
173                 
174         pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
175         
176         this._lastPwd = pwd;
177     },
178     reset: function () {
179         Roo.bootstrap.SecurePass.superclass.reset.call(this);
180         
181         this._lastPwd = '';
182         //var pm = this.trigger.child('div/div/div').dom;
183         //pm.style.width = 0;
184         var pm = this.trigger.child('div/div/div');
185         pm.removeClass(this.meterClass);
186         pm.addClass('roo-password-meter-grey');        
187         
188         
189         var pt = this.trigger.child('/div/div/').child('>*[class=roo-password-meter-text]').dom;        
190                 
191         //pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
192         
193         pt.innerHTML = '';
194         this.inputEl().dom.type='password';
195     },
196     // private
197     validateValue: function (value) {
198         
199         if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
200             return false;
201         }
202         if (value.length == 0) {
203             if (this.allowBlank) {
204                 this.clearInvalid();
205                 return true;
206             }
207
208             this.markInvalid(this.errors.PwdEmpty);
209             this.errorMsg = this.errors.PwdEmpty;
210             return false;
211         }
212         
213         if(this.insecure){
214             return true;
215         }
216         
217         if ('[\x21-\x7e]*'.match(value)) {
218             this.markInvalid(this.errors.PwdBadChar);
219             this.errorMsg = this.errors.PwdBadChar;
220             return false;
221         }
222         if (value.length < 6) {
223             this.markInvalid(this.errors.PwdShort);
224             this.errorMsg = this.errors.PwdShort;
225             return false;
226         }
227         if (value.length > 16) {
228             this.markInvalid(this.errors.PwdLong);
229             this.errorMsg = this.errors.PwdLong;
230             return false;
231         }
232         var strength;
233         if (this.ClientSideStrongPassword(value)) {
234             strength = 3;
235         } else if (this.ClientSideMediumPassword(value)) {
236             strength = 2;
237         } else if (this.ClientSideWeakPassword(value)) {
238             strength = 1;
239         } else {
240             strength = 0;
241         }
242
243         
244         if (strength < 2) {
245             //this.markInvalid(this.errors.TooWeak);
246             this.errorMsg = this.errors.TooWeak;
247             //return false;
248         }
249         
250         
251         console.log('strength2: ' + strength);
252         
253         //var pm = this.trigger.child('div/div/div').dom;
254         
255         var pm = this.trigger.child('div/div/div');
256         pm.removeClass(this.meterClass);
257         pm.addClass(this.meterClass[strength]);
258                 
259         var pt = this.trigger.child('/div/div/').child('>*[class=roo-password-meter-text]').dom;        
260                 
261         pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
262         
263         this.errorMsg = ''; 
264         return true;
265     },
266     // private
267     CharacterSetChecks: function (type) {
268         this.type = type;
269         this.fResult = false;
270     },
271     // private
272     isctype: function (character, type) {
273         switch (type) { //why needed break after return in js ? very odd bug
274             case this.kCapitalLetter:
275                 if (character >= 'A' && character <= 'Z') {
276                     return true;
277                 }
278                 break;
279             case this.kSmallLetter:
280                 if (character >= 'a' && character <= 'z') {
281                     return true;
282                 }
283                 break;
284             case this.kDigit:
285                 if (character >= '0' && character <= '9') {
286                     return true;
287                 }
288                 break;
289             case this.kPunctuation:
290                 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
291                     return true;
292                 }
293                 break;
294             default:
295                 return false;
296         }
297
298     },
299     // private
300     IsLongEnough: function (pwd, size) {
301         return !(pwd == null || isNaN(size) || pwd.length < size);
302     },
303     // private
304     SpansEnoughCharacterSets: function (word, nb) {
305         if (!this.IsLongEnough(word, nb))
306         {
307             return false;
308         }
309
310         var characterSetChecks = new Array(
311                 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
312                 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation));
313         for (var index = 0; index < word.length; ++index) {
314             for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
315                 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
316                     characterSetChecks[nCharSet].fResult = true;
317                     break;
318                 }
319             }
320         }
321
322         var nCharSets = 0;
323         for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
324             if (characterSetChecks[nCharSet].fResult) {
325                 ++nCharSets;
326             }
327         }
328
329         if (nCharSets < nb) {
330             return false;
331         }
332         return true;
333     },
334     // private
335     ClientSideStrongPassword: function (pwd) {
336         return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
337     },
338     // private
339     ClientSideMediumPassword: function (pwd) {
340         return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
341     },
342     // private
343     ClientSideWeakPassword: function (pwd) {
344         return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
345     }
346           
347 })