@fr0st/ui-passwordstrength 2.0.7 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +0 -0
- package/README.md +334 -37
- package/dist/frost-ui-passwordstrength.esm.js +395 -0
- package/dist/frost-ui-passwordstrength.esm.js.map +1 -0
- package/dist/frost-ui-passwordstrength.esm.min.js +2 -0
- package/dist/frost-ui-passwordstrength.esm.min.js.map +1 -0
- package/dist/frost-ui-passwordstrength.js +428 -341
- package/dist/frost-ui-passwordstrength.js.map +1 -1
- package/dist/frost-ui-passwordstrength.min.js +2 -1
- package/dist/frost-ui-passwordstrength.min.js.map +1 -1
- package/package.json +57 -25
- package/src/{wrapper.js → browser.js} +0 -0
- package/src/index.js +0 -55
- package/src/password-strength.js +227 -24
- package/src/strength.js +273 -0
- package/src/prototype/events.js +0 -10
- package/src/prototype/helpers.js +0 -33
- package/src/prototype/render.js +0 -29
- package/src/static/helpers.js +0 -162
|
@@ -1,341 +1,428 @@
|
|
|
1
|
-
(function
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
})(this,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
1
|
+
(function(global, factory) {
|
|
2
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@fr0st/ui'), require('@fr0st/query')) :
|
|
3
|
+
typeof define === 'function' && define.amd ? define(['exports', '@fr0st/ui', '@fr0st/query'], factory) :
|
|
4
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.UI = global.UI || {}), global.UI,global.fQuery));
|
|
5
|
+
})(this, function(exports, _fr0st_ui, _fr0st_query) {
|
|
6
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
7
|
+
//#region \0rolldown/runtime.js
|
|
8
|
+
var __create = Object.create;
|
|
9
|
+
var __defProp = Object.defineProperty;
|
|
10
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
11
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
12
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
13
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
14
|
+
var __copyProps = (to, from, except, desc) => {
|
|
15
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
16
|
+
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
17
|
+
key = keys[i];
|
|
18
|
+
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
19
|
+
__defProp(to, key, {
|
|
20
|
+
get: ((k) => from[k]).bind(null, key),
|
|
21
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return to;
|
|
27
|
+
};
|
|
28
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
|
|
29
|
+
value: mod,
|
|
30
|
+
enumerable: true
|
|
31
|
+
}) : target, mod));
|
|
32
|
+
|
|
33
|
+
//#endregion
|
|
34
|
+
_fr0st_query = __toESM(_fr0st_query, 1);
|
|
35
|
+
|
|
36
|
+
//#region src/strength.js
|
|
37
|
+
var characterTypes = [
|
|
38
|
+
{
|
|
39
|
+
pattern: /\p{Ll}/u,
|
|
40
|
+
type: "lower"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
pattern: /\p{Lu}/u,
|
|
44
|
+
type: "upper"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
pattern: /\p{N}/u,
|
|
48
|
+
type: "number"
|
|
49
|
+
}
|
|
50
|
+
];
|
|
51
|
+
var keyboardSequences = [
|
|
52
|
+
"1234567890",
|
|
53
|
+
"qwertyuiop",
|
|
54
|
+
"asdfghjkl",
|
|
55
|
+
"zxcvbnm"
|
|
56
|
+
].flatMap((row) => [row, Array.from(row).reverse().join("")]);
|
|
57
|
+
var leetCharacters = {
|
|
58
|
+
"$": "s",
|
|
59
|
+
"0": "o",
|
|
60
|
+
"3": "e",
|
|
61
|
+
"4": "a",
|
|
62
|
+
"5": "s",
|
|
63
|
+
"7": "t",
|
|
64
|
+
"@": "a"
|
|
65
|
+
};
|
|
66
|
+
var lengthBands = [
|
|
67
|
+
{
|
|
68
|
+
end: 5,
|
|
69
|
+
max: 19,
|
|
70
|
+
min: 1,
|
|
71
|
+
start: 1
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
end: 8,
|
|
75
|
+
max: 39,
|
|
76
|
+
min: 20,
|
|
77
|
+
start: 6
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
end: 11,
|
|
81
|
+
max: 59,
|
|
82
|
+
min: 40,
|
|
83
|
+
start: 9
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
end: 15,
|
|
87
|
+
max: 79,
|
|
88
|
+
min: 60,
|
|
89
|
+
start: 12
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
end: 24,
|
|
93
|
+
max: 100,
|
|
94
|
+
min: 80,
|
|
95
|
+
start: 16
|
|
96
|
+
}
|
|
97
|
+
];
|
|
98
|
+
/**
|
|
99
|
+
* Gets the type of a password character.
|
|
100
|
+
* @param {string} character The character.
|
|
101
|
+
* @returns {string} The character type.
|
|
102
|
+
*/
|
|
103
|
+
var getCharacterType = (character) => characterTypes.find(({ pattern }) => pattern.test(character))?.type || "symbol";
|
|
104
|
+
/**
|
|
105
|
+
* Gets a length-based password strength.
|
|
106
|
+
* @param {string[]} characters The password characters.
|
|
107
|
+
* @returns {number} The password strength.
|
|
108
|
+
*/
|
|
109
|
+
var getLengthStrength = (characters) => {
|
|
110
|
+
const band = lengthBands.find(({ end }) => characters.length <= end) || lengthBands.at(-1);
|
|
111
|
+
const score = Math.round(_fr0st_query.default._map(Math.min(characters.length, band.end), band.start, band.end, band.min, band.max));
|
|
112
|
+
const diversity = new Set(characters.map(getCharacterType)).size;
|
|
113
|
+
return Math.min(score + (diversity - 1) * 2, band.max);
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* Gets the smallest repeated pattern.
|
|
117
|
+
* @param {string[]} characters The password characters.
|
|
118
|
+
* @returns {string[]|null} The repeated pattern.
|
|
119
|
+
*/
|
|
120
|
+
var getRepeatedPattern = (characters) => {
|
|
121
|
+
const maxLength = Math.floor(characters.length / 2);
|
|
122
|
+
for (let length = 1; length <= maxLength; length++) if (characters.length % length === 0 && characters.every((character, index) => character === characters[index % length])) return characters.slice(0, length);
|
|
123
|
+
return null;
|
|
124
|
+
};
|
|
125
|
+
/**
|
|
126
|
+
* Normalizes common password matching.
|
|
127
|
+
* @param {string} password The password.
|
|
128
|
+
* @returns {string} The normalized password.
|
|
129
|
+
*/
|
|
130
|
+
var normalizePassword = (password) => String(password).normalize("NFKC").toLowerCase();
|
|
131
|
+
/**
|
|
132
|
+
* Normalizes common leet substitutions.
|
|
133
|
+
* @param {string} password The password.
|
|
134
|
+
* @returns {string} The normalized password.
|
|
135
|
+
*/
|
|
136
|
+
var normalizeLeet = (password) => Array.from(password, (character) => leetCharacters[character] || character).join("");
|
|
137
|
+
/**
|
|
138
|
+
* Gets normalized variants used to match common passwords.
|
|
139
|
+
* @param {string} password The normalized password.
|
|
140
|
+
* @returns {Set<string>} The password variants.
|
|
141
|
+
*/
|
|
142
|
+
var getPasswordVariants = (password) => {
|
|
143
|
+
const variants = [password, password.replace(/[^\p{L}\p{N}]/gu, normalizeLeet)].flatMap((value) => {
|
|
144
|
+
const undecorated = value.replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu, "");
|
|
145
|
+
return [undecorated, undecorated.replace(/^\d+|\d+$/g, "")];
|
|
146
|
+
});
|
|
147
|
+
return /* @__PURE__ */ new Set([
|
|
148
|
+
normalizeLeet(password),
|
|
149
|
+
...variants,
|
|
150
|
+
...variants.map(normalizeLeet)
|
|
151
|
+
]);
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* Gets the score for a common password.
|
|
155
|
+
* @param {string} password The normalized password.
|
|
156
|
+
* @param {string[]} commonPasswords The common passwords.
|
|
157
|
+
* @returns {number|null} The common-password score.
|
|
158
|
+
*/
|
|
159
|
+
var getCommonPasswordStrength = (password, commonPasswords) => {
|
|
160
|
+
const common = new Set(commonPasswords.map(normalizePassword));
|
|
161
|
+
if (common.has(password)) return 0;
|
|
162
|
+
return common.isDisjointFrom(getPasswordVariants(password)) ? null : 5;
|
|
163
|
+
};
|
|
164
|
+
/**
|
|
165
|
+
* Checks whether characters form an ascending or descending sequence.
|
|
166
|
+
* @param {string[]} characters The password characters.
|
|
167
|
+
* @returns {boolean} Whether the characters form a sequence.
|
|
168
|
+
*/
|
|
169
|
+
var isSequence = (characters) => {
|
|
170
|
+
const [first, second, third] = characters.map((character) => character.toLowerCase());
|
|
171
|
+
const type = getCharacterType(first);
|
|
172
|
+
const direction = second.codePointAt(0) - first.codePointAt(0);
|
|
173
|
+
return ["lower", "number"].includes(type) && getCharacterType(second) === type && getCharacterType(third) === type && Math.abs(direction) === 1 && third.codePointAt(0) - second.codePointAt(0) === direction;
|
|
174
|
+
};
|
|
175
|
+
/**
|
|
176
|
+
* Checks whether characters form a keyboard sequence.
|
|
177
|
+
* @param {string[]} characters The password characters.
|
|
178
|
+
* @returns {boolean} Whether the characters form a keyboard sequence.
|
|
179
|
+
*/
|
|
180
|
+
var isKeyboardSequence = (characters) => {
|
|
181
|
+
const sequence = characters.join("").toLowerCase();
|
|
182
|
+
return keyboardSequences.some((keyboardSequence) => keyboardSequence.includes(sequence));
|
|
183
|
+
};
|
|
184
|
+
/**
|
|
185
|
+
* Checks whether characters form a predictable pattern.
|
|
186
|
+
* @param {string[]} characters The password characters.
|
|
187
|
+
* @returns {boolean} Whether the characters form a predictable pattern.
|
|
188
|
+
*/
|
|
189
|
+
var isPredictable = (characters) => new Set(characters).size === 1 || isSequence(characters) || isKeyboardSequence(characters);
|
|
190
|
+
/**
|
|
191
|
+
* Gets the number of characters in predictable patterns.
|
|
192
|
+
* @param {string[]} characters The password characters.
|
|
193
|
+
* @returns {number} The number of predictable characters.
|
|
194
|
+
*/
|
|
195
|
+
var getPredictableCount = (characters) => {
|
|
196
|
+
const indices = /* @__PURE__ */ new Set();
|
|
197
|
+
for (let i = 0; i + 2 < characters.length; i++) if (isPredictable(characters.slice(i, i + 3))) {
|
|
198
|
+
indices.add(i);
|
|
199
|
+
indices.add(i + 1);
|
|
200
|
+
indices.add(i + 2);
|
|
201
|
+
}
|
|
202
|
+
return indices.size;
|
|
203
|
+
};
|
|
204
|
+
/**
|
|
205
|
+
* Calculates the strength of a password.
|
|
206
|
+
* @param {string} password The password.
|
|
207
|
+
* @param {string[]} [commonPasswords=[]] Passwords to score as very weak.
|
|
208
|
+
* @returns {number} The password strength, from 0 to 100.
|
|
209
|
+
*/
|
|
210
|
+
var getStrength = (password, commonPasswords = []) => {
|
|
211
|
+
const normalizedPassword = password.normalize("NFKC");
|
|
212
|
+
const characters = Array.from(normalizedPassword);
|
|
213
|
+
if (!characters.length) return 0;
|
|
214
|
+
const commonStrength = getCommonPasswordStrength(normalizedPassword.toLowerCase(), commonPasswords);
|
|
215
|
+
if (commonStrength !== null) return commonStrength;
|
|
216
|
+
const score = getLengthStrength(characters);
|
|
217
|
+
const repeatedPattern = getRepeatedPattern(characters);
|
|
218
|
+
if (repeatedPattern?.length === 1) return 0;
|
|
219
|
+
if (repeatedPattern) return Math.min(score, getLengthStrength(repeatedPattern), 15);
|
|
220
|
+
const predictableCount = getPredictableCount(characters);
|
|
221
|
+
return _fr0st_query.default._clamp(score - predictableCount, 0, predictableCount === characters.length ? 15 : 100);
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
//#endregion
|
|
225
|
+
//#region src/password-strength.js
|
|
226
|
+
/**
|
|
227
|
+
* @typedef {object} PasswordStrengthLevel
|
|
228
|
+
* @property {string} class The CSS class applied to the progress bar.
|
|
229
|
+
* @property {number} score The minimum score for the level.
|
|
230
|
+
* @property {string} [text] The label displayed in the progress bar.
|
|
231
|
+
*/
|
|
232
|
+
/**
|
|
233
|
+
* @callback PasswordStrengthScorer
|
|
234
|
+
* @param {string} password The password.
|
|
235
|
+
* @param {string[]} commonPasswords The common passwords.
|
|
236
|
+
* @returns {number} The password strength, from 0 to 100.
|
|
237
|
+
*/
|
|
238
|
+
/**
|
|
239
|
+
* @typedef {object} PasswordStrengthOptions
|
|
240
|
+
* @property {string[]} [commonPasswords] Passwords to score as very weak.
|
|
241
|
+
* @property {string|null} [container=null] The selector for the progress container.
|
|
242
|
+
* @property {PasswordStrengthLevel[]} [levels] The ordered password-strength levels.
|
|
243
|
+
* @property {PasswordStrengthScorer} [scorer] Calculates the password strength.
|
|
244
|
+
* @property {boolean} [striped=false] Whether to display a striped progress bar.
|
|
245
|
+
*/
|
|
246
|
+
/**
|
|
247
|
+
* Displays the strength of a password input as a progress bar.
|
|
248
|
+
* @augments {BaseComponent<PasswordStrengthOptions>}
|
|
249
|
+
*/
|
|
250
|
+
var PasswordStrength = class extends _fr0st_ui.BaseComponent {
|
|
251
|
+
static classes = {
|
|
252
|
+
progress: "progress mt-2",
|
|
253
|
+
progressBar: "progress-bar",
|
|
254
|
+
progressBarStriped: "progress-bar-striped"
|
|
255
|
+
};
|
|
256
|
+
/** @type {PasswordStrengthOptions} */
|
|
257
|
+
static defaults = {
|
|
258
|
+
commonPasswords: [
|
|
259
|
+
"123456",
|
|
260
|
+
"12345678",
|
|
261
|
+
"123456789",
|
|
262
|
+
"1234567890",
|
|
263
|
+
"000000",
|
|
264
|
+
"111111",
|
|
265
|
+
"abc123",
|
|
266
|
+
"admin",
|
|
267
|
+
"dragon",
|
|
268
|
+
"iloveyou",
|
|
269
|
+
"letmein",
|
|
270
|
+
"monkey",
|
|
271
|
+
"password",
|
|
272
|
+
"password1",
|
|
273
|
+
"password123",
|
|
274
|
+
"qwerty",
|
|
275
|
+
"qwerty123",
|
|
276
|
+
"welcome"
|
|
277
|
+
],
|
|
278
|
+
levels: [
|
|
279
|
+
{
|
|
280
|
+
score: 0,
|
|
281
|
+
class: "text-bg-danger",
|
|
282
|
+
text: "Very Weak"
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
score: 20,
|
|
286
|
+
class: "text-bg-danger",
|
|
287
|
+
text: "Weak"
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
score: 40,
|
|
291
|
+
class: "text-bg-warning",
|
|
292
|
+
text: "Normal"
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
score: 60,
|
|
296
|
+
class: "text-bg-success",
|
|
297
|
+
text: "Strong"
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
score: 80,
|
|
301
|
+
class: "text-bg-success",
|
|
302
|
+
text: "Very Strong"
|
|
303
|
+
}
|
|
304
|
+
],
|
|
305
|
+
container: null,
|
|
306
|
+
scorer: getStrength,
|
|
307
|
+
striped: false
|
|
308
|
+
};
|
|
309
|
+
#container;
|
|
310
|
+
#describedBy;
|
|
311
|
+
#form;
|
|
312
|
+
#progress;
|
|
313
|
+
#progressBar;
|
|
314
|
+
#resetHandler;
|
|
315
|
+
/**
|
|
316
|
+
* Calculates the strength of a password.
|
|
317
|
+
* @param {string} password The password.
|
|
318
|
+
* @param {string[]} [commonPasswords=this.defaults.commonPasswords] Passwords to score as very weak.
|
|
319
|
+
* @returns {number} The password strength, from 0 to 100.
|
|
320
|
+
*/
|
|
321
|
+
static getStrength(password, commonPasswords = this.defaults.commonPasswords) {
|
|
322
|
+
return getStrength(password, commonPasswords);
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Creates a PasswordStrength.
|
|
326
|
+
* @param {HTMLElement} node The input node.
|
|
327
|
+
* @param {PasswordStrengthOptions} [options] The PasswordStrength options.
|
|
328
|
+
*/
|
|
329
|
+
constructor(node, options) {
|
|
330
|
+
super(node, options);
|
|
331
|
+
const overrides = {
|
|
332
|
+
...(0, _fr0st_ui.getDataset)(node),
|
|
333
|
+
...options
|
|
334
|
+
};
|
|
335
|
+
for (const key of ["levels", "commonPasswords"]) if (Array.isArray(overrides[key])) {
|
|
336
|
+
this.options[key].length = 0;
|
|
337
|
+
_fr0st_query.default._extend(this.options[key], overrides[key]);
|
|
338
|
+
}
|
|
339
|
+
this.#form = this.node.form;
|
|
340
|
+
if (this.options.container) this.#container = _fr0st_query.default.findOne(this.options.container);
|
|
341
|
+
else this.#container = _fr0st_query.default.closest(this.node, ":not(.form-input):not(.input-group)").shift();
|
|
342
|
+
this.#render();
|
|
343
|
+
this.#refresh();
|
|
344
|
+
this.#events();
|
|
345
|
+
}
|
|
346
|
+
/** @inheritdoc */
|
|
347
|
+
dispose() {
|
|
348
|
+
_fr0st_query.default.remove(this.#progress);
|
|
349
|
+
_fr0st_query.default.removeEvent(this.node, "input.ui.passwordstrength");
|
|
350
|
+
if (this.#form) _fr0st_query.default.removeEvent(this.#form, "reset.ui.passwordstrength", this.#resetHandler);
|
|
351
|
+
if (this.#describedBy === null) _fr0st_query.default.removeAttribute(this.node, "aria-describedby");
|
|
352
|
+
else _fr0st_query.default.setAttribute(this.node, { "aria-describedby": this.#describedBy });
|
|
353
|
+
this.#container = null;
|
|
354
|
+
this.#form = null;
|
|
355
|
+
this.#progress = null;
|
|
356
|
+
this.#progressBar = null;
|
|
357
|
+
this.#resetHandler = null;
|
|
358
|
+
super.dispose();
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Gets the password strength.
|
|
362
|
+
* @returns {number} The password strength, from 0 to 100.
|
|
363
|
+
*/
|
|
364
|
+
getStrength() {
|
|
365
|
+
const value = _fr0st_query.default.getValue(this.node);
|
|
366
|
+
const strength = Number(this.options.scorer(value, this.options.commonPasswords));
|
|
367
|
+
return Number.isFinite(strength) ? _fr0st_query.default._clamp(strength, 0, 100) : 0;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Attaches events for the PasswordStrength.
|
|
371
|
+
*/
|
|
372
|
+
#events() {
|
|
373
|
+
if (this.#form) {
|
|
374
|
+
this.#resetHandler = (event) => {
|
|
375
|
+
setTimeout(() => {
|
|
376
|
+
if (this.node && !event.defaultPrevented) this.#refresh();
|
|
377
|
+
}, 0);
|
|
378
|
+
};
|
|
379
|
+
_fr0st_query.default.addEvent(this.#form, "reset.ui.passwordstrength", this.#resetHandler);
|
|
380
|
+
}
|
|
381
|
+
_fr0st_query.default.addEvent(this.node, "input.ui.passwordstrength", (_) => {
|
|
382
|
+
this.#refresh();
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Refreshes the password strength.
|
|
387
|
+
*/
|
|
388
|
+
#refresh() {
|
|
389
|
+
const strength = this.getStrength();
|
|
390
|
+
const nextLevel = this.options.levels.findLast((level) => strength >= level.score);
|
|
391
|
+
_fr0st_query.default.setStyle(this.#progressBar, { width: `${strength}%` });
|
|
392
|
+
_fr0st_query.default.setAttribute(this.#progressBar, {
|
|
393
|
+
"class": this.constructor.classes.progressBar,
|
|
394
|
+
"aria-valuenow": strength
|
|
395
|
+
});
|
|
396
|
+
_fr0st_query.default.addClass(this.#progressBar, nextLevel.class);
|
|
397
|
+
if (this.options.striped) _fr0st_query.default.addClass(this.#progressBar, this.constructor.classes.progressBarStriped);
|
|
398
|
+
_fr0st_query.default.setText(this.#progressBar, nextLevel.text ?? "");
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Renders the password strength element.
|
|
402
|
+
*/
|
|
403
|
+
#render() {
|
|
404
|
+
this.#describedBy = _fr0st_query.default.getAttribute(this.node, "aria-describedby");
|
|
405
|
+
this.#progress = _fr0st_query.default.create("div", { class: this.constructor.classes.progress });
|
|
406
|
+
const id = (0, _fr0st_ui.generateId)("password-strength");
|
|
407
|
+
this.#progressBar = _fr0st_query.default.create("div", { attributes: {
|
|
408
|
+
"id": id,
|
|
409
|
+
"role": "progressbar",
|
|
410
|
+
"aria-valuemin": 0,
|
|
411
|
+
"aria-valuemax": 100
|
|
412
|
+
} });
|
|
413
|
+
_fr0st_query.default.append(this.#progress, this.#progressBar);
|
|
414
|
+
_fr0st_query.default.append(this.#container, this.#progress);
|
|
415
|
+
const describedBy = [this.#describedBy, id].filter(Boolean).join(" ");
|
|
416
|
+
_fr0st_query.default.setAttribute(this.node, { "aria-describedby": describedBy });
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
//#endregion
|
|
421
|
+
//#region src/index.js
|
|
422
|
+
(0, _fr0st_ui.initComponent)("passwordstrength", PasswordStrength);
|
|
423
|
+
var src_default = PasswordStrength;
|
|
424
|
+
|
|
425
|
+
//#endregion
|
|
426
|
+
exports.PasswordStrength = src_default;
|
|
427
|
+
});
|
|
428
|
+
//# sourceMappingURL=frost-ui-passwordstrength.js.map
|