PageSourceSearch

https://subs.springwise.com/JavaScript/core/classes/password.strength.class.js

js springwise.com collected 2026-09-24 08:51:29 UTC 8,369 bytes, 348 lines download raw bytes

1/*
2---
3
4requires: [AbacusAD, MooTools, Class, Class.Extras, DomReady, Element, Element.Event]
5
6provides: [AbacusAD.PasswordStrength]
7
8...
9*/
10
11(function($, window, document){
12
13	$(window).addEvent('domready', function() {
14		$$('.passwordMeter').each(function(element) {
15			new StrongPass(element, {
16				minChar: 8,
17				label: 'Strength',
18				passStrengthZen: 'div.passwordStrength.alignRight',
19				passbarClassZen: 'div.indicator',
20				passbarHintZen: 'p',
21				checkBannedPasswords: false
22			});
23		});
24	});
25
26	(function() {
27		'use strict';
28
29		var StrongPass = new Class({
30
31			Implements: [Options, Events],
32
33			options: {
34				minChar: 6, // too short while less than this
35				passIndex: 2, // Weak
36				checkBannedPasswords: true,  // prompts when match is found against bannedPassword, set false to disable
37				// output verdicts, colours and bar %
38				label: 'Password strength: ',
39				verdicts: [
40					' ',
41					'Very weak',
42					'Weak',
43					'Good',
44					'Strong',
45					'Very strong'
46				],
47				colors: [
48					'#F3F3F3',
49					'#B71F38',
50					'#FF8000',
51					'#FFD044',
52					'#008C5C',
53					'#205793'
54				],
55				width: [
56					'',
57					'26px',
58					'57px',
59					'88px',
60					'119px',
61					'150px'
62				],
63				klasses: [
64					'default',
65					'very-weak',
66					'weak',
67					'good',
68					'strong',
69					'very-strong'
70				],
71				// tweak scores here
72				scores: [
73					10,
74					15,
75					25,
76					45
77				],
78				// when in banned list, verdict is:
79				bannedPass: 'Not allowed',
80				// styles
81				passStrengthZen: 'div.pass-container',
82				passbarClassZen: 'div.pass-bar', // css controls
83				passbarHintZen: 'div.pass-hint',
84				passbarHintZenPlacement: 'top',
85				// output
86				render: true, // it can just report for your own implementation
87				injectTarget: null,
88				injectPlacement: 'after'
89			},
90
91			bannedPasswords: [
92				// see study here: http://smrt.io/JlNfrH
93				'123456',
94				'12345',
95				'123456789',
96				'password',
97				'iloveyou',
98				'princess',
99				'rockyou',
100				'1234567',
101				'12345678',
102				'abc123',
103				'nicole',
104				'daniel',
105				'babygirl',
106				'monkey',
107				'jessica',
108				'lovely',
109				'michael',
110				'ashley',
111				'654321',
112				'qwerty',
113				'password1',
114				'welcome',
115				'welcome1',
116				'password2',
117				'password01',
118				'password3',
119				'p@ssw0rd',
120				'passw0rd',
121				'password4',
122				'password123',
123				'summer09',
124				'password6',
125				'password7',
126				'password9',
127				'password8',
128				'welcome2',
129				'welcome01',
130				'winter12',
131				'spring2012',
132				'summer12',
133				'summer2012'
134			],
135
136			/**
137			 * @constructor
138			 * @param {DOMElement} element Base element to attach to
139			 * @param {Object} options* Options to merge in / attach events from
140			 * @fires StrongPass#ready
141			 * @returns SrongPass
142			 */
143			initialize: function(element, options) {
144				this.setOptions(options);
145				this.element = document.id(element);
146				if(this.element.getNext('div.passwordStrength')) {
147					this.element.getNext('div.passwordStrength').dispose();
148				}
149				this.options.render && this.createBox();
150				this.attachEvents();
151				this.fireEvent('ready');
152			},
153
154			/**
155			 * @description Attaches events and saves a reference
156			 * @returns {StrongPass}
157			 */
158			attachEvents: function() {
159				var self = this;
160				// only attach events once so freshen
161				this.eventObj && this.element.removeEvents(this.eventObj);
162				this.element.addEvents(this.eventObj = {
163					keyup: this.runPassword.bind(this),
164					focus: function() {
165						self.showStrengthPass(this.value);
166					},
167					blur: function() {
168						this.getSiblings(self.options.passStrengthZen)[0].setStyle('display', 'none');
169					}
170				});
171
172				return this;
173			},
174
175			/**
176			 * @description Attaches pass elements.
177			 * @returns {StrongPass}
178			 */
179			createBox: function() {
180				//todo: should be templated
181				var width = this.element.getSize().x,
182					o = this.options;
183
184				this.stbox = new Element(o.passStrengthZen);
185
186				this.stdbar = new Element(o.passbarClassZen, {
187					'html': '<div></div>'
188				}).inject(this.stbox);
189
190				this.txtbox = new Element(o.passbarHintZen, {
191					'html': '<span></span><strong></strong>'
192				}).inject(this.stbox, this.options.passbarHintZenPlacement);
193				this.stbox.inject((document.id(o.injectTarget) || this.element), o.injectPlacement);
194
195				return this;
196			},
197
198			/**
199			 * @description Shows pass strength element.
200			 * @returns {StrongPass}
201			 */
202			showStrengthPass: function(field) {
203				if(field.length > 0) {
204					this.element.getSiblings(this.options.passStrengthZen)[0].setStyle('display', 'block');
205				}
206				return this;
207			},
208
209			/**
210			 * @description Runs a password check on the keyup event
211			 * @param {Object} event*
212			 * @param {String} password* Optionally pass a string or go to element getter
213			 * @fires StrongPass#fail StrongPass#pass
214			 * @returns {StrongPass}
215			 */
216			runPassword: function(event, password) {
217				password = password || this.element.get('value');
218
219				this.showStrengthPass(password);
220
221				var score = this.checkPassword(password),
222					index = 0,
223					o = this.options,
224					s = Array.clone(o.scores),
225					verdict;
226
227				var setscore = function() {
228					if (score < 0 && score > -199) {
229						index = 0;
230					}
231					else {
232						s.push(score);
233						s.sort(function(a, b) {
234							return a - b;
235						});
236						index = s.indexOf(score) + 1;
237					}
238
239					verdict = o.verdicts[index] || o.verdicts.getLast();
240				}
241
242				if(this.options.checkBannedPasswords) {
243					if (Array.indexOf(this.bannedPasswords, password.toLowerCase()) !== -1) {
244						this.fireEvent('banned', password);
245						verdict = o.bannedPass;
246					}
247					else {
248						setscore();
249					}
250				} else {
251					setscore();
252				}
253
254				if (o.render) {
255					this.txtbox.getElement('span').set('text', o.label);
256					this.txtbox.getElement('strong').set('text', verdict);
257					this.stdbar.getElement('div').setStyles({
258						'width': o.width[index] || o.width.getLast(),
259						'background-color': o.colors[index] || o.colors.getLast()
260					});
261
262					this.stdbar
263						.removeClass(o.klasses[0])
264						.removeClass(o.klasses[1])
265						.removeClass(o.klasses[2])
266						.removeClass(o.klasses[3])
267						.removeClass(o.klasses[4])
268						.addClass(o.klasses[index]);
269				}
270
271				/**
272				 * @event StrongPass#fail,StrongPass#pass
273				 */
274				return this.fireEvent(['fail', 'pass'][+(this.passed = o.verdicts.indexOf(verdict) >= o.passIndex)], [index, verdict, password]);
275			},
276
277			/**
278			 * @type {Array}
279			 * @description The collection of regex checks and how much they affect the scoring
280			 */
281			checks: [
282				/* alphaLower */ {
283					re: /[a-z]/,
284					score: 1
285				},
286				/* alphaUpper */ {
287					re: /[A-Z]/,
288					score: 5
289				},
290				/* mixture of upper and lowercase */ {
291					re: /([a-z].*[A-Z])|([A-Z].*[a-z])/,
292					score: 2
293				},
294				/* threeNumbers */ {
295					re: /(.*[0-9].*[0-9].*[0-9])/,
296					score: 7
297				},
298				/* special chars */ {
299					re: /.[!@#$%^&*?_~]/,
300					score: 5
301				},
302				/* multiple special chars */ {
303					re: /(.*[!@#$%^&*?_~].*[!@#$%^&*?_~])/,
304					score: 7
305				},
306				/* all together now, does it look nice? */ {
307					re: /([a-zA-Z0-9].*[!@#$%^&*?_~])|([!@#$%^&*?_~].*[a-zA-Z0-9])/,
308					score: 3
309				},
310				/* password of a single char sucks */ {
311					re: /(.)\1+$/,
312					score: 2
313				}
314			],
315
316			checkPassword: function(pass) {
317				var score = 0,
318					minChar = this.options.minChar,
319					len = pass.length,
320					diff = len - minChar;
321
322				(diff < 0 && (score -= 100)) || (diff >= 5 && (score += 18)) || (diff >= 3 && (score += 12)) || (diff === 2 && (score += 6));
323
324				Array.each(this.checks, function(check) {
325					pass.match(check.re) && (score += check.score);
326				});
327
328				// bonus for length per char
329				score && (score += len);
330				return score;
331			}
332		});
333
334		if (typeof define === 'function' && define.amd) {
335			// return an AMD module
336			define(function(){
337				return StrongPass;
338			});
339		}
340		else {
341			// exports to global object
342			this.StrongPass = StrongPass;
343		}
344
345		// change to any object / ns
346	}.call(this));
347
348})(document.id, window, document);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.