@fr0st/ui-passwordstrength 2.0.8 → 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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frost-ui-passwordstrength.js","sources":["../src/password-strength.js","../src/prototype/events.js","../src/prototype/helpers.js","../src/prototype/render.js","../src/static/helpers.js","../src/index.js"],"sourcesContent":["import $ from '@fr0st/query';\nimport { BaseComponent } from '@fr0st/ui';\n\n/**\n * PasswordStrength Class\n * @class\n */\nexport default class PasswordStrength extends BaseComponent {\n /**\n * New PasswordStrength constructor.\n * @param {HTMLElement} node The input node.\n * @param {object} [options] The options to create the PasswordStrength with.\n */\n constructor(node, options) {\n super(node, options);\n\n if (this._options.container) {\n this._container = $.findOne(this._options.container);\n } else {\n this._container = $.closest(this._node, ':not(.form-input):not(.input-group)');\n }\n\n this._render();\n this._refresh();\n this._events();\n }\n\n /**\n * Dispose the PasswordStrength.\n */\n dispose() {\n $.remove(this._progress);\n $.removeEvent(this._node, 'input.ui.passwordstrength');\n $.removeAttribute(this._node, 'aria-describedby');\n\n this._container = null;\n this._progress = null;\n this._progressBar = null;\n\n super.dispose();\n }\n\n /**\n * Get the password strength.\n * @return {number} The password strength. (0, 100)\n */\n getStrength() {\n const value = $.getValue(this._node);\n\n return this.constructor.getStrength(value);\n }\n}\n","import $ from '@fr0st/query';\n\n/**\n * Attach events for the PasswordStrength.\n */\nexport function _events() {\n $.addEvent(this._node, 'input.ui.passwordstrength', (_) => {\n this._refresh();\n });\n};\n","import $ from '@fr0st/query';\n\n/**\n * Refresh the password strength.\n */\nexport function _refresh() {\n const strength = this.getStrength();\n\n let nextLevel;\n for (const level of this._options.levels) {\n if (strength < level.score) {\n break;\n }\n\n nextLevel = level;\n }\n\n $.setStyle(this._progressBar, { width: `${strength}%` });\n $.setAttribute(this._progressBar, {\n 'class': this.constructor.classes.progressBar,\n 'aria-valuenow': strength,\n });\n\n $.addClass(this._progressBar, nextLevel.class);\n\n if (this._options.striped) {\n $.addClass(this._progressBar, this.constructor.classes.progressBarStriped);\n }\n\n if (nextLevel.text) {\n $.setText(this._progressBar, nextLevel.text);\n }\n};\n","import $ from '@fr0st/query';\nimport { generateId } from '@fr0st/ui';\n\n/**\n * Render the password strength element.\n */\nexport function _render() {\n this._progress = $.create('div', {\n class: this.constructor.classes.progress,\n });\n\n const id = generateId('password-strength');\n\n this._progressBar = $.create('div', {\n attributes: {\n 'id': id,\n 'role': 'progressbar',\n 'aria-valuemin': 0,\n 'aria-valuemax': 100,\n },\n });\n\n $.append(this._progress, this._progressBar);\n $.append(this._container, this._progress);\n\n $.setAttribute(this._node, {\n 'aria-describedby': id,\n });\n};\n","import $ from '@fr0st/query';\n\n/**\n * Find character sequences in a string.\n * @param {string} string The input string.\n * @param {array} locations The character locations.\n * @return {array} The character sequences.\n */\nfunction findSequences(string, locations) {\n const sequences = [];\n let sequence = [];\n\n for (let i = 0; i < locations.length - 1; i++) {\n const current = locations[i];\n const next = locations[i + 1];\n const distance = next - current;\n\n const char = string[current];\n const nextChar = string[next];\n const charDistance = nextChar.charCodeAt(0) - char.charCodeAt(0);\n\n if (distance === 1 && charDistance === 1) {\n if (!sequence.length) {\n sequence.push(char);\n }\n sequence.push(nextChar);\n } else if (sequence.length) {\n sequences.push(sequence);\n sequence = [];\n }\n }\n\n if (sequence.length) {\n sequences.push(sequence);\n }\n\n return sequences;\n};\n\n/**\n * Get the strength of a password.\n * @param {string} password The password.\n * @return {number} The password strength.\n */\nexport function getStrength(password) {\n if (password.match(/^password/i)) {\n password = password.substring(8);\n }\n\n const length = password.length;\n\n let score = 0;\n\n if (length) {\n score += length * 6;\n }\n\n const upper = [];\n const lower = [];\n const numbers = [];\n const symbols = [];\n const dictionary = {};\n\n for (let i = 0; i < length; i++) {\n const char = password[i];\n const code = char.charCodeAt(0);\n\n if (code >= 48 && code <= 57) {\n numbers.push(i);\n } else if (code >= 65 && code <= 90) {\n upper.push(i);\n } else if (code >= 97 && code <= 122) {\n lower.push(i);\n } else {\n symbols.push(i);\n }\n\n if (!(char in dictionary)) {\n dictionary[char] = 0;\n }\n\n dictionary[char]++;\n }\n\n // reward upper/lower case\n if (upper.length !== length && lower.length !== length) {\n if (upper.length) {\n score += length - upper.length;\n }\n\n if (lower.length) {\n score += length - lower.length;\n }\n }\n\n // reward numbers\n if (numbers.length !== length) {\n score += numbers.length * 3;\n }\n\n // reward symbols\n score += symbols.length * 6;\n\n // reward inner numbers/symbols\n for (const list of [numbers, symbols]) {\n const reward = list.filter((v) => v && v !== length - 1).length;\n score += reward * 3;\n }\n\n // punish only letters\n if (!numbers.length && !symbols.length) {\n score -= length;\n }\n\n // punish only numbers\n if (!upper.length && !lower.length && !symbols.length) {\n score -= length;\n }\n\n // punish no symbols\n if (!symbols.length) {\n score -= length;\n }\n\n // repeating characters\n const repeats = Object.values(dictionary)\n .reduce((acc, count) => acc + count - 1, 0);\n\n if (repeats > 0) {\n score -= repeats;\n }\n\n if (length >= 2) {\n // consecutive characters\n const matches = password.matchAll(/(.)\\1+/g);\n\n for (const match of matches) {\n score -= Math.min(match[0].length, 12) * 3;\n }\n\n const lowerPassword = password.toLowerCase();\n\n // sequential letters\n const letters = upper.concat(lower);\n const letterSequences = findSequences(lowerPassword, letters);\n for (const sequence of letterSequences) {\n if (sequence.length > 2) {\n score -= (Math.min(sequence.length - 2, 16)) * 3;\n }\n }\n\n // sequential numbers\n const numberSequences = findSequences(lowerPassword, numbers);\n for (const sequence of numberSequences) {\n if (sequence.length > 2) {\n score -= (Math.min(sequence.length - 2, 16)) * 3;\n }\n }\n }\n\n return $._clamp(score, 0, 100);\n};\n","import { initComponent } from '@fr0st/ui';\nimport PasswordStrength from './password-strength.js';\nimport { _events } from './prototype/events.js';\nimport { _refresh } from './prototype/helpers.js';\nimport { _render } from './prototype/render.js';\nimport { getStrength } from './static/helpers.js';\n\n// PasswordStrength default options\nPasswordStrength.defaults = {\n levels: [\n {\n score: 0,\n class: 'text-bg-danger',\n text: 'Very Weak',\n },\n {\n score: 20,\n class: 'text-bg-danger',\n text: 'Weak',\n },\n {\n score: 40,\n class: 'text-bg-warning',\n text: 'Normal',\n },\n {\n score: 60,\n class: 'text-bg-success',\n text: 'Strong',\n },\n {\n score: 80,\n class: 'text-bg-success',\n text: 'Very Strong',\n },\n ],\n container: null,\n striped: false,\n};\n\n// PasswordStrength classes\nPasswordStrength.classes = {\n progress: 'progress mt-2',\n progressBar: 'progress-bar',\n progressBarStriped: 'progress-bar-striped',\n};\n\n// PasswordStrength static\nPasswordStrength.getStrength = getStrength;\n\n// PasswordStrength prototype\nconst proto = PasswordStrength.prototype;\n\nproto._events = _events;\nproto._refresh = _refresh;\nproto._render = _render;\n\n// PasswordStrength init\ninitComponent('passwordstrength', PasswordStrength);\n\nexport default PasswordStrength;\n"],"names":["BaseComponent","generateId","initComponent"],"mappings":";;;;;;IAGA;IACA;IACA;IACA;IACe,MAAM,gBAAgB,SAASA,gBAAa,CAAC;IAC5D;IACA;IACA;IACA;IACA;IACA,IAAI,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE;IAC/B,QAAQ,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC;;IAE5B,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE;IACrC,YAAY,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;IAChE,SAAS,MAAM;IACf,YAAY,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,qCAAqC,CAAC;IAC1F;;IAEA,QAAQ,IAAI,CAAC,OAAO,EAAE;IACtB,QAAQ,IAAI,CAAC,QAAQ,EAAE;IACvB,QAAQ,IAAI,CAAC,OAAO,EAAE;IACtB;;IAEA;IACA;IACA;IACA,IAAI,OAAO,GAAG;IACd,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC;IAChC,QAAQ,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,EAAE,2BAA2B,CAAC;IAC9D,QAAQ,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,EAAE,kBAAkB,CAAC;;IAEzD,QAAQ,IAAI,CAAC,UAAU,GAAG,IAAI;IAC9B,QAAQ,IAAI,CAAC,SAAS,GAAG,IAAI;IAC7B,QAAQ,IAAI,CAAC,YAAY,GAAG,IAAI;;IAEhC,QAAQ,KAAK,CAAC,OAAO,EAAE;IACvB;;IAEA;IACA;IACA;IACA;IACA,IAAI,WAAW,GAAG;IAClB,QAAQ,MAAM,KAAK,GAAG,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC;;IAE5C,QAAQ,OAAO,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,KAAK,CAAC;IAClD;IACA;;ICjDA;IACA;IACA;IACO,SAAS,OAAO,GAAG;IAC1B,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,2BAA2B,EAAE,CAAC,CAAC,KAAK;IAC/D,QAAQ,IAAI,CAAC,QAAQ,EAAE;IACvB,KAAK,CAAC;IACN;;ICPA;IACA;IACA;IACO,SAAS,QAAQ,GAAG;IAC3B,IAAI,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE;;IAEvC,IAAI,IAAI,SAAS;IACjB,IAAI,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE;IAC9C,QAAQ,IAAI,QAAQ,GAAG,KAAK,CAAC,KAAK,EAAE;IACpC,YAAY;IACZ;;IAEA,QAAQ,SAAS,GAAG,KAAK;IACzB;;IAEA,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5D,IAAI,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,EAAE;IACtC,QAAQ,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,WAAW;IACrD,QAAQ,eAAe,EAAE,QAAQ;IACjC,KAAK,CAAC;;IAEN,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,KAAK,CAAC;;IAElD,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE;IAC/B,QAAQ,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,kBAAkB,CAAC;IAClF;;IAEA,IAAI,IAAI,SAAS,CAAC,IAAI,EAAE;IACxB,QAAQ,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,IAAI,CAAC;IACpD;IACA;;IC7BA;IACA;IACA;IACO,SAAS,OAAO,GAAG;IAC1B,IAAI,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE;IACrC,QAAQ,KAAK,EAAE,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,QAAQ;IAChD,KAAK,CAAC;;IAEN,IAAI,MAAM,EAAE,GAAGC,aAAU,CAAC,mBAAmB,CAAC;;IAE9C,IAAI,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE;IACxC,QAAQ,UAAU,EAAE;IACpB,YAAY,IAAI,EAAE,EAAE;IACpB,YAAY,MAAM,EAAE,aAAa;IACjC,YAAY,eAAe,EAAE,CAAC;IAC9B,YAAY,eAAe,EAAE,GAAG;IAChC,SAAS;IACT,KAAK,CAAC;;IAEN,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,YAAY,CAAC;IAC/C,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC;;IAE7C,IAAI,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE;IAC/B,QAAQ,kBAAkB,EAAE,EAAE;IAC9B,KAAK,CAAC;IACN;;IC1BA;IACA;IACA;IACA;IACA;IACA;IACA,SAAS,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE;IAC1C,IAAI,MAAM,SAAS,GAAG,EAAE;IACxB,IAAI,IAAI,QAAQ,GAAG,EAAE;;IAErB,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;IACnD,QAAQ,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC;IACpC,QAAQ,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC;IACrC,QAAQ,MAAM,QAAQ,GAAG,IAAI,GAAG,OAAO;;IAEvC,QAAQ,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC;IACpC,QAAQ,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC;IACrC,QAAQ,MAAM,YAAY,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;;IAExE,QAAQ,IAAI,QAAQ,KAAK,CAAC,IAAI,YAAY,KAAK,CAAC,EAAE;IAClD,YAAY,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE;IAClC,gBAAgB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;IACnC;IACA,YAAY,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC;IACnC,SAAS,MAAM,IAAI,QAAQ,CAAC,MAAM,EAAE;IACpC,YAAY,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC;IACpC,YAAY,QAAQ,GAAG,EAAE;IACzB;IACA;;IAEA,IAAI,IAAI,QAAQ,CAAC,MAAM,EAAE;IACzB,QAAQ,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC;IAChC;;IAEA,IAAI,OAAO,SAAS;IACpB;IAEA;IACA;IACA;IACA;IACA;IACO,SAAS,WAAW,CAAC,QAAQ,EAAE;IACtC,IAAI,IAAI,QAAQ,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE;IACtC,QAAQ,QAAQ,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;IACxC;;IAEA,IAAI,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM;;IAElC,IAAI,IAAI,KAAK,GAAG,CAAC;;IAEjB,IAAI,IAAI,MAAM,EAAE;IAChB,QAAQ,KAAK,IAAI,MAAM,GAAG,CAAC;IAC3B;;IAEA,IAAI,MAAM,KAAK,GAAG,EAAE;IACpB,IAAI,MAAM,KAAK,GAAG,EAAE;IACpB,IAAI,MAAM,OAAO,GAAG,EAAE;IACtB,IAAI,MAAM,OAAO,GAAG,EAAE;IACtB,IAAI,MAAM,UAAU,GAAG,EAAE;;IAEzB,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE;IACrC,QAAQ,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC;IAChC,QAAQ,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;;IAEvC,QAAQ,IAAI,IAAI,IAAI,EAAE,IAAI,IAAI,IAAI,EAAE,EAAE;IACtC,YAAY,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3B,SAAS,MAAM,IAAI,IAAI,IAAI,EAAE,IAAI,IAAI,IAAI,EAAE,EAAE;IAC7C,YAAY,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IACzB,SAAS,MAAM,IAAI,IAAI,IAAI,EAAE,IAAI,IAAI,IAAI,GAAG,EAAE;IAC9C,YAAY,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IACzB,SAAS,MAAM;IACf,YAAY,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3B;;IAEA,QAAQ,IAAI,EAAE,IAAI,IAAI,UAAU,CAAC,EAAE;IACnC,YAAY,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC;IAChC;;IAEA,QAAQ,UAAU,CAAC,IAAI,CAAC,EAAE;IAC1B;;IAEA;IACA,IAAI,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,EAAE;IAC5D,QAAQ,IAAI,KAAK,CAAC,MAAM,EAAE;IAC1B,YAAY,KAAK,IAAI,MAAM,GAAG,KAAK,CAAC,MAAM;IAC1C;;IAEA,QAAQ,IAAI,KAAK,CAAC,MAAM,EAAE;IAC1B,YAAY,KAAK,IAAI,MAAM,GAAG,KAAK,CAAC,MAAM;IAC1C;IACA;;IAEA;IACA,IAAI,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE;IACnC,QAAQ,KAAK,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;IACnC;;IAEA;IACA,IAAI,KAAK,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;;IAE/B;IACA,IAAI,KAAK,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE;IAC3C,QAAQ,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,MAAM,GAAG,CAAC,CAAC,CAAC,MAAM;IACvE,QAAQ,KAAK,IAAI,MAAM,GAAG,CAAC;IAC3B;;IAEA;IACA,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE;IAC5C,QAAQ,KAAK,IAAI,MAAM;IACvB;;IAEA;IACA,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE;IAC3D,QAAQ,KAAK,IAAI,MAAM;IACvB;;IAEA;IACA,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE;IACzB,QAAQ,KAAK,IAAI,MAAM;IACvB;;IAEA;IACA,IAAI,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,UAAU;IAC5C,SAAS,MAAM,CAAC,CAAC,GAAG,EAAE,KAAK,KAAK,GAAG,GAAG,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC;;IAEnD,IAAI,IAAI,OAAO,GAAG,CAAC,EAAE;IACrB,QAAQ,KAAK,IAAI,OAAO;IACxB;;IAEA,IAAI,IAAI,MAAM,IAAI,CAAC,EAAE;IACrB;IACA,QAAQ,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;;IAEpD,QAAQ,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE;IACrC,YAAY,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC;IACtD;;IAEA,QAAQ,MAAM,aAAa,GAAG,QAAQ,CAAC,WAAW,EAAE;;IAEpD;IACA,QAAQ,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;IAC3C,QAAQ,MAAM,eAAe,GAAG,aAAa,CAAC,aAAa,EAAE,OAAO,CAAC;IACrE,QAAQ,KAAK,MAAM,QAAQ,IAAI,eAAe,EAAE;IAChD,YAAY,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE;IACrC,gBAAgB,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC;IAChE;IACA;;IAEA;IACA,QAAQ,MAAM,eAAe,GAAG,aAAa,CAAC,aAAa,EAAE,OAAO,CAAC;IACrE,QAAQ,KAAK,MAAM,QAAQ,IAAI,eAAe,EAAE;IAChD,YAAY,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE;IACrC,gBAAgB,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC;IAChE;IACA;IACA;;IAEA,IAAI,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC;IAClC;;IC1JA;IACA,gBAAgB,CAAC,QAAQ,GAAG;IAC5B,IAAI,MAAM,EAAE;IACZ,QAAQ;IACR,YAAY,KAAK,EAAE,CAAC;IACpB,YAAY,KAAK,EAAE,gBAAgB;IACnC,YAAY,IAAI,EAAE,WAAW;IAC7B,SAAS;IACT,QAAQ;IACR,YAAY,KAAK,EAAE,EAAE;IACrB,YAAY,KAAK,EAAE,gBAAgB;IACnC,YAAY,IAAI,EAAE,MAAM;IACxB,SAAS;IACT,QAAQ;IACR,YAAY,KAAK,EAAE,EAAE;IACrB,YAAY,KAAK,EAAE,iBAAiB;IACpC,YAAY,IAAI,EAAE,QAAQ;IAC1B,SAAS;IACT,QAAQ;IACR,YAAY,KAAK,EAAE,EAAE;IACrB,YAAY,KAAK,EAAE,iBAAiB;IACpC,YAAY,IAAI,EAAE,QAAQ;IAC1B,SAAS;IACT,QAAQ;IACR,YAAY,KAAK,EAAE,EAAE;IACrB,YAAY,KAAK,EAAE,iBAAiB;IACpC,YAAY,IAAI,EAAE,aAAa;IAC/B,SAAS;IACT,KAAK;IACL,IAAI,SAAS,EAAE,IAAI;IACnB,IAAI,OAAO,EAAE,KAAK;IAClB,CAAC;;IAED;IACA,gBAAgB,CAAC,OAAO,GAAG;IAC3B,IAAI,QAAQ,EAAE,eAAe;IAC7B,IAAI,WAAW,EAAE,cAAc;IAC/B,IAAI,kBAAkB,EAAE,sBAAsB;IAC9C,CAAC;;IAED;IACA,gBAAgB,CAAC,WAAW,GAAG,WAAW;;IAE1C;IACA,MAAM,KAAK,GAAG,gBAAgB,CAAC,SAAS;;IAExC,KAAK,CAAC,OAAO,GAAG,OAAO;IACvB,KAAK,CAAC,QAAQ,GAAG,QAAQ;IACzB,KAAK,CAAC,OAAO,GAAG,OAAO;;IAEvB;AACAC,oBAAa,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"frost-ui-passwordstrength.js","names":["$","BaseComponent","getDataset","$","generateId"],"sources":["../src/strength.js","../src/password-strength.js","../src/index.js"],"sourcesContent":["import $ from '@fr0st/query';\n\nconst characterTypes = [\n { pattern: /\\p{Ll}/u, type: 'lower' },\n { pattern: /\\p{Lu}/u, type: 'upper' },\n { pattern: /\\p{N}/u, type: 'number' },\n];\n\nconst keyboardSequences = [\n '1234567890',\n 'qwertyuiop',\n 'asdfghjkl',\n 'zxcvbnm',\n].flatMap(\n (row) => [\n row,\n Array.from(row).reverse().join(''),\n ],\n);\n\nconst leetCharacters = {\n '$': 's',\n '0': 'o',\n '3': 'e',\n '4': 'a',\n '5': 's',\n '7': 't',\n '@': 'a',\n};\n\nconst lengthBands = [\n { end: 5, max: 19, min: 1, start: 1 },\n { end: 8, max: 39, min: 20, start: 6 },\n { end: 11, max: 59, min: 40, start: 9 },\n { end: 15, max: 79, min: 60, start: 12 },\n { end: 24, max: 100, min: 80, start: 16 },\n];\n\n/**\n * Gets the type of a password character.\n * @param {string} character The character.\n * @returns {string} The character type.\n */\nconst getCharacterType = (character) =>\n characterTypes.find(\n ({ pattern }) => pattern.test(character),\n )?.type || 'symbol';\n\n/**\n * Gets a length-based password strength.\n * @param {string[]} characters The password characters.\n * @returns {number} The password strength.\n */\nconst getLengthStrength = (characters) => {\n const band = lengthBands.find(\n ({ end }) => characters.length <= end,\n ) || lengthBands.at(-1);\n const score = Math.round(\n $._map(\n Math.min(characters.length, band.end),\n band.start,\n band.end,\n band.min,\n band.max,\n ),\n );\n const diversity = new Set(\n characters.map(getCharacterType),\n ).size;\n\n return Math.min(\n score +\n (diversity - 1) * 2,\n band.max,\n );\n};\n\n/**\n * Gets the smallest repeated pattern.\n * @param {string[]} characters The password characters.\n * @returns {string[]|null} The repeated pattern.\n */\nconst getRepeatedPattern = (characters) => {\n const maxLength = Math.floor(characters.length / 2);\n\n for (let length = 1; length <= maxLength; length++) {\n if (\n characters.length % length === 0 &&\n characters.every(\n (character, index) =>\n character === characters[index % length],\n )\n ) {\n return characters.slice(0, length);\n }\n }\n\n return null;\n};\n\n/**\n * Normalizes common password matching.\n * @param {string} password The password.\n * @returns {string} The normalized password.\n */\nconst normalizePassword = (password) =>\n String(password)\n .normalize('NFKC')\n .toLowerCase();\n\n/**\n * Normalizes common leet substitutions.\n * @param {string} password The password.\n * @returns {string} The normalized password.\n */\nconst normalizeLeet = (password) =>\n Array.from(\n password,\n (character) => leetCharacters[character] || character,\n ).join('');\n\n/**\n * Gets normalized variants used to match common passwords.\n * @param {string} password The normalized password.\n * @returns {Set<string>} The password variants.\n */\nconst getPasswordVariants = (password) => {\n // Preserve digits for decoration stripping while resolving symbol substitutions.\n const substituted = password.replace(/[^\\p{L}\\p{N}]/gu, normalizeLeet);\n const variants = [password, substituted].flatMap((value) => {\n const undecorated = value.replace(\n /^[^\\p{L}\\p{N}]+|[^\\p{L}\\p{N}]+$/gu,\n '',\n );\n\n return [\n undecorated,\n undecorated.replace(/^\\d+|\\d+$/g, ''),\n ];\n });\n\n return new Set([\n normalizeLeet(password),\n ...variants,\n ...variants.map(normalizeLeet),\n ]);\n};\n\n/**\n * Gets the score for a common password.\n * @param {string} password The normalized password.\n * @param {string[]} commonPasswords The common passwords.\n * @returns {number|null} The common-password score.\n */\nconst getCommonPasswordStrength = (password, commonPasswords) => {\n const common = new Set(\n commonPasswords.map(normalizePassword),\n );\n\n if (common.has(password)) {\n return 0;\n }\n\n return common.isDisjointFrom(getPasswordVariants(password)) ? null : 5;\n};\n\n/**\n * Checks whether characters form an ascending or descending sequence.\n * @param {string[]} characters The password characters.\n * @returns {boolean} Whether the characters form a sequence.\n */\nconst isSequence = (characters) => {\n const [first, second, third] = characters.map(\n (character) => character.toLowerCase(),\n );\n const type = getCharacterType(first);\n const direction = second.codePointAt(0) - first.codePointAt(0);\n\n return ['lower', 'number'].includes(type) &&\n getCharacterType(second) === type &&\n getCharacterType(third) === type &&\n Math.abs(direction) === 1 &&\n third.codePointAt(0) - second.codePointAt(0) === direction;\n};\n\n/**\n * Checks whether characters form a keyboard sequence.\n * @param {string[]} characters The password characters.\n * @returns {boolean} Whether the characters form a keyboard sequence.\n */\nconst isKeyboardSequence = (characters) => {\n const sequence = characters.join('').toLowerCase();\n\n return keyboardSequences.some(\n (keyboardSequence) => keyboardSequence.includes(sequence),\n );\n};\n\n/**\n * Checks whether characters form a predictable pattern.\n * @param {string[]} characters The password characters.\n * @returns {boolean} Whether the characters form a predictable pattern.\n */\nconst isPredictable = (characters) =>\n new Set(characters).size === 1 ||\n isSequence(characters) ||\n isKeyboardSequence(characters);\n\n/**\n * Gets the number of characters in predictable patterns.\n * @param {string[]} characters The password characters.\n * @returns {number} The number of predictable characters.\n */\nconst getPredictableCount = (characters) => {\n const indices = new Set();\n\n for (let i = 0; i + 2 < characters.length; i++) {\n if (isPredictable(characters.slice(i, i + 3))) {\n indices.add(i);\n indices.add(i + 1);\n indices.add(i + 2);\n }\n }\n\n return indices.size;\n};\n\n/**\n * Calculates the strength of a password.\n * @param {string} password The password.\n * @param {string[]} [commonPasswords=[]] Passwords to score as very weak.\n * @returns {number} The password strength, from 0 to 100.\n */\nexport const getStrength = (password, commonPasswords = []) => {\n const normalizedPassword = password.normalize('NFKC');\n const characters = Array.from(normalizedPassword);\n\n if (!characters.length) {\n return 0;\n }\n\n const commonStrength = getCommonPasswordStrength(\n normalizedPassword.toLowerCase(),\n commonPasswords,\n );\n\n if (commonStrength !== null) {\n return commonStrength;\n }\n\n const score = getLengthStrength(characters);\n const repeatedPattern = getRepeatedPattern(characters);\n\n if (repeatedPattern?.length === 1) {\n return 0;\n }\n\n if (repeatedPattern) {\n return Math.min(\n score,\n getLengthStrength(repeatedPattern),\n 15,\n );\n }\n\n const predictableCount = getPredictableCount(characters);\n\n return $._clamp(\n score - predictableCount,\n 0,\n predictableCount === characters.length ? 15 : 100,\n );\n};\n","import $ from '@fr0st/query';\nimport { BaseComponent, generateId, getDataset } from '@fr0st/ui';\nimport { getStrength } from './strength.js';\n\n/**\n * @typedef {object} PasswordStrengthLevel\n * @property {string} class The CSS class applied to the progress bar.\n * @property {number} score The minimum score for the level.\n * @property {string} [text] The label displayed in the progress bar.\n */\n\n/**\n * @callback PasswordStrengthScorer\n * @param {string} password The password.\n * @param {string[]} commonPasswords The common passwords.\n * @returns {number} The password strength, from 0 to 100.\n */\n\n/**\n * @typedef {object} PasswordStrengthOptions\n * @property {string[]} [commonPasswords] Passwords to score as very weak.\n * @property {string|null} [container=null] The selector for the progress container.\n * @property {PasswordStrengthLevel[]} [levels] The ordered password-strength levels.\n * @property {PasswordStrengthScorer} [scorer] Calculates the password strength.\n * @property {boolean} [striped=false] Whether to display a striped progress bar.\n */\n\n/**\n * Displays the strength of a password input as a progress bar.\n * @augments {BaseComponent<PasswordStrengthOptions>}\n */\nexport default class PasswordStrength extends BaseComponent {\n static classes = {\n progress: 'progress mt-2',\n progressBar: 'progress-bar',\n progressBarStriped: 'progress-bar-striped',\n };\n /** @type {PasswordStrengthOptions} */\n static defaults = {\n commonPasswords: [\n '123456',\n '12345678',\n '123456789',\n '1234567890',\n '000000',\n '111111',\n 'abc123',\n 'admin',\n 'dragon',\n 'iloveyou',\n 'letmein',\n 'monkey',\n 'password',\n 'password1',\n 'password123',\n 'qwerty',\n 'qwerty123',\n 'welcome',\n ],\n levels: [\n {\n score: 0,\n class: 'text-bg-danger',\n text: 'Very Weak',\n },\n {\n score: 20,\n class: 'text-bg-danger',\n text: 'Weak',\n },\n {\n score: 40,\n class: 'text-bg-warning',\n text: 'Normal',\n },\n {\n score: 60,\n class: 'text-bg-success',\n text: 'Strong',\n },\n {\n score: 80,\n class: 'text-bg-success',\n text: 'Very Strong',\n },\n ],\n container: null,\n scorer: getStrength,\n striped: false,\n };\n\n #container;\n #describedBy;\n #form;\n #progress;\n #progressBar;\n #resetHandler;\n\n /**\n * Calculates the strength of a password.\n * @param {string} password The password.\n * @param {string[]} [commonPasswords=this.defaults.commonPasswords] Passwords to score as very weak.\n * @returns {number} The password strength, from 0 to 100.\n */\n static getStrength(password, commonPasswords = this.defaults.commonPasswords) {\n return getStrength(password, commonPasswords);\n }\n\n /**\n * Creates a PasswordStrength.\n * @param {HTMLElement} node The input node.\n * @param {PasswordStrengthOptions} [options] The PasswordStrength options.\n */\n constructor(node, options) {\n super(node, options);\n\n const overrides = { ...getDataset(node), ...options };\n\n // Replace supplied arrays instead of merging them with default entries.\n for (const key of ['levels', 'commonPasswords']) {\n if (Array.isArray(overrides[key])) {\n this.options[key].length = 0;\n $._extend(this.options[key], overrides[key]);\n }\n }\n\n this.#form = this.node.form;\n\n if (this.options.container) {\n this.#container = $.findOne(this.options.container);\n } else {\n this.#container = $.closest(this.node, ':not(.form-input):not(.input-group)').shift();\n }\n\n this.#render();\n this.#refresh();\n this.#events();\n }\n\n /** @inheritdoc */\n dispose() {\n $.remove(this.#progress);\n $.removeEvent(this.node, 'input.ui.passwordstrength');\n\n if (this.#form) {\n $.removeEvent(this.#form, 'reset.ui.passwordstrength', this.#resetHandler);\n }\n\n if (this.#describedBy === null) {\n $.removeAttribute(this.node, 'aria-describedby');\n } else {\n $.setAttribute(this.node, { 'aria-describedby': this.#describedBy });\n }\n\n this.#container = null;\n this.#form = null;\n this.#progress = null;\n this.#progressBar = null;\n this.#resetHandler = null;\n\n super.dispose();\n }\n\n /**\n * Gets the password strength.\n * @returns {number} The password strength, from 0 to 100.\n */\n getStrength() {\n const value = $.getValue(this.node);\n const strength = Number(this.options.scorer(\n value,\n this.options.commonPasswords,\n ));\n\n return Number.isFinite(strength) ?\n $._clamp(strength, 0, 100) :\n 0;\n }\n\n /**\n * Attaches events for the PasswordStrength.\n */\n #events() {\n if (this.#form) {\n this.#resetHandler = (event) => {\n setTimeout(() => {\n if (this.node && !event.defaultPrevented) {\n this.#refresh();\n }\n }, 0);\n };\n\n $.addEvent(this.#form, 'reset.ui.passwordstrength', this.#resetHandler);\n }\n\n $.addEvent(this.node, 'input.ui.passwordstrength', (_) => {\n this.#refresh();\n });\n }\n\n /**\n * Refreshes the password strength.\n */\n #refresh() {\n const strength = this.getStrength();\n\n const nextLevel = this.options.levels.findLast(\n (level) => strength >= level.score,\n );\n\n $.setStyle(this.#progressBar, { width: `${strength}%` });\n $.setAttribute(this.#progressBar, {\n 'class': this.constructor.classes.progressBar,\n 'aria-valuenow': strength,\n });\n\n $.addClass(this.#progressBar, nextLevel.class);\n\n if (this.options.striped) {\n $.addClass(this.#progressBar, this.constructor.classes.progressBarStriped);\n }\n\n $.setText(this.#progressBar, nextLevel.text ?? '');\n }\n\n /**\n * Renders the password strength element.\n */\n #render() {\n this.#describedBy = $.getAttribute(this.node, 'aria-describedby');\n this.#progress = $.create('div', {\n class: this.constructor.classes.progress,\n });\n\n const id = generateId('password-strength');\n\n this.#progressBar = $.create('div', {\n attributes: {\n 'id': id,\n 'role': 'progressbar',\n 'aria-valuemin': 0,\n 'aria-valuemax': 100,\n },\n });\n\n $.append(this.#progress, this.#progressBar);\n $.append(this.#container, this.#progress);\n\n const describedBy = [this.#describedBy, id]\n .filter(Boolean)\n .join(' ');\n\n $.setAttribute(this.node, { 'aria-describedby': describedBy });\n }\n}\n","import { initComponent } from '@fr0st/ui';\nimport PasswordStrength from './password-strength.js';\n\ninitComponent('passwordstrength', PasswordStrength);\n\nexport default PasswordStrength;\n"],"mappings":"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"}
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
(function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("@fr0st/ui"),require("@fr0st/query")):typeof define==`function`&&define.amd?define([`exports`,`@fr0st/ui`,`@fr0st/query`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.UI=e.UI||{},e.UI,e.fQuery))})(this,function(e,t,n){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var r=Object.create,i=Object.defineProperty,a=Object.getOwnPropertyDescriptor,o=Object.getOwnPropertyNames,s=Object.getPrototypeOf,c=Object.prototype.hasOwnProperty,l=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var s=o(t),l=0,u=s.length,d;l<u;l++)d=s[l],!c.call(e,d)&&d!==n&&i(e,d,{get:(e=>t[e]).bind(null,d),enumerable:!(r=a(t,d))||r.enumerable});return e};n=((e,t,n)=>(n=e==null?{}:r(s(e)),l(t||!e||!e.__esModule||!c.call(e,`default`)?i(n,`default`,{value:e,enumerable:!0}):n,e)))(n,1);var u=[{pattern:/\p{Ll}/u,type:`lower`},{pattern:/\p{Lu}/u,type:`upper`},{pattern:/\p{N}/u,type:`number`}],d=[`1234567890`,`qwertyuiop`,`asdfghjkl`,`zxcvbnm`].flatMap(e=>[e,Array.from(e).reverse().join(``)]),f={$:`s`,0:`o`,3:`e`,4:`a`,5:`s`,7:`t`,"@":`a`},p=[{end:5,max:19,min:1,start:1},{end:8,max:39,min:20,start:6},{end:11,max:59,min:40,start:9},{end:15,max:79,min:60,start:12},{end:24,max:100,min:80,start:16}],m=e=>u.find(({pattern:t})=>t.test(e))?.type||`symbol`,h=e=>{let t=p.find(({end:t})=>e.length<=t)||p.at(-1),r=Math.round(n.default._map(Math.min(e.length,t.end),t.start,t.end,t.min,t.max)),i=new Set(e.map(m)).size;return Math.min(r+(i-1)*2,t.max)},g=e=>{let t=Math.floor(e.length/2);for(let n=1;n<=t;n++)if(e.length%n===0&&e.every((t,r)=>t===e[r%n]))return e.slice(0,n);return null},_=e=>String(e).normalize(`NFKC`).toLowerCase(),v=e=>Array.from(e,e=>f[e]||e).join(``),y=e=>{let t=[e,e.replace(/[^\p{L}\p{N}]/gu,v)].flatMap(e=>{let t=e.replace(/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/gu,``);return[t,t.replace(/^\d+|\d+$/g,``)]});return new Set([v(e),...t,...t.map(v)])},b=(e,t)=>{let n=new Set(t.map(_));return n.has(e)?0:n.isDisjointFrom(y(e))?null:5},x=e=>{let[t,n,r]=e.map(e=>e.toLowerCase()),i=m(t),a=n.codePointAt(0)-t.codePointAt(0);return[`lower`,`number`].includes(i)&&m(n)===i&&m(r)===i&&Math.abs(a)===1&&r.codePointAt(0)-n.codePointAt(0)===a},S=e=>{let t=e.join(``).toLowerCase();return d.some(e=>e.includes(t))},C=e=>new Set(e).size===1||x(e)||S(e),w=e=>{let t=new Set;for(let n=0;n+2<e.length;n++)C(e.slice(n,n+3))&&(t.add(n),t.add(n+1),t.add(n+2));return t.size},T=(e,t=[])=>{let r=e.normalize(`NFKC`),i=Array.from(r);if(!i.length)return 0;let a=b(r.toLowerCase(),t);if(a!==null)return a;let o=h(i),s=g(i);if(s?.length===1)return 0;if(s)return Math.min(o,h(s),15);let c=w(i);return n.default._clamp(o-c,0,c===i.length?15:100)},E=class extends t.BaseComponent{static classes={progress:`progress mt-2`,progressBar:`progress-bar`,progressBarStriped:`progress-bar-striped`};static defaults={commonPasswords:[`123456`,`12345678`,`123456789`,`1234567890`,`000000`,`111111`,`abc123`,`admin`,`dragon`,`iloveyou`,`letmein`,`monkey`,`password`,`password1`,`password123`,`qwerty`,`qwerty123`,`welcome`],levels:[{score:0,class:`text-bg-danger`,text:`Very Weak`},{score:20,class:`text-bg-danger`,text:`Weak`},{score:40,class:`text-bg-warning`,text:`Normal`},{score:60,class:`text-bg-success`,text:`Strong`},{score:80,class:`text-bg-success`,text:`Very Strong`}],container:null,scorer:T,striped:!1};#e;#t;#n;#r;#i;#a;static getStrength(e,t=this.defaults.commonPasswords){return T(e,t)}constructor(e,r){super(e,r);let i={...(0,t.getDataset)(e),...r};for(let e of[`levels`,`commonPasswords`])Array.isArray(i[e])&&(this.options[e].length=0,n.default._extend(this.options[e],i[e]));this.#n=this.node.form,this.#e=this.options.container?n.default.findOne(this.options.container):n.default.closest(this.node,`:not(.form-input):not(.input-group)`).shift(),this.#c(),this.#s(),this.#o()}dispose(){n.default.remove(this.#r),n.default.removeEvent(this.node,`input.ui.passwordstrength`),this.#n&&n.default.removeEvent(this.#n,`reset.ui.passwordstrength`,this.#a),this.#t===null?n.default.removeAttribute(this.node,`aria-describedby`):n.default.setAttribute(this.node,{"aria-describedby":this.#t}),this.#e=null,this.#n=null,this.#r=null,this.#i=null,this.#a=null,super.dispose()}getStrength(){let e=n.default.getValue(this.node),t=Number(this.options.scorer(e,this.options.commonPasswords));return Number.isFinite(t)?n.default._clamp(t,0,100):0}#o(){this.#n&&(this.#a=e=>{setTimeout(()=>{this.node&&!e.defaultPrevented&&this.#s()},0)},n.default.addEvent(this.#n,`reset.ui.passwordstrength`,this.#a)),n.default.addEvent(this.node,`input.ui.passwordstrength`,e=>{this.#s()})}#s(){let e=this.getStrength(),t=this.options.levels.findLast(t=>e>=t.score);n.default.setStyle(this.#i,{width:`${e}%`}),n.default.setAttribute(this.#i,{class:this.constructor.classes.progressBar,"aria-valuenow":e}),n.default.addClass(this.#i,t.class),this.options.striped&&n.default.addClass(this.#i,this.constructor.classes.progressBarStriped),n.default.setText(this.#i,t.text??``)}#c(){this.#t=n.default.getAttribute(this.node,`aria-describedby`),this.#r=n.default.create(`div`,{class:this.constructor.classes.progress});let e=(0,t.generateId)(`password-strength`);this.#i=n.default.create(`div`,{attributes:{id:e,role:`progressbar`,"aria-valuemin":0,"aria-valuemax":100}}),n.default.append(this.#r,this.#i),n.default.append(this.#e,this.#r);let r=[this.#t,e].filter(Boolean).join(` `);n.default.setAttribute(this.node,{"aria-describedby":r})}};(0,t.initComponent)(`passwordstrength`,E),e.PasswordStrength=E});
|
|
2
|
+
//# sourceMappingURL=frost-ui-passwordstrength.min.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["PasswordStrength","BaseComponent","constructor","node","options","super","this","_options","container","_container","$","findOne","closest","_node","_render","_refresh","_events","dispose","remove","_progress","removeEvent","removeAttribute","_progressBar","getStrength","value","getValue","findSequences","string","locations","sequences","sequence","i","length","current","next","distance","char","nextChar","charDistance","charCodeAt","push","defaults","levels","score","class","text","striped","classes","progress","progressBar","progressBarStriped","password","match","substring","upper","lower","numbers","symbols","dictionary","code","list","filter","v","repeats","Object","values","reduce","acc","count","matches","matchAll","Math","min","lowerPassword","toLowerCase","letterSequences","concat","numberSequences","_clamp","proto","prototype","addEvent","_","strength","nextLevel","level","setStyle","width","setAttribute","addClass","setText","create","id","generateId","attributes","role","append","initComponent"],"sources":["../src/password-strength.js","../src/static/helpers.js","../src/index.js","../src/prototype/events.js","../src/prototype/helpers.js","../src/prototype/render.js"],"sourcesContent":["import $ from '@fr0st/query';\nimport { BaseComponent } from '@fr0st/ui';\n\n/**\n * PasswordStrength Class\n * @class\n */\nexport default class PasswordStrength extends BaseComponent {\n /**\n * New PasswordStrength constructor.\n * @param {HTMLElement} node The input node.\n * @param {object} [options] The options to create the PasswordStrength with.\n */\n constructor(node, options) {\n super(node, options);\n\n if (this._options.container) {\n this._container = $.findOne(this._options.container);\n } else {\n this._container = $.closest(this._node, ':not(.form-input):not(.input-group)');\n }\n\n this._render();\n this._refresh();\n this._events();\n }\n\n /**\n * Dispose the PasswordStrength.\n */\n dispose() {\n $.remove(this._progress);\n $.removeEvent(this._node, 'input.ui.passwordstrength');\n $.removeAttribute(this._node, 'aria-describedby');\n\n this._container = null;\n this._progress = null;\n this._progressBar = null;\n\n super.dispose();\n }\n\n /**\n * Get the password strength.\n * @return {number} The password strength. (0, 100)\n */\n getStrength() {\n const value = $.getValue(this._node);\n\n return this.constructor.getStrength(value);\n }\n}\n","import $ from '@fr0st/query';\n\n/**\n * Find character sequences in a string.\n * @param {string} string The input string.\n * @param {array} locations The character locations.\n * @return {array} The character sequences.\n */\nfunction findSequences(string, locations) {\n const sequences = [];\n let sequence = [];\n\n for (let i = 0; i < locations.length - 1; i++) {\n const current = locations[i];\n const next = locations[i + 1];\n const distance = next - current;\n\n const char = string[current];\n const nextChar = string[next];\n const charDistance = nextChar.charCodeAt(0) - char.charCodeAt(0);\n\n if (distance === 1 && charDistance === 1) {\n if (!sequence.length) {\n sequence.push(char);\n }\n sequence.push(nextChar);\n } else if (sequence.length) {\n sequences.push(sequence);\n sequence = [];\n }\n }\n\n if (sequence.length) {\n sequences.push(sequence);\n }\n\n return sequences;\n};\n\n/**\n * Get the strength of a password.\n * @param {string} password The password.\n * @return {number} The password strength.\n */\nexport function getStrength(password) {\n if (password.match(/^password/i)) {\n password = password.substring(8);\n }\n\n const length = password.length;\n\n let score = 0;\n\n if (length) {\n score += length * 6;\n }\n\n const upper = [];\n const lower = [];\n const numbers = [];\n const symbols = [];\n const dictionary = {};\n\n for (let i = 0; i < length; i++) {\n const char = password[i];\n const code = char.charCodeAt(0);\n\n if (code >= 48 && code <= 57) {\n numbers.push(i);\n } else if (code >= 65 && code <= 90) {\n upper.push(i);\n } else if (code >= 97 && code <= 122) {\n lower.push(i);\n } else {\n symbols.push(i);\n }\n\n if (!(char in dictionary)) {\n dictionary[char] = 0;\n }\n\n dictionary[char]++;\n }\n\n // reward upper/lower case\n if (upper.length !== length && lower.length !== length) {\n if (upper.length) {\n score += length - upper.length;\n }\n\n if (lower.length) {\n score += length - lower.length;\n }\n }\n\n // reward numbers\n if (numbers.length !== length) {\n score += numbers.length * 3;\n }\n\n // reward symbols\n score += symbols.length * 6;\n\n // reward inner numbers/symbols\n for (const list of [numbers, symbols]) {\n const reward = list.filter((v) => v && v !== length - 1).length;\n score += reward * 3;\n }\n\n // punish only letters\n if (!numbers.length && !symbols.length) {\n score -= length;\n }\n\n // punish only numbers\n if (!upper.length && !lower.length && !symbols.length) {\n score -= length;\n }\n\n // punish no symbols\n if (!symbols.length) {\n score -= length;\n }\n\n // repeating characters\n const repeats = Object.values(dictionary)\n .reduce((acc, count) => acc + count - 1, 0);\n\n if (repeats > 0) {\n score -= repeats;\n }\n\n if (length >= 2) {\n // consecutive characters\n const matches = password.matchAll(/(.)\\1+/g);\n\n for (const match of matches) {\n score -= Math.min(match[0].length, 12) * 3;\n }\n\n const lowerPassword = password.toLowerCase();\n\n // sequential letters\n const letters = upper.concat(lower);\n const letterSequences = findSequences(lowerPassword, letters);\n for (const sequence of letterSequences) {\n if (sequence.length > 2) {\n score -= (Math.min(sequence.length - 2, 16)) * 3;\n }\n }\n\n // sequential numbers\n const numberSequences = findSequences(lowerPassword, numbers);\n for (const sequence of numberSequences) {\n if (sequence.length > 2) {\n score -= (Math.min(sequence.length - 2, 16)) * 3;\n }\n }\n }\n\n return $._clamp(score, 0, 100);\n};\n","import { initComponent } from '@fr0st/ui';\nimport PasswordStrength from './password-strength.js';\nimport { _events } from './prototype/events.js';\nimport { _refresh } from './prototype/helpers.js';\nimport { _render } from './prototype/render.js';\nimport { getStrength } from './static/helpers.js';\n\n// PasswordStrength default options\nPasswordStrength.defaults = {\n levels: [\n {\n score: 0,\n class: 'text-bg-danger',\n text: 'Very Weak',\n },\n {\n score: 20,\n class: 'text-bg-danger',\n text: 'Weak',\n },\n {\n score: 40,\n class: 'text-bg-warning',\n text: 'Normal',\n },\n {\n score: 60,\n class: 'text-bg-success',\n text: 'Strong',\n },\n {\n score: 80,\n class: 'text-bg-success',\n text: 'Very Strong',\n },\n ],\n container: null,\n striped: false,\n};\n\n// PasswordStrength classes\nPasswordStrength.classes = {\n progress: 'progress mt-2',\n progressBar: 'progress-bar',\n progressBarStriped: 'progress-bar-striped',\n};\n\n// PasswordStrength static\nPasswordStrength.getStrength = getStrength;\n\n// PasswordStrength prototype\nconst proto = PasswordStrength.prototype;\n\nproto._events = _events;\nproto._refresh = _refresh;\nproto._render = _render;\n\n// PasswordStrength init\ninitComponent('passwordstrength', PasswordStrength);\n\nexport default PasswordStrength;\n","import $ from '@fr0st/query';\n\n/**\n * Attach events for the PasswordStrength.\n */\nexport function _events() {\n $.addEvent(this._node, 'input.ui.passwordstrength', (_) => {\n this._refresh();\n });\n};\n","import $ from '@fr0st/query';\n\n/**\n * Refresh the password strength.\n */\nexport function _refresh() {\n const strength = this.getStrength();\n\n let nextLevel;\n for (const level of this._options.levels) {\n if (strength < level.score) {\n break;\n }\n\n nextLevel = level;\n }\n\n $.setStyle(this._progressBar, { width: `${strength}%` });\n $.setAttribute(this._progressBar, {\n 'class': this.constructor.classes.progressBar,\n 'aria-valuenow': strength,\n });\n\n $.addClass(this._progressBar, nextLevel.class);\n\n if (this._options.striped) {\n $.addClass(this._progressBar, this.constructor.classes.progressBarStriped);\n }\n\n if (nextLevel.text) {\n $.setText(this._progressBar, nextLevel.text);\n }\n};\n","import $ from '@fr0st/query';\nimport { generateId } from '@fr0st/ui';\n\n/**\n * Render the password strength element.\n */\nexport function _render() {\n this._progress = $.create('div', {\n class: this.constructor.classes.progress,\n });\n\n const id = generateId('password-strength');\n\n this._progressBar = $.create('div', {\n attributes: {\n 'id': id,\n 'role': 'progressbar',\n 'aria-valuemin': 0,\n 'aria-valuemax': 100,\n },\n });\n\n $.append(this._progress, this._progressBar);\n $.append(this._container, this._progress);\n\n $.setAttribute(this._node, {\n 'aria-describedby': id,\n });\n};\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"frost-ui-passwordstrength.min.js","names":["$","BaseComponent","getDataset","$","generateId"],"sources":["../src/strength.js","../src/password-strength.js","../src/index.js"],"sourcesContent":["import $ from '@fr0st/query';\n\nconst characterTypes = [\n { pattern: /\\p{Ll}/u, type: 'lower' },\n { pattern: /\\p{Lu}/u, type: 'upper' },\n { pattern: /\\p{N}/u, type: 'number' },\n];\n\nconst keyboardSequences = [\n '1234567890',\n 'qwertyuiop',\n 'asdfghjkl',\n 'zxcvbnm',\n].flatMap(\n (row) => [\n row,\n Array.from(row).reverse().join(''),\n ],\n);\n\nconst leetCharacters = {\n '$': 's',\n '0': 'o',\n '3': 'e',\n '4': 'a',\n '5': 's',\n '7': 't',\n '@': 'a',\n};\n\nconst lengthBands = [\n { end: 5, max: 19, min: 1, start: 1 },\n { end: 8, max: 39, min: 20, start: 6 },\n { end: 11, max: 59, min: 40, start: 9 },\n { end: 15, max: 79, min: 60, start: 12 },\n { end: 24, max: 100, min: 80, start: 16 },\n];\n\n/**\n * Gets the type of a password character.\n * @param {string} character The character.\n * @returns {string} The character type.\n */\nconst getCharacterType = (character) =>\n characterTypes.find(\n ({ pattern }) => pattern.test(character),\n )?.type || 'symbol';\n\n/**\n * Gets a length-based password strength.\n * @param {string[]} characters The password characters.\n * @returns {number} The password strength.\n */\nconst getLengthStrength = (characters) => {\n const band = lengthBands.find(\n ({ end }) => characters.length <= end,\n ) || lengthBands.at(-1);\n const score = Math.round(\n $._map(\n Math.min(characters.length, band.end),\n band.start,\n band.end,\n band.min,\n band.max,\n ),\n );\n const diversity = new Set(\n characters.map(getCharacterType),\n ).size;\n\n return Math.min(\n score +\n (diversity - 1) * 2,\n band.max,\n );\n};\n\n/**\n * Gets the smallest repeated pattern.\n * @param {string[]} characters The password characters.\n * @returns {string[]|null} The repeated pattern.\n */\nconst getRepeatedPattern = (characters) => {\n const maxLength = Math.floor(characters.length / 2);\n\n for (let length = 1; length <= maxLength; length++) {\n if (\n characters.length % length === 0 &&\n characters.every(\n (character, index) =>\n character === characters[index % length],\n )\n ) {\n return characters.slice(0, length);\n }\n }\n\n return null;\n};\n\n/**\n * Normalizes common password matching.\n * @param {string} password The password.\n * @returns {string} The normalized password.\n */\nconst normalizePassword = (password) =>\n String(password)\n .normalize('NFKC')\n .toLowerCase();\n\n/**\n * Normalizes common leet substitutions.\n * @param {string} password The password.\n * @returns {string} The normalized password.\n */\nconst normalizeLeet = (password) =>\n Array.from(\n password,\n (character) => leetCharacters[character] || character,\n ).join('');\n\n/**\n * Gets normalized variants used to match common passwords.\n * @param {string} password The normalized password.\n * @returns {Set<string>} The password variants.\n */\nconst getPasswordVariants = (password) => {\n // Preserve digits for decoration stripping while resolving symbol substitutions.\n const substituted = password.replace(/[^\\p{L}\\p{N}]/gu, normalizeLeet);\n const variants = [password, substituted].flatMap((value) => {\n const undecorated = value.replace(\n /^[^\\p{L}\\p{N}]+|[^\\p{L}\\p{N}]+$/gu,\n '',\n );\n\n return [\n undecorated,\n undecorated.replace(/^\\d+|\\d+$/g, ''),\n ];\n });\n\n return new Set([\n normalizeLeet(password),\n ...variants,\n ...variants.map(normalizeLeet),\n ]);\n};\n\n/**\n * Gets the score for a common password.\n * @param {string} password The normalized password.\n * @param {string[]} commonPasswords The common passwords.\n * @returns {number|null} The common-password score.\n */\nconst getCommonPasswordStrength = (password, commonPasswords) => {\n const common = new Set(\n commonPasswords.map(normalizePassword),\n );\n\n if (common.has(password)) {\n return 0;\n }\n\n return common.isDisjointFrom(getPasswordVariants(password)) ? null : 5;\n};\n\n/**\n * Checks whether characters form an ascending or descending sequence.\n * @param {string[]} characters The password characters.\n * @returns {boolean} Whether the characters form a sequence.\n */\nconst isSequence = (characters) => {\n const [first, second, third] = characters.map(\n (character) => character.toLowerCase(),\n );\n const type = getCharacterType(first);\n const direction = second.codePointAt(0) - first.codePointAt(0);\n\n return ['lower', 'number'].includes(type) &&\n getCharacterType(second) === type &&\n getCharacterType(third) === type &&\n Math.abs(direction) === 1 &&\n third.codePointAt(0) - second.codePointAt(0) === direction;\n};\n\n/**\n * Checks whether characters form a keyboard sequence.\n * @param {string[]} characters The password characters.\n * @returns {boolean} Whether the characters form a keyboard sequence.\n */\nconst isKeyboardSequence = (characters) => {\n const sequence = characters.join('').toLowerCase();\n\n return keyboardSequences.some(\n (keyboardSequence) => keyboardSequence.includes(sequence),\n );\n};\n\n/**\n * Checks whether characters form a predictable pattern.\n * @param {string[]} characters The password characters.\n * @returns {boolean} Whether the characters form a predictable pattern.\n */\nconst isPredictable = (characters) =>\n new Set(characters).size === 1 ||\n isSequence(characters) ||\n isKeyboardSequence(characters);\n\n/**\n * Gets the number of characters in predictable patterns.\n * @param {string[]} characters The password characters.\n * @returns {number} The number of predictable characters.\n */\nconst getPredictableCount = (characters) => {\n const indices = new Set();\n\n for (let i = 0; i + 2 < characters.length; i++) {\n if (isPredictable(characters.slice(i, i + 3))) {\n indices.add(i);\n indices.add(i + 1);\n indices.add(i + 2);\n }\n }\n\n return indices.size;\n};\n\n/**\n * Calculates the strength of a password.\n * @param {string} password The password.\n * @param {string[]} [commonPasswords=[]] Passwords to score as very weak.\n * @returns {number} The password strength, from 0 to 100.\n */\nexport const getStrength = (password, commonPasswords = []) => {\n const normalizedPassword = password.normalize('NFKC');\n const characters = Array.from(normalizedPassword);\n\n if (!characters.length) {\n return 0;\n }\n\n const commonStrength = getCommonPasswordStrength(\n normalizedPassword.toLowerCase(),\n commonPasswords,\n );\n\n if (commonStrength !== null) {\n return commonStrength;\n }\n\n const score = getLengthStrength(characters);\n const repeatedPattern = getRepeatedPattern(characters);\n\n if (repeatedPattern?.length === 1) {\n return 0;\n }\n\n if (repeatedPattern) {\n return Math.min(\n score,\n getLengthStrength(repeatedPattern),\n 15,\n );\n }\n\n const predictableCount = getPredictableCount(characters);\n\n return $._clamp(\n score - predictableCount,\n 0,\n predictableCount === characters.length ? 15 : 100,\n );\n};\n","import $ from '@fr0st/query';\nimport { BaseComponent, generateId, getDataset } from '@fr0st/ui';\nimport { getStrength } from './strength.js';\n\n/**\n * @typedef {object} PasswordStrengthLevel\n * @property {string} class The CSS class applied to the progress bar.\n * @property {number} score The minimum score for the level.\n * @property {string} [text] The label displayed in the progress bar.\n */\n\n/**\n * @callback PasswordStrengthScorer\n * @param {string} password The password.\n * @param {string[]} commonPasswords The common passwords.\n * @returns {number} The password strength, from 0 to 100.\n */\n\n/**\n * @typedef {object} PasswordStrengthOptions\n * @property {string[]} [commonPasswords] Passwords to score as very weak.\n * @property {string|null} [container=null] The selector for the progress container.\n * @property {PasswordStrengthLevel[]} [levels] The ordered password-strength levels.\n * @property {PasswordStrengthScorer} [scorer] Calculates the password strength.\n * @property {boolean} [striped=false] Whether to display a striped progress bar.\n */\n\n/**\n * Displays the strength of a password input as a progress bar.\n * @augments {BaseComponent<PasswordStrengthOptions>}\n */\nexport default class PasswordStrength extends BaseComponent {\n static classes = {\n progress: 'progress mt-2',\n progressBar: 'progress-bar',\n progressBarStriped: 'progress-bar-striped',\n };\n /** @type {PasswordStrengthOptions} */\n static defaults = {\n commonPasswords: [\n '123456',\n '12345678',\n '123456789',\n '1234567890',\n '000000',\n '111111',\n 'abc123',\n 'admin',\n 'dragon',\n 'iloveyou',\n 'letmein',\n 'monkey',\n 'password',\n 'password1',\n 'password123',\n 'qwerty',\n 'qwerty123',\n 'welcome',\n ],\n levels: [\n {\n score: 0,\n class: 'text-bg-danger',\n text: 'Very Weak',\n },\n {\n score: 20,\n class: 'text-bg-danger',\n text: 'Weak',\n },\n {\n score: 40,\n class: 'text-bg-warning',\n text: 'Normal',\n },\n {\n score: 60,\n class: 'text-bg-success',\n text: 'Strong',\n },\n {\n score: 80,\n class: 'text-bg-success',\n text: 'Very Strong',\n },\n ],\n container: null,\n scorer: getStrength,\n striped: false,\n };\n\n #container;\n #describedBy;\n #form;\n #progress;\n #progressBar;\n #resetHandler;\n\n /**\n * Calculates the strength of a password.\n * @param {string} password The password.\n * @param {string[]} [commonPasswords=this.defaults.commonPasswords] Passwords to score as very weak.\n * @returns {number} The password strength, from 0 to 100.\n */\n static getStrength(password, commonPasswords = this.defaults.commonPasswords) {\n return getStrength(password, commonPasswords);\n }\n\n /**\n * Creates a PasswordStrength.\n * @param {HTMLElement} node The input node.\n * @param {PasswordStrengthOptions} [options] The PasswordStrength options.\n */\n constructor(node, options) {\n super(node, options);\n\n const overrides = { ...getDataset(node), ...options };\n\n // Replace supplied arrays instead of merging them with default entries.\n for (const key of ['levels', 'commonPasswords']) {\n if (Array.isArray(overrides[key])) {\n this.options[key].length = 0;\n $._extend(this.options[key], overrides[key]);\n }\n }\n\n this.#form = this.node.form;\n\n if (this.options.container) {\n this.#container = $.findOne(this.options.container);\n } else {\n this.#container = $.closest(this.node, ':not(.form-input):not(.input-group)').shift();\n }\n\n this.#render();\n this.#refresh();\n this.#events();\n }\n\n /** @inheritdoc */\n dispose() {\n $.remove(this.#progress);\n $.removeEvent(this.node, 'input.ui.passwordstrength');\n\n if (this.#form) {\n $.removeEvent(this.#form, 'reset.ui.passwordstrength', this.#resetHandler);\n }\n\n if (this.#describedBy === null) {\n $.removeAttribute(this.node, 'aria-describedby');\n } else {\n $.setAttribute(this.node, { 'aria-describedby': this.#describedBy });\n }\n\n this.#container = null;\n this.#form = null;\n this.#progress = null;\n this.#progressBar = null;\n this.#resetHandler = null;\n\n super.dispose();\n }\n\n /**\n * Gets the password strength.\n * @returns {number} The password strength, from 0 to 100.\n */\n getStrength() {\n const value = $.getValue(this.node);\n const strength = Number(this.options.scorer(\n value,\n this.options.commonPasswords,\n ));\n\n return Number.isFinite(strength) ?\n $._clamp(strength, 0, 100) :\n 0;\n }\n\n /**\n * Attaches events for the PasswordStrength.\n */\n #events() {\n if (this.#form) {\n this.#resetHandler = (event) => {\n setTimeout(() => {\n if (this.node && !event.defaultPrevented) {\n this.#refresh();\n }\n }, 0);\n };\n\n $.addEvent(this.#form, 'reset.ui.passwordstrength', this.#resetHandler);\n }\n\n $.addEvent(this.node, 'input.ui.passwordstrength', (_) => {\n this.#refresh();\n });\n }\n\n /**\n * Refreshes the password strength.\n */\n #refresh() {\n const strength = this.getStrength();\n\n const nextLevel = this.options.levels.findLast(\n (level) => strength >= level.score,\n );\n\n $.setStyle(this.#progressBar, { width: `${strength}%` });\n $.setAttribute(this.#progressBar, {\n 'class': this.constructor.classes.progressBar,\n 'aria-valuenow': strength,\n });\n\n $.addClass(this.#progressBar, nextLevel.class);\n\n if (this.options.striped) {\n $.addClass(this.#progressBar, this.constructor.classes.progressBarStriped);\n }\n\n $.setText(this.#progressBar, nextLevel.text ?? '');\n }\n\n /**\n * Renders the password strength element.\n */\n #render() {\n this.#describedBy = $.getAttribute(this.node, 'aria-describedby');\n this.#progress = $.create('div', {\n class: this.constructor.classes.progress,\n });\n\n const id = generateId('password-strength');\n\n this.#progressBar = $.create('div', {\n attributes: {\n 'id': id,\n 'role': 'progressbar',\n 'aria-valuemin': 0,\n 'aria-valuemax': 100,\n },\n });\n\n $.append(this.#progress, this.#progressBar);\n $.append(this.#container, this.#progress);\n\n const describedBy = [this.#describedBy, id]\n .filter(Boolean)\n .join(' ');\n\n $.setAttribute(this.node, { 'aria-describedby': describedBy });\n }\n}\n","import { initComponent } from '@fr0st/ui';\nimport PasswordStrength from './password-strength.js';\n\ninitComponent('passwordstrength', PasswordStrength);\n\nexport default PasswordStrength;\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,22 +1,43 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fr0st/ui-passwordstrength",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Password strength indicator component for Frost UI with customizable levels, labels, and striped progress styling.",
|
|
5
6
|
"keywords": [
|
|
6
|
-
"ui",
|
|
7
7
|
"component",
|
|
8
|
+
"frost",
|
|
9
|
+
"frontend",
|
|
10
|
+
"javascript",
|
|
8
11
|
"password",
|
|
12
|
+
"password-strength",
|
|
13
|
+
"security",
|
|
9
14
|
"strength",
|
|
10
|
-
"
|
|
11
|
-
"web"
|
|
15
|
+
"ui"
|
|
12
16
|
],
|
|
13
|
-
"homepage": "https://github.com/
|
|
17
|
+
"homepage": "https://github.com/frost-js/ui-passwordstrength",
|
|
14
18
|
"bugs": {
|
|
15
|
-
"url": "https://github.com/
|
|
19
|
+
"url": "https://github.com/frost-js/ui-passwordstrength/issues",
|
|
16
20
|
"email": "elusivecodes@gmail.com"
|
|
17
21
|
},
|
|
18
|
-
"
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/frost-js/ui-passwordstrength.git"
|
|
25
|
+
},
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"author": "Elusive <elusivecodes@gmail.com>",
|
|
19
28
|
"type": "module",
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"import": "./dist/frost-ui-passwordstrength.esm.js",
|
|
32
|
+
"default": "./dist/frost-ui-passwordstrength.esm.js"
|
|
33
|
+
},
|
|
34
|
+
"./dist/*": "./dist/*",
|
|
35
|
+
"./src/*": "./src/*"
|
|
36
|
+
},
|
|
37
|
+
"main": "./dist/frost-ui-passwordstrength.esm.js",
|
|
38
|
+
"jsdelivr": "./dist/frost-ui-passwordstrength.min.js",
|
|
39
|
+
"unpkg": "./dist/frost-ui-passwordstrength.min.js",
|
|
40
|
+
"module": "./dist/frost-ui-passwordstrength.esm.js",
|
|
20
41
|
"files": [
|
|
21
42
|
"dist",
|
|
22
43
|
"LICENSE",
|
|
@@ -24,23 +45,34 @@
|
|
|
24
45
|
"src"
|
|
25
46
|
],
|
|
26
47
|
"scripts": {
|
|
27
|
-
"build": "
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
48
|
+
"build": "vite build && vite build --mode umd",
|
|
49
|
+
"lint": "eslint",
|
|
50
|
+
"test": "npm run build && npm run test:browser",
|
|
51
|
+
"test:browser": "playwright test --forbid-only",
|
|
52
|
+
"test:coverage": "playwright test --config=playwright.coverage.config.js --forbid-only",
|
|
53
|
+
"test:headed": "playwright test --forbid-only --headed",
|
|
54
|
+
"test:ui": "playwright test --ui"
|
|
31
55
|
},
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
},
|
|
36
|
-
"author": "Elusive",
|
|
37
|
-
"license": "MIT",
|
|
38
|
-
"private": false,
|
|
56
|
+
"browserslist": [
|
|
57
|
+
"baseline newly available"
|
|
58
|
+
],
|
|
39
59
|
"devDependencies": {
|
|
40
|
-
"@fr0st/eslint-config": "^
|
|
41
|
-
"@
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
60
|
+
"@fr0st/eslint-config": "^5.0.3",
|
|
61
|
+
"@fr0st/query": "^5.0.0",
|
|
62
|
+
"@fr0st/ui": "^4.0.0",
|
|
63
|
+
"@playwright/test": "^1.63.0",
|
|
64
|
+
"eslint": "^10.10.0",
|
|
65
|
+
"monocart-reporter": "^2.13.1",
|
|
66
|
+
"vite": "^8.3.0"
|
|
67
|
+
},
|
|
68
|
+
"peerDependencies": {
|
|
69
|
+
"@fr0st/query": "^5.0.0",
|
|
70
|
+
"@fr0st/ui": "^4.0.0"
|
|
71
|
+
},
|
|
72
|
+
"engines": {
|
|
73
|
+
"node": "^20.19.0 || ^22.13.0 || >=24"
|
|
74
|
+
},
|
|
75
|
+
"publishConfig": {
|
|
76
|
+
"access": "public"
|
|
45
77
|
}
|
|
46
|
-
}
|
|
78
|
+
}
|
|
File without changes
|
package/src/index.js
CHANGED
|
@@ -1,61 +1,6 @@
|
|
|
1
1
|
import { initComponent } from '@fr0st/ui';
|
|
2
2
|
import PasswordStrength from './password-strength.js';
|
|
3
|
-
import { _events } from './prototype/events.js';
|
|
4
|
-
import { _refresh } from './prototype/helpers.js';
|
|
5
|
-
import { _render } from './prototype/render.js';
|
|
6
|
-
import { getStrength } from './static/helpers.js';
|
|
7
3
|
|
|
8
|
-
// PasswordStrength default options
|
|
9
|
-
PasswordStrength.defaults = {
|
|
10
|
-
levels: [
|
|
11
|
-
{
|
|
12
|
-
score: 0,
|
|
13
|
-
class: 'text-bg-danger',
|
|
14
|
-
text: 'Very Weak',
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
score: 20,
|
|
18
|
-
class: 'text-bg-danger',
|
|
19
|
-
text: 'Weak',
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
score: 40,
|
|
23
|
-
class: 'text-bg-warning',
|
|
24
|
-
text: 'Normal',
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
score: 60,
|
|
28
|
-
class: 'text-bg-success',
|
|
29
|
-
text: 'Strong',
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
score: 80,
|
|
33
|
-
class: 'text-bg-success',
|
|
34
|
-
text: 'Very Strong',
|
|
35
|
-
},
|
|
36
|
-
],
|
|
37
|
-
container: null,
|
|
38
|
-
striped: false,
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
// PasswordStrength classes
|
|
42
|
-
PasswordStrength.classes = {
|
|
43
|
-
progress: 'progress mt-2',
|
|
44
|
-
progressBar: 'progress-bar',
|
|
45
|
-
progressBarStriped: 'progress-bar-striped',
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
// PasswordStrength static
|
|
49
|
-
PasswordStrength.getStrength = getStrength;
|
|
50
|
-
|
|
51
|
-
// PasswordStrength prototype
|
|
52
|
-
const proto = PasswordStrength.prototype;
|
|
53
|
-
|
|
54
|
-
proto._events = _events;
|
|
55
|
-
proto._refresh = _refresh;
|
|
56
|
-
proto._render = _render;
|
|
57
|
-
|
|
58
|
-
// PasswordStrength init
|
|
59
4
|
initComponent('passwordstrength', PasswordStrength);
|
|
60
5
|
|
|
61
6
|
export default PasswordStrength;
|