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