New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@zxcvbn-ts/core

Package Overview
Dependencies
Maintainers
1
Versions
24
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@zxcvbn-ts/core - npm Package Compare versions

Comparing version 2.1.0 to 2.2.0

dist/matcher/dictionary/types.d.ts

8

dist/data/const.esm.js

@@ -10,7 +10,7 @@ import dateSplits from './dateSplits.esm.js';

const MIN_SUBMATCH_GUESSES_MULTI_CHAR = 50;
const MIN_YEAR_SPACE = 20; // \xbf-\xdf is a range for almost all special uppercase letter like Ä and so on
const MIN_YEAR_SPACE = 20;
// \xbf-\xdf is a range for almost all special uppercase letter like Ä and so on
const START_UPPER = /^[A-Z\xbf-\xdf][^A-Z\xbf-\xdf]+$/;
const END_UPPER = /^[^A-Z\xbf-\xdf]+[A-Z\xbf-\xdf]$/; // \xdf-\xff is a range for almost all special lowercase letter like ä and so on
const END_UPPER = /^[^A-Z\xbf-\xdf]+[A-Z\xbf-\xdf]$/;
// \xdf-\xff is a range for almost all special lowercase letter like ä and so on
const ALL_UPPER = /^[A-Z\xbf-\xdf]+$/;

@@ -17,0 +17,0 @@ const ALL_UPPER_INVERTED = /^[^a-z\xdf-\xff]+$/;

'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var dateSplits = require('./dateSplits.js');

@@ -14,7 +12,7 @@

const MIN_SUBMATCH_GUESSES_MULTI_CHAR = 50;
const MIN_YEAR_SPACE = 20; // \xbf-\xdf is a range for almost all special uppercase letter like Ä and so on
const MIN_YEAR_SPACE = 20;
// \xbf-\xdf is a range for almost all special uppercase letter like Ä and so on
const START_UPPER = /^[A-Z\xbf-\xdf][^A-Z\xbf-\xdf]+$/;
const END_UPPER = /^[^A-Z\xbf-\xdf]+[A-Z\xbf-\xdf]$/; // \xdf-\xff is a range for almost all special lowercase letter like ä and so on
const END_UPPER = /^[^A-Z\xbf-\xdf]+[A-Z\xbf-\xdf]$/;
// \xdf-\xff is a range for almost all special lowercase letter like ä and so on
const ALL_UPPER = /^[A-Z\xbf-\xdf]+$/;

@@ -21,0 +19,0 @@ const ALL_UPPER_INVERTED = /^[^a-z\xdf-\xff]+$/;

var dateSplits = {
4: [// for length-4 strings, eg 1191 or 9111, two ways to split:
4: [
// for length-4 strings, eg 1191 or 9111, two ways to split:
[1, 2], [2, 3] // 91 1 1
],
5: [[1, 3], [2, 3], // [2, 3], // 91 1 11 <- duplicate previous one
5: [[1, 3], [2, 3],
// [2, 3], // 91 1 11 <- duplicate previous one
[2, 4] // 91 11 1 <- New and must be added as bug fix
],
6: [[1, 2], [2, 4], [4, 5] // 1991 1 1
],
// 1111991
7: [[1, 3], [2, 3], [4, 5], [4, 6] // 1991 11 1
],
8: [[2, 4], [4, 6] // 1991 11 11

@@ -14,0 +20,0 @@ ]

'use strict';
var dateSplits = {
4: [// for length-4 strings, eg 1191 or 9111, two ways to split:
4: [
// for length-4 strings, eg 1191 or 9111, two ways to split:
[1, 2], [2, 3] // 91 1 1
],
5: [[1, 3], [2, 3], // [2, 3], // 91 1 11 <- duplicate previous one
5: [[1, 3], [2, 3],
// [2, 3], // 91 1 11 <- duplicate previous one
[2, 4] // 91 11 1 <- New and must be added as bug fix
],
6: [[1, 2], [2, 4], [4, 5] // 1991 1 1
],
// 1111991
7: [[1, 3], [2, 3], [4, 5], [4, 6] // 1991 11 1
],
8: [[2, 4], [4, 6] // 1991 11 11

@@ -16,0 +22,0 @@ ]

@@ -1,2 +0,2 @@

export declare type Procedure = (...args: any[]) => void;
export type Procedure = (...args: any[]) => void;
/**

@@ -3,0 +3,0 @@ * @link https://davidwalsh.name/javascript-debounce-function

@@ -8,6 +8,4 @@ /**

const context = this;
const later = () => {
timeout = undefined;
if (!isImmediate) {

@@ -17,15 +15,10 @@ func.apply(context, args);

};
const shouldCallNow = isImmediate && !timeout;
if (timeout !== undefined) {
clearTimeout(timeout);
}
timeout = setTimeout(later, wait);
if (shouldCallNow) {
return func.apply(context, args);
}
return undefined;

@@ -32,0 +25,0 @@ };

@@ -10,6 +10,4 @@ 'use strict';

const context = this;
const later = () => {
timeout = undefined;
if (!isImmediate) {

@@ -19,15 +17,10 @@ func.apply(context, args);

};
const shouldCallNow = isImmediate && !timeout;
if (timeout !== undefined) {
clearTimeout(timeout);
}
timeout = setTimeout(later, wait);
if (shouldCallNow) {
return func.apply(context, args);
}
return undefined;

@@ -34,0 +27,0 @@ };

import { DefaultFeedbackFunction, FeedbackType, MatchEstimated } from './types';
declare type Matchers = {
type Matchers = {
[key: string]: DefaultFeedbackFunction;

@@ -12,4 +12,4 @@ };

getLongestMatch(sequence: MatchEstimated[]): MatchEstimated;
getMatchFeedback(match: MatchEstimated, isSoleMatch: Boolean): FeedbackType | null;
getMatchFeedback(match: MatchEstimated, isSoleMatch: boolean): FeedbackType | null;
}
export default Feedback;

@@ -19,3 +19,2 @@ import zxcvbnOptions from './Options.esm.js';

*/
class Feedback {

@@ -38,7 +37,5 @@ constructor() {

}
setDefaultSuggestions() {
this.defaultFeedback.suggestions.push(zxcvbnOptions.translations.suggestions.useWords, zxcvbnOptions.translations.suggestions.noNeed);
}
getFeedback(score, sequence) {

@@ -48,14 +45,10 @@ if (sequence.length === 0) {

}
if (score > 2) {
return defaultFeedback;
}
const extraFeedback = zxcvbnOptions.translations.suggestions.anotherWord;
const longestMatch = this.getLongestMatch(sequence);
let feedback = this.getMatchFeedback(longestMatch, sequence.length === 1);
if (feedback !== null && feedback !== undefined) {
feedback.suggestions.unshift(extraFeedback);
if (feedback.warning == null) {

@@ -70,6 +63,4 @@ feedback.warning = '';

}
return feedback;
}
getLongestMatch(sequence) {

@@ -85,3 +76,2 @@ let longestMatch = sequence[0];

}
getMatchFeedback(match, isSoleMatch) {

@@ -91,10 +81,7 @@ if (this.matchers[match.pattern]) {

}
if (zxcvbnOptions.matchers[match.pattern] && 'feedback' in zxcvbnOptions.matchers[match.pattern]) {
return zxcvbnOptions.matchers[match.pattern].feedback(match, isSoleMatch);
}
return defaultFeedback;
}
}

@@ -101,0 +88,0 @@

@@ -21,3 +21,2 @@ 'use strict';

*/
class Feedback {

@@ -40,7 +39,5 @@ constructor() {

}
setDefaultSuggestions() {
this.defaultFeedback.suggestions.push(Options["default"].translations.suggestions.useWords, Options["default"].translations.suggestions.noNeed);
this.defaultFeedback.suggestions.push(Options.default.translations.suggestions.useWords, Options.default.translations.suggestions.noNeed);
}
getFeedback(score, sequence) {

@@ -50,14 +47,10 @@ if (sequence.length === 0) {

}
if (score > 2) {
return defaultFeedback;
}
const extraFeedback = Options["default"].translations.suggestions.anotherWord;
const extraFeedback = Options.default.translations.suggestions.anotherWord;
const longestMatch = this.getLongestMatch(sequence);
let feedback = this.getMatchFeedback(longestMatch, sequence.length === 1);
if (feedback !== null && feedback !== undefined) {
feedback.suggestions.unshift(extraFeedback);
if (feedback.warning == null) {

@@ -72,6 +65,4 @@ feedback.warning = '';

}
return feedback;
}
getLongestMatch(sequence) {

@@ -87,3 +78,2 @@ let longestMatch = sequence[0];

}
getMatchFeedback(match, isSoleMatch) {

@@ -93,10 +83,7 @@ if (this.matchers[match.pattern]) {

}
if (Options["default"].matchers[match.pattern] && 'feedback' in Options["default"].matchers[match.pattern]) {
return Options["default"].matchers[match.pattern].feedback(match, isSoleMatch);
if (Options.default.matchers[match.pattern] && 'feedback' in Options.default.matchers[match.pattern]) {
return Options.default.matchers[match.pattern].feedback(match, isSoleMatch);
}
return defaultFeedback;
}
}

@@ -103,0 +90,0 @@

const empty = obj => Object.keys(obj).length === 0;
const extend = (listToExtend, list) => // eslint-disable-next-line prefer-spread
const extend = (listToExtend, list) =>
// eslint-disable-next-line prefer-spread
listToExtend.push.apply(listToExtend, list);

@@ -7,4 +8,4 @@ const translate = (string, chrMap) => {

return tempArray.map(char => chrMap[char] || char).join('');
}; // mod implementation that works for negative numbers
};
// sort on i primary, j secondary
const sorted = matches => matches.sort((m1, m2) => m1.i - m2.i || m1.j - m2.j);

@@ -14,3 +15,2 @@ const buildRankedDictionary = orderedList => {

let counter = 1; // rank starts at 1, not 0
orderedList.forEach(word => {

@@ -17,0 +17,0 @@ result[word] = counter;

'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
const empty = obj => Object.keys(obj).length === 0;
const extend = (listToExtend, list) => // eslint-disable-next-line prefer-spread
const extend = (listToExtend, list) =>
// eslint-disable-next-line prefer-spread
listToExtend.push.apply(listToExtend, list);

@@ -11,4 +10,4 @@ const translate = (string, chrMap) => {

return tempArray.map(char => chrMap[char] || char).join('');
}; // mod implementation that works for negative numbers
};
// sort on i primary, j secondary
const sorted = matches => matches.sort((m1, m2) => m1.i - m2.i || m1.j - m2.j);

@@ -18,3 +17,2 @@ const buildRankedDictionary = orderedList => {

let counter = 1; // rank starts at 1, not 0
orderedList.forEach(word => {

@@ -21,0 +19,0 @@ result[word] = counter;

@@ -1,6 +0,6 @@

import zxcvbnOptions from './Options';
import zxcvbnOptions, { Options } from './Options';
import debounce from './debounce';
import { ZxcvbnResult } from './types';
import { MatchExtended, ZxcvbnResult, Matcher, MatchOptions } from './types';
export declare const zxcvbn: (password: string, userInputs?: (string | number)[]) => ZxcvbnResult;
export declare const zxcvbnAsync: (password: string, userInputs?: (string | number)[]) => Promise<ZxcvbnResult>;
export { zxcvbnOptions, ZxcvbnResult, debounce };
export { zxcvbnOptions, ZxcvbnResult, debounce, Options, Matcher, MatchOptions, MatchExtended, };

@@ -6,7 +6,6 @@ import Matching from './Matching.esm.js';

import zxcvbnOptions from './Options.esm.js';
export { default as zxcvbnOptions } from './Options.esm.js';
export { Options } from './Options.esm.js';
export { default as debounce } from './debounce.esm.js';
const time = () => new Date().getTime();
const createReturnValue = (resolvedMatches, password, start) => {

@@ -25,3 +24,2 @@ const feedback = new Feedback();

};
const main = (password, userInputs) => {

@@ -31,15 +29,11 @@ if (userInputs) {

}
const matching = new Matching();
return matching.match(password);
};
const zxcvbn = (password, userInputs) => {
const start = time();
const matches = main(password, userInputs);
if (matches instanceof Promise) {
throw new Error('You are using a Promised matcher, please use `zxcvbnAsync` for it.');
}
return createReturnValue(matches, password, start);

@@ -53,3 +47,3 @@ };

export { zxcvbn, zxcvbnAsync };
export { zxcvbn, zxcvbnAsync, zxcvbnOptions };
//# sourceMappingURL=index.esm.js.map
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var Matching = require('./Matching.js');

@@ -13,3 +11,2 @@ var index = require('./scoring/index.js');

const time = () => new Date().getTime();
const createReturnValue = (resolvedMatches, password, start) => {

@@ -28,20 +25,15 @@ const feedback = new Feedback();

};
const main = (password, userInputs) => {
if (userInputs) {
Options["default"].extendUserInputsDictionary(userInputs);
Options.default.extendUserInputsDictionary(userInputs);
}
const matching = new Matching();
return matching.match(password);
};
const zxcvbn = (password, userInputs) => {
const start = time();
const matches = main(password, userInputs);
if (matches instanceof Promise) {
throw new Error('You are using a Promised matcher, please use `zxcvbnAsync` for it.');
}
return createReturnValue(matches, password, start);

@@ -55,3 +47,4 @@ };

exports.zxcvbnOptions = Options["default"];
exports.Options = Options.Options;
exports.zxcvbnOptions = Options.default;
exports.debounce = debounce;

@@ -58,0 +51,0 @@ exports.zxcvbn = zxcvbn;

@@ -1,2 +0,2 @@

import { distance } from './vendor/fastest-levenshtein.esm.js';
import { distance } from 'fastest-levenshtein';

@@ -6,7 +6,6 @@ const getUsedThreshold = (password, entry, threshold) => {

const isThresholdLongerThanPassword = password.length <= threshold;
const shouldUsePasswordLength = isPasswordToShort || isThresholdLongerThanPassword; // if password is too small use the password length divided by 4 while the threshold needs to be at least 1
const shouldUsePasswordLength = isPasswordToShort || isThresholdLongerThanPassword;
// if password is too small use the password length divided by 4 while the threshold needs to be at least 1
return shouldUsePasswordLength ? Math.ceil(password.length / 4) : threshold;
};
const findLevenshteinDistance = (password, rankedDictionary, threshold) => {

@@ -18,10 +17,7 @@ let foundDistance = 0;

const isInThreshold = foundEntryDistance <= usedThreshold;
if (isInThreshold) {
foundDistance = foundEntryDistance;
}
return isInThreshold;
});
if (found) {

@@ -33,3 +29,2 @@ return {

}
return {};

@@ -36,0 +31,0 @@ };

'use strict';
var fastestLevenshtein = require('./vendor/fastest-levenshtein.js');
var fastestLevenshtein = require('fastest-levenshtein');

@@ -8,7 +8,6 @@ const getUsedThreshold = (password, entry, threshold) => {

const isThresholdLongerThanPassword = password.length <= threshold;
const shouldUsePasswordLength = isPasswordToShort || isThresholdLongerThanPassword; // if password is too small use the password length divided by 4 while the threshold needs to be at least 1
const shouldUsePasswordLength = isPasswordToShort || isThresholdLongerThanPassword;
// if password is too small use the password length divided by 4 while the threshold needs to be at least 1
return shouldUsePasswordLength ? Math.ceil(password.length / 4) : threshold;
};
const findLevenshteinDistance = (password, rankedDictionary, threshold) => {

@@ -20,10 +19,7 @@ let foundDistance = 0;

const isInThreshold = foundEntryDistance <= usedThreshold;
if (isInThreshold) {
foundDistance = foundEntryDistance;
}
return isInThreshold;
});
if (found) {

@@ -35,3 +31,2 @@ return {

}
return {};

@@ -38,0 +33,0 @@ };

@@ -7,10 +7,8 @@ import { BRUTEFORCE_CARDINALITY, MIN_SUBMATCH_GUESSES_SINGLE_CHAR, MIN_SUBMATCH_GUESSES_MULTI_CHAR } from '../../data/const.esm.js';

let guesses = BRUTEFORCE_CARDINALITY ** token.length;
if (guesses === Number.POSITIVE_INFINITY) {
guesses = Number.MAX_VALUE;
}
let minGuesses; // small detail: make bruteforce matches at minimum one guess bigger than smallest allowed
let minGuesses;
// small detail: make bruteforce matches at minimum one guess bigger than smallest allowed
// submatch guesses, such that non-bruteforce submatches over the same [i..j] take precedence.
if (token.length === 1) {

@@ -21,3 +19,2 @@ minGuesses = MIN_SUBMATCH_GUESSES_SINGLE_CHAR + 1;

}
return Math.max(guesses, minGuesses);

@@ -24,0 +21,0 @@ });

@@ -9,10 +9,8 @@ 'use strict';

let guesses = _const.BRUTEFORCE_CARDINALITY ** token.length;
if (guesses === Number.POSITIVE_INFINITY) {
guesses = Number.MAX_VALUE;
}
let minGuesses; // small detail: make bruteforce matches at minimum one guess bigger than smallest allowed
let minGuesses;
// small detail: make bruteforce matches at minimum one guess bigger than smallest allowed
// submatch guesses, such that non-bruteforce submatches over the same [i..j] take precedence.
if (token.length === 1) {

@@ -23,3 +21,2 @@ minGuesses = _const.MIN_SUBMATCH_GUESSES_SINGLE_CHAR + 1;

}
return Math.max(guesses, minGuesses);

@@ -26,0 +23,0 @@ });

@@ -7,4 +7,4 @@ 'use strict';

return {
warning: Options["default"].translations.warnings.dates,
suggestions: [Options["default"].translations.suggestions.dates]
warning: Options.default.translations.warnings.dates,
suggestions: [Options.default.translations.suggestions.dates]
};

@@ -11,0 +11,0 @@ });

@@ -9,3 +9,2 @@ import { DATE_MIN_YEAR, DATE_MAX_YEAR, REFERENCE_YEAR, DATE_SPLITS } from '../../data/const.esm.js';

*/
class MatchDate {

@@ -39,7 +38,6 @@ /*

}
getMatchesWithSeparator(password) {
const matches = [];
const maybeDateWithSeparator = /^(\d{1,4})([\s/\\_.-])(\d{1,2})\2(\d{1,4})$/; // # dates with separators are between length 6 '1/1/91' and 10 '11/11/1991'
const maybeDateWithSeparator = /^(\d{1,4})([\s/\\_.-])(\d{1,2})\2(\d{1,4})$/;
// # dates with separators are between length 6 '1/1/91' and 10 '11/11/1991'
for (let i = 0; i <= Math.abs(password.length - 6); i += 1) {

@@ -50,9 +48,6 @@ for (let j = i + 5; j <= i + 9; j += 1) {

}
const token = password.slice(i, +j + 1 || 9e9);
const regexMatch = maybeDateWithSeparator.exec(token);
if (regexMatch != null) {
const dmy = this.mapIntegersToDayMonthYear([parseInt(regexMatch[1], 10), parseInt(regexMatch[3], 10), parseInt(regexMatch[4], 10)]);
if (dmy != null) {

@@ -73,14 +68,10 @@ matches.push({

}
return matches;
} // eslint-disable-next-line max-statements
}
// eslint-disable-next-line max-statements
getMatchesWithoutSeparator(password) {
const matches = [];
const maybeDateNoSeparator = /^\d{4,8}$/;
const metric = candidate => Math.abs(candidate.year - REFERENCE_YEAR); // # dates without separators are between length 4 '1191' and 8 '11111991'
const metric = candidate => Math.abs(candidate.year - REFERENCE_YEAR);
// # dates without separators are between length 4 '1191' and 8 '11111991'
for (let i = 0; i <= Math.abs(password.length - 4); i += 1) {

@@ -91,5 +82,3 @@ for (let j = i + 3; j <= i + 7; j += 1) {

}
const token = password.slice(i, +j + 1 || 9e9);
if (maybeDateNoSeparator.exec(token)) {

@@ -101,3 +90,2 @@ const candidates = [];

const dmy = this.mapIntegersToDayMonthYear([parseInt(token.slice(0, k), 10), parseInt(token.slice(k, l), 10), parseInt(token.slice(l), 10)]);
if (dmy != null) {

@@ -107,3 +95,2 @@ candidates.push(dmy);

});
if (candidates.length > 0) {

@@ -123,3 +110,2 @@ /*

const distance = metric(candidate);
if (distance < minDistance) {

@@ -144,3 +130,2 @@ bestCandidate = candidate;

}
return matches;

@@ -157,4 +142,2 @@ }

*/
filterNoise(matches) {

@@ -164,6 +147,4 @@ return matches.filter(match => {

const matchesLength = matches.length;
for (let o = 0; o < matchesLength; o += 1) {
const otherMatch = matches[o];
if (match !== otherMatch) {

@@ -176,3 +157,2 @@ if (otherMatch.i <= match.i && otherMatch.j >= match.j) {

}
return !isSubmatch;

@@ -192,4 +172,2 @@ });

// eslint-disable-next-line complexity, max-statements
mapIntegersToDayMonthYear(integers) {

@@ -199,22 +177,16 @@ if (integers[1] > 31 || integers[1] <= 0) {

}
let over12 = 0;
let over31 = 0;
let under1 = 0;
for (let o = 0, len1 = integers.length; o < len1; o += 1) {
const int = integers[o];
if (int > 99 && int < DATE_MIN_YEAR || int > DATE_MAX_YEAR) {
return null;
}
if (int > 31) {
over31 += 1;
}
if (int > 12) {
over12 += 1;
}
if (int <= 0) {

@@ -224,11 +196,8 @@ under1 += 1;

}
if (over31 >= 2 || over12 === 3 || under1 >= 2) {
return null;
}
return this.getDayMonth(integers);
} // eslint-disable-next-line max-statements
}
// eslint-disable-next-line max-statements
getDayMonth(integers) {

@@ -238,10 +207,8 @@ // first look for a four digit year: yyyy + daymonth or daymonth + yyyy

];
const possibleYearSplitsLength = possibleYearSplits.length;
for (let j = 0; j < possibleYearSplitsLength; j += 1) {
const [y, rest] = possibleYearSplits[j];
if (DATE_MIN_YEAR <= y && y <= DATE_MAX_YEAR) {
const dm = this.mapIntegersToDayMonth(rest);
if (dm != null) {

@@ -259,14 +226,10 @@ return {

*/
return null;
}
} // given no four-digit year, two digit years are the most flexible int to match, so
}
// given no four-digit year, two digit years are the most flexible int to match, so
// try to parse a day-month out of integers[0..1] or integers[1..0]
for (let k = 0; k < possibleYearSplitsLength; k += 1) {
const [y, rest] = possibleYearSplits[k];
const dm = this.mapIntegersToDayMonth(rest);
if (dm != null) {

@@ -280,9 +243,6 @@ return {

}
return null;
}
mapIntegersToDayMonth(integers) {
const temp = [integers, integers.slice().reverse()];
for (let i = 0; i < temp.length; i += 1) {

@@ -292,3 +252,2 @@ const data = temp[i];

const month = data[1];
if (day >= 1 && day <= 31 && month >= 1 && month <= 12) {

@@ -301,6 +260,4 @@ return {

}
return null;
}
twoToFourDigitYear(year) {

@@ -310,12 +267,9 @@ if (year > 99) {

}
if (year > 50) {
// 87 -> 1987
return year + 1900;
} // 15 -> 2015
}
// 15 -> 2015
return year + 2000;
}
}

@@ -322,0 +276,0 @@

@@ -11,3 +11,2 @@ 'use strict';

*/
class MatchDate {

@@ -41,7 +40,6 @@ /*

}
getMatchesWithSeparator(password) {
const matches = [];
const maybeDateWithSeparator = /^(\d{1,4})([\s/\\_.-])(\d{1,2})\2(\d{1,4})$/; // # dates with separators are between length 6 '1/1/91' and 10 '11/11/1991'
const maybeDateWithSeparator = /^(\d{1,4})([\s/\\_.-])(\d{1,2})\2(\d{1,4})$/;
// # dates with separators are between length 6 '1/1/91' and 10 '11/11/1991'
for (let i = 0; i <= Math.abs(password.length - 6); i += 1) {

@@ -52,9 +50,6 @@ for (let j = i + 5; j <= i + 9; j += 1) {

}
const token = password.slice(i, +j + 1 || 9e9);
const regexMatch = maybeDateWithSeparator.exec(token);
if (regexMatch != null) {
const dmy = this.mapIntegersToDayMonthYear([parseInt(regexMatch[1], 10), parseInt(regexMatch[3], 10), parseInt(regexMatch[4], 10)]);
if (dmy != null) {

@@ -75,14 +70,10 @@ matches.push({

}
return matches;
} // eslint-disable-next-line max-statements
}
// eslint-disable-next-line max-statements
getMatchesWithoutSeparator(password) {
const matches = [];
const maybeDateNoSeparator = /^\d{4,8}$/;
const metric = candidate => Math.abs(candidate.year - _const.REFERENCE_YEAR); // # dates without separators are between length 4 '1191' and 8 '11111991'
const metric = candidate => Math.abs(candidate.year - _const.REFERENCE_YEAR);
// # dates without separators are between length 4 '1191' and 8 '11111991'
for (let i = 0; i <= Math.abs(password.length - 4); i += 1) {

@@ -93,5 +84,3 @@ for (let j = i + 3; j <= i + 7; j += 1) {

}
const token = password.slice(i, +j + 1 || 9e9);
if (maybeDateNoSeparator.exec(token)) {

@@ -103,3 +92,2 @@ const candidates = [];

const dmy = this.mapIntegersToDayMonthYear([parseInt(token.slice(0, k), 10), parseInt(token.slice(k, l), 10), parseInt(token.slice(l), 10)]);
if (dmy != null) {

@@ -109,3 +97,2 @@ candidates.push(dmy);

});
if (candidates.length > 0) {

@@ -125,3 +112,2 @@ /*

const distance = metric(candidate);
if (distance < minDistance) {

@@ -146,3 +132,2 @@ bestCandidate = candidate;

}
return matches;

@@ -159,4 +144,2 @@ }

*/
filterNoise(matches) {

@@ -166,6 +149,4 @@ return matches.filter(match => {

const matchesLength = matches.length;
for (let o = 0; o < matchesLength; o += 1) {
const otherMatch = matches[o];
if (match !== otherMatch) {

@@ -178,3 +159,2 @@ if (otherMatch.i <= match.i && otherMatch.j >= match.j) {

}
return !isSubmatch;

@@ -194,4 +174,2 @@ });

// eslint-disable-next-line complexity, max-statements
mapIntegersToDayMonthYear(integers) {

@@ -201,22 +179,16 @@ if (integers[1] > 31 || integers[1] <= 0) {

}
let over12 = 0;
let over31 = 0;
let under1 = 0;
for (let o = 0, len1 = integers.length; o < len1; o += 1) {
const int = integers[o];
if (int > 99 && int < _const.DATE_MIN_YEAR || int > _const.DATE_MAX_YEAR) {
return null;
}
if (int > 31) {
over31 += 1;
}
if (int > 12) {
over12 += 1;
}
if (int <= 0) {

@@ -226,11 +198,8 @@ under1 += 1;

}
if (over31 >= 2 || over12 === 3 || under1 >= 2) {
return null;
}
return this.getDayMonth(integers);
} // eslint-disable-next-line max-statements
}
// eslint-disable-next-line max-statements
getDayMonth(integers) {

@@ -240,10 +209,8 @@ // first look for a four digit year: yyyy + daymonth or daymonth + yyyy

];
const possibleYearSplitsLength = possibleYearSplits.length;
for (let j = 0; j < possibleYearSplitsLength; j += 1) {
const [y, rest] = possibleYearSplits[j];
if (_const.DATE_MIN_YEAR <= y && y <= _const.DATE_MAX_YEAR) {
const dm = this.mapIntegersToDayMonth(rest);
if (dm != null) {

@@ -261,14 +228,10 @@ return {

*/
return null;
}
} // given no four-digit year, two digit years are the most flexible int to match, so
}
// given no four-digit year, two digit years are the most flexible int to match, so
// try to parse a day-month out of integers[0..1] or integers[1..0]
for (let k = 0; k < possibleYearSplitsLength; k += 1) {
const [y, rest] = possibleYearSplits[k];
const dm = this.mapIntegersToDayMonth(rest);
if (dm != null) {

@@ -282,9 +245,6 @@ return {

}
return null;
}
mapIntegersToDayMonth(integers) {
const temp = [integers, integers.slice().reverse()];
for (let i = 0; i < temp.length; i += 1) {

@@ -294,3 +254,2 @@ const data = temp[i];

const month = data[1];
if (day >= 1 && day <= 31 && month >= 1 && month <= 12) {

@@ -303,6 +262,4 @@ return {

}
return null;
}
twoToFourDigitYear(year) {

@@ -312,12 +269,9 @@ if (year > 99) {

}
if (year > 50) {
// 87 -> 1987
return year + 1900;
} // 15 -> 2015
}
// 15 -> 2015
return year + 2000;
}
}

@@ -324,0 +278,0 @@

@@ -9,8 +9,7 @@ import { REFERENCE_YEAR, MIN_YEAR_SPACE } from '../../data/const.esm.js';

const yearSpace = Math.max(Math.abs(year - REFERENCE_YEAR), MIN_YEAR_SPACE);
let guesses = yearSpace * 365; // add factor of 4 for separator selection (one of ~4 choices)
let guesses = yearSpace * 365;
// add factor of 4 for separator selection (one of ~4 choices)
if (separator) {
guesses *= 4;
}
return guesses;

@@ -17,0 +16,0 @@ });

@@ -11,8 +11,7 @@ 'use strict';

const yearSpace = Math.max(Math.abs(year - _const.REFERENCE_YEAR), _const.MIN_YEAR_SPACE);
let guesses = yearSpace * 365; // add factor of 4 for separator selection (one of ~4 choices)
let guesses = yearSpace * 365;
// add factor of 4 for separator selection (one of ~4 choices)
if (separator) {
guesses *= 4;
}
return guesses;

@@ -19,0 +18,0 @@ });

import { MatchEstimated } from '../../types';
declare const _default: (match: MatchEstimated, isSoleMatch?: Boolean) => {
declare const _default: (match: MatchEstimated, isSoleMatch?: boolean) => {
warning: string;

@@ -4,0 +4,0 @@ suggestions: string[];

@@ -6,3 +6,2 @@ import zxcvbnOptions from '../../Options.esm.js';

let warning = '';
if (isSoleMatch && !match.l33t && !match.reversed) {

@@ -19,16 +18,11 @@ if (match.rank <= 10) {

}
return warning;
};
const getDictionaryWarningWikipedia = (match, isSoleMatch) => {
let warning = '';
if (isSoleMatch) {
warning = zxcvbnOptions.translations.warnings.wordByItself;
}
return warning;
};
const getDictionaryWarningNames = (match, isSoleMatch) => {

@@ -38,6 +32,4 @@ if (isSoleMatch) {

}
return zxcvbnOptions.translations.warnings.commonNames;
};
const getDictionaryWarning = (match, isSoleMatch) => {

@@ -47,3 +39,2 @@ let warning = '';

const isAName = dictName === 'lastnames' || dictName.toLowerCase().includes('firstnames');
if (dictName === 'passwords') {

@@ -58,6 +49,4 @@ warning = getDictionaryWarningPassword(match, isSoleMatch);

}
return warning;
};
var dictionaryMatcher = ((match, isSoleMatch) => {

@@ -67,3 +56,2 @@ const warning = getDictionaryWarning(match, isSoleMatch);

const word = match.token;
if (word.match(START_UPPER)) {

@@ -74,11 +62,8 @@ suggestions.push(zxcvbnOptions.translations.suggestions.capitalization);

}
if (match.reversed && match.token.length >= 4) {
suggestions.push(zxcvbnOptions.translations.suggestions.reverseWords);
}
if (match.l33t) {
suggestions.push(zxcvbnOptions.translations.suggestions.l33t);
}
return {

@@ -85,0 +70,0 @@ warning,

@@ -8,36 +8,28 @@ 'use strict';

let warning = '';
if (isSoleMatch && !match.l33t && !match.reversed) {
if (match.rank <= 10) {
warning = Options["default"].translations.warnings.topTen;
warning = Options.default.translations.warnings.topTen;
} else if (match.rank <= 100) {
warning = Options["default"].translations.warnings.topHundred;
warning = Options.default.translations.warnings.topHundred;
} else {
warning = Options["default"].translations.warnings.common;
warning = Options.default.translations.warnings.common;
}
} else if (match.guessesLog10 <= 4) {
warning = Options["default"].translations.warnings.similarToCommon;
warning = Options.default.translations.warnings.similarToCommon;
}
return warning;
};
const getDictionaryWarningWikipedia = (match, isSoleMatch) => {
let warning = '';
if (isSoleMatch) {
warning = Options["default"].translations.warnings.wordByItself;
warning = Options.default.translations.warnings.wordByItself;
}
return warning;
};
const getDictionaryWarningNames = (match, isSoleMatch) => {
if (isSoleMatch) {
return Options["default"].translations.warnings.namesByThemselves;
return Options.default.translations.warnings.namesByThemselves;
}
return Options["default"].translations.warnings.commonNames;
return Options.default.translations.warnings.commonNames;
};
const getDictionaryWarning = (match, isSoleMatch) => {

@@ -47,3 +39,2 @@ let warning = '';

const isAName = dictName === 'lastnames' || dictName.toLowerCase().includes('firstnames');
if (dictName === 'passwords') {

@@ -56,8 +47,6 @@ warning = getDictionaryWarningPassword(match, isSoleMatch);

} else if (dictName === 'userInputs') {
warning = Options["default"].translations.warnings.userInputs;
warning = Options.default.translations.warnings.userInputs;
}
return warning;
};
var dictionaryMatcher = ((match, isSoleMatch) => {

@@ -67,17 +56,13 @@ const warning = getDictionaryWarning(match, isSoleMatch);

const word = match.token;
if (word.match(_const.START_UPPER)) {
suggestions.push(Options["default"].translations.suggestions.capitalization);
suggestions.push(Options.default.translations.suggestions.capitalization);
} else if (word.match(_const.ALL_UPPER_INVERTED) && word.toLowerCase() !== word) {
suggestions.push(Options["default"].translations.suggestions.allUppercase);
suggestions.push(Options.default.translations.suggestions.allUppercase);
}
if (match.reversed && match.token.length >= 4) {
suggestions.push(Options["default"].translations.suggestions.reverseWords);
suggestions.push(Options.default.translations.suggestions.reverseWords);
}
if (match.l33t) {
suggestions.push(Options["default"].translations.suggestions.l33t);
suggestions.push(Options.default.translations.suggestions.l33t);
}
return {

@@ -84,0 +69,0 @@ warning,

import { DictionaryMatch } from '../../types';
import Reverse from './variants/matching/reverse';
import L33t from './variants/matching/l33t';
interface DictionaryMatchOptions {
password: string;
}
import { DictionaryMatchOptions } from './types';
declare class MatchDictionary {

@@ -8,0 +6,0 @@ l33t: L33t;

import findLevenshteinDistance from '../../levenshtein.esm.js';
import { sorted } from '../../helper.esm.js';
import zxcvbnOptions from '../../Options.esm.js';
import MatchL33t$1 from './variants/matching/reverse.esm.js';
import MatchReverse from './variants/matching/reverse.esm.js';
import MatchL33t from './variants/matching/l33t.esm.js';

@@ -10,5 +10,4 @@

this.l33t = new MatchL33t(this.defaultMatch);
this.reverse = new MatchL33t$1(this.defaultMatch);
this.reverse = new MatchReverse(this.defaultMatch);
}
match({

@@ -26,3 +25,2 @@ password

}
defaultMatch({

@@ -33,22 +31,21 @@ password

const passwordLength = password.length;
const passwordLower = password.toLowerCase(); // eslint-disable-next-line complexity
const passwordLower = password.toLowerCase();
// eslint-disable-next-line complexity,max-statements
Object.keys(zxcvbnOptions.rankedDictionaries).forEach(dictionaryName => {
const rankedDict = zxcvbnOptions.rankedDictionaries[dictionaryName];
const longestDictionaryWordSize = zxcvbnOptions.rankedDictionariesMaxWordSize[dictionaryName];
const searchWidth = Math.min(longestDictionaryWordSize, passwordLength);
for (let i = 0; i < passwordLength; i += 1) {
for (let j = i; j < passwordLength; j += 1) {
const searchEnd = Math.min(i + searchWidth, passwordLength);
for (let j = i; j < searchEnd; j += 1) {
const usedPassword = passwordLower.slice(i, +j + 1 || 9e9);
const isInDictionary = (usedPassword in rankedDict);
let foundLevenshteinDistance = {}; // only use levenshtein distance on full password to minimize the performance drop
let foundLevenshteinDistance = {};
// only use levenshtein distance on full password to minimize the performance drop
// and because otherwise there would be to many false positives
const isFullPassword = i === 0 && j === passwordLength - 1;
if (zxcvbnOptions.useLevenshteinDistance && isFullPassword && !isInDictionary) {
foundLevenshteinDistance = findLevenshteinDistance(usedPassword, rankedDict, zxcvbnOptions.levenshteinThreshold);
}
const isLevenshteinMatch = Object.keys(foundLevenshteinDistance).length !== 0;
if (isInDictionary || isLevenshteinMatch) {

@@ -75,3 +72,2 @@ const usedRankPassword = isLevenshteinMatch ? foundLevenshteinDistance.levenshteinDistanceEntry : usedPassword;

}
}

@@ -78,0 +74,0 @@

@@ -14,3 +14,2 @@ 'use strict';

}
match({

@@ -28,3 +27,2 @@ password

}
defaultMatch({

@@ -35,22 +33,21 @@ password

const passwordLength = password.length;
const passwordLower = password.toLowerCase(); // eslint-disable-next-line complexity
Object.keys(Options["default"].rankedDictionaries).forEach(dictionaryName => {
const rankedDict = Options["default"].rankedDictionaries[dictionaryName];
const passwordLower = password.toLowerCase();
// eslint-disable-next-line complexity,max-statements
Object.keys(Options.default.rankedDictionaries).forEach(dictionaryName => {
const rankedDict = Options.default.rankedDictionaries[dictionaryName];
const longestDictionaryWordSize = Options.default.rankedDictionariesMaxWordSize[dictionaryName];
const searchWidth = Math.min(longestDictionaryWordSize, passwordLength);
for (let i = 0; i < passwordLength; i += 1) {
for (let j = i; j < passwordLength; j += 1) {
const searchEnd = Math.min(i + searchWidth, passwordLength);
for (let j = i; j < searchEnd; j += 1) {
const usedPassword = passwordLower.slice(i, +j + 1 || 9e9);
const isInDictionary = (usedPassword in rankedDict);
let foundLevenshteinDistance = {}; // only use levenshtein distance on full password to minimize the performance drop
let foundLevenshteinDistance = {};
// only use levenshtein distance on full password to minimize the performance drop
// and because otherwise there would be to many false positives
const isFullPassword = i === 0 && j === passwordLength - 1;
if (Options["default"].useLevenshteinDistance && isFullPassword && !isInDictionary) {
foundLevenshteinDistance = levenshtein(usedPassword, rankedDict, Options["default"].levenshteinThreshold);
if (Options.default.useLevenshteinDistance && isFullPassword && !isInDictionary) {
foundLevenshteinDistance = levenshtein(usedPassword, rankedDict, Options.default.levenshteinThreshold);
}
const isLevenshteinMatch = Object.keys(foundLevenshteinDistance).length !== 0;
if (isInDictionary || isLevenshteinMatch) {

@@ -77,3 +74,2 @@ const usedRankPassword = isLevenshteinMatch ? foundLevenshteinDistance.levenshteinDistanceEntry : usedPassword;

}
}

@@ -80,0 +76,0 @@

@@ -12,3 +12,2 @@ import uppercaseVariant from './variants/scoring/uppercase.esm.js';

const baseGuesses = rank; // keep these as properties for display purposes
const uppercaseVariations = uppercaseVariant(token);

@@ -15,0 +14,0 @@ const l33tVariations = l33tVariant({

@@ -14,3 +14,2 @@ 'use strict';

const baseGuesses = rank; // keep these as properties for display purposes
const uppercaseVariations = uppercase(token);

@@ -17,0 +16,0 @@ const l33tVariations = l33t({

import { L33tMatch, LooseObject, OptionsL33tTable } from '../../../../types';
declare type Subs = string[][][];
import { DefaultMatch } from '../../types';
type Subs = string[][][];
declare class MatchL33t {
defaultMatch: Function;
constructor(defaultMatch: Function);
defaultMatch: DefaultMatch;
constructor(defaultMatch: DefaultMatch);
match({ password }: {

@@ -7,0 +8,0 @@ password: string;

@@ -9,3 +9,2 @@ import { empty, translate } from '../../../../helper.esm.js';

*/
class MatchL33t {

@@ -15,3 +14,2 @@ constructor(defaultMatch) {

}
match({

@@ -22,10 +20,9 @@ password

const enumeratedSubs = this.enumerateL33tSubs(this.relevantL33tSubtable(password, zxcvbnOptions.l33tTable));
for (let i = 0; i < enumeratedSubs.length; i += 1) {
const sub = enumeratedSubs[i]; // corner case: password has no relevant subs.
const length = Math.min(enumeratedSubs.length, zxcvbnOptions.l33tMaxSubstitutions);
for (let i = 0; i < length; i += 1) {
const sub = enumeratedSubs[i];
// corner case: password has no relevant subs.
if (empty(sub)) {
break;
}
const subbedPassword = translate(password, sub);

@@ -36,4 +33,4 @@ const matchedDictionary = this.defaultMatch({

matchedDictionary.forEach(match => {
const token = password.slice(match.i, +match.j + 1 || 9e9); // only return the matches that contain an actual substitution
const token = password.slice(match.i, +match.j + 1 || 9e9);
// only return the matches that contain an actual substitution
if (token.toLowerCase() !== match.matchedWord) {

@@ -44,3 +41,2 @@ // subset of mappings in sub that are in use for this match

const chr = sub[subbedChr];
if (token.indexOf(subbedChr) !== -1) {

@@ -51,3 +47,4 @@ matchSub[subbedChr] = chr;

const subDisplay = Object.keys(matchSub).map(k => `${k} -> ${matchSub[k]}`).join(', ');
matches.push({ ...match,
matches.push({
...match,
l33t: true,

@@ -60,11 +57,9 @@ token,

});
} // filter single-character l33t matches to reduce noise.
}
// filter single-character l33t matches to reduce noise.
// otherwise '1' matches 'i', '4' matches 'a', both very common English words
// with low dictionary rank.
return matches.filter(match => match.token.length > 1);
} // makes a pruned copy of l33t_table that only includes password's possible substitutions
}
// makes a pruned copy of l33t_table that only includes password's possible substitutions
relevantL33tSubtable(password, table) {

@@ -79,3 +74,2 @@ const passwordChars = {};

const relevantSubs = subs.filter(sub => sub in passwordChars);
if (relevantSubs.length > 0) {

@@ -86,9 +80,8 @@ subTable[letter] = relevantSubs;

return subTable;
} // returns the list of possible 1337 replacement dictionaries for a given password
}
// returns the list of possible 1337 replacement dictionaries for a given password
enumerateL33tSubs(table) {
const tableKeys = Object.keys(table);
const subs = this.getSubs(tableKeys, [[]], table); // convert from assoc lists to dicts
const subs = this.getSubs(tableKeys, [[]], table);
// convert from assoc lists to dicts
return subs.map(sub => {

@@ -102,3 +95,2 @@ const subDict = {};

}
getSubs(keys, subs, table) {

@@ -108,3 +100,2 @@ if (!keys.length) {

}
const firstKey = keys[0];

@@ -116,3 +107,2 @@ const restKeys = keys.slice(1);

let dupL33tIndex = -1;
for (let i = 0; i < sub.length; i += 1) {

@@ -124,3 +114,2 @@ if (sub[i][0] === l33tChr) {

}
if (dupL33tIndex === -1) {

@@ -139,10 +128,7 @@ const subExtension = sub.concat([[l33tChr, firstKey]]);

const newSubs = this.dedup(nextSubs);
if (restKeys.length) {
return this.getSubs(restKeys, newSubs, table);
}
return newSubs;
}
dedup(subs) {

@@ -155,3 +141,2 @@ const deduped = [];

const label = assoc.map(([k, v]) => `${k},${v}`).join('-');
if (!(label in members)) {

@@ -164,3 +149,2 @@ members[label] = true;

}
}

@@ -167,0 +151,0 @@

@@ -11,3 +11,2 @@ 'use strict';

*/
class MatchL33t {

@@ -17,3 +16,2 @@ constructor(defaultMatch) {

}
match({

@@ -23,11 +21,10 @@ password

const matches = [];
const enumeratedSubs = this.enumerateL33tSubs(this.relevantL33tSubtable(password, Options["default"].l33tTable));
for (let i = 0; i < enumeratedSubs.length; i += 1) {
const sub = enumeratedSubs[i]; // corner case: password has no relevant subs.
const enumeratedSubs = this.enumerateL33tSubs(this.relevantL33tSubtable(password, Options.default.l33tTable));
const length = Math.min(enumeratedSubs.length, Options.default.l33tMaxSubstitutions);
for (let i = 0; i < length; i += 1) {
const sub = enumeratedSubs[i];
// corner case: password has no relevant subs.
if (helper.empty(sub)) {
break;
}
const subbedPassword = helper.translate(password, sub);

@@ -38,4 +35,4 @@ const matchedDictionary = this.defaultMatch({

matchedDictionary.forEach(match => {
const token = password.slice(match.i, +match.j + 1 || 9e9); // only return the matches that contain an actual substitution
const token = password.slice(match.i, +match.j + 1 || 9e9);
// only return the matches that contain an actual substitution
if (token.toLowerCase() !== match.matchedWord) {

@@ -46,3 +43,2 @@ // subset of mappings in sub that are in use for this match

const chr = sub[subbedChr];
if (token.indexOf(subbedChr) !== -1) {

@@ -53,3 +49,4 @@ matchSub[subbedChr] = chr;

const subDisplay = Object.keys(matchSub).map(k => `${k} -> ${matchSub[k]}`).join(', ');
matches.push({ ...match,
matches.push({
...match,
l33t: true,

@@ -62,11 +59,9 @@ token,

});
} // filter single-character l33t matches to reduce noise.
}
// filter single-character l33t matches to reduce noise.
// otherwise '1' matches 'i', '4' matches 'a', both very common English words
// with low dictionary rank.
return matches.filter(match => match.token.length > 1);
} // makes a pruned copy of l33t_table that only includes password's possible substitutions
}
// makes a pruned copy of l33t_table that only includes password's possible substitutions
relevantL33tSubtable(password, table) {

@@ -81,3 +76,2 @@ const passwordChars = {};

const relevantSubs = subs.filter(sub => sub in passwordChars);
if (relevantSubs.length > 0) {

@@ -88,9 +82,8 @@ subTable[letter] = relevantSubs;

return subTable;
} // returns the list of possible 1337 replacement dictionaries for a given password
}
// returns the list of possible 1337 replacement dictionaries for a given password
enumerateL33tSubs(table) {
const tableKeys = Object.keys(table);
const subs = this.getSubs(tableKeys, [[]], table); // convert from assoc lists to dicts
const subs = this.getSubs(tableKeys, [[]], table);
// convert from assoc lists to dicts
return subs.map(sub => {

@@ -104,3 +97,2 @@ const subDict = {};

}
getSubs(keys, subs, table) {

@@ -110,3 +102,2 @@ if (!keys.length) {

}
const firstKey = keys[0];

@@ -118,3 +109,2 @@ const restKeys = keys.slice(1);

let dupL33tIndex = -1;
for (let i = 0; i < sub.length; i += 1) {

@@ -126,3 +116,2 @@ if (sub[i][0] === l33tChr) {

}
if (dupL33tIndex === -1) {

@@ -141,10 +130,7 @@ const subExtension = sub.concat([[l33tChr, firstKey]]);

const newSubs = this.dedup(nextSubs);
if (restKeys.length) {
return this.getSubs(restKeys, newSubs, table);
}
return newSubs;
}
dedup(subs) {

@@ -157,3 +143,2 @@ const deduped = [];

const label = assoc.map(([k, v]) => `${k},${v}`).join('-');
if (!(label in members)) {

@@ -166,3 +151,2 @@ members[label] = true;

}
}

@@ -169,0 +153,0 @@

@@ -1,8 +0,19 @@

declare class MatchL33t {
defaultMatch: Function;
constructor(defaultMatch: Function);
import { DefaultMatch } from '../../types';
declare class MatchReverse {
defaultMatch: DefaultMatch;
constructor(defaultMatch: DefaultMatch);
match({ password }: {
password: string;
}): any;
}): {
token: string;
reversed: boolean;
i: number;
j: number;
pattern: "dictionary";
matchedWord: string;
rank: number;
dictionaryName: import("../../../../types").DictionaryNames;
l33t: boolean;
}[];
}
export default MatchL33t;
export default MatchReverse;

@@ -6,7 +6,6 @@ /*

*/
class MatchL33t {
class MatchReverse {
constructor(defaultMatch) {
this.defaultMatch = defaultMatch;
}
match({

@@ -18,3 +17,4 @@ password

password: passwordReversed
}).map(match => ({ ...match,
}).map(match => ({
...match,
token: match.token.split('').reverse().join(''),

@@ -27,6 +27,5 @@ reversed: true,

}
}
export { MatchL33t as default };
export { MatchReverse as default };
//# sourceMappingURL=reverse.esm.js.map

@@ -8,7 +8,6 @@ 'use strict';

*/
class MatchL33t {
class MatchReverse {
constructor(defaultMatch) {
this.defaultMatch = defaultMatch;
}
match({

@@ -20,3 +19,4 @@ password

password: passwordReversed
}).map(match => ({ ...match,
}).map(match => ({
...match,
token: match.token.split('').reverse().join(''),

@@ -29,6 +29,5 @@ reversed: true,

}
}
module.exports = MatchL33t;
module.exports = MatchReverse;
//# sourceMappingURL=reverse.js.map

@@ -8,8 +8,8 @@ import utils from '../../../../scoring/utils.esm.js';

}) => {
const unsubbed = subs[subbed]; // lower-case match.token before calculating: capitalization shouldn't affect l33t calc.
const chrs = token.toLowerCase().split(''); // num of subbed chars
const subbedCount = chrs.filter(char => char === subbed).length; // num of unsubbed chars
const unsubbed = subs[subbed];
// lower-case match.token before calculating: capitalization shouldn't affect l33t calc.
const chrs = token.toLowerCase().split('');
// num of subbed chars
const subbedCount = chrs.filter(char => char === subbed).length;
// num of unsubbed chars
const unsubbedCount = chrs.filter(char => char === unsubbed).length;

@@ -21,3 +21,2 @@ return {

};
var l33tVariant = (({

@@ -31,3 +30,2 @@ l33t,

}
let variations = 1;

@@ -44,3 +42,2 @@ const subs = sub;

});
if (subbedCount === 0 || unsubbedCount === 0) {

@@ -56,7 +53,5 @@ // for this sub, password is either fully subbed (444) or fully unsubbed (aaa)

let possibilities = 0;
for (let i = 1; i <= p; i += 1) {
possibilities += utils.nCk(unsubbedCount + subbedCount, i);
}
variations *= possibilities;

@@ -63,0 +58,0 @@ }

@@ -10,8 +10,8 @@ 'use strict';

}) => {
const unsubbed = subs[subbed]; // lower-case match.token before calculating: capitalization shouldn't affect l33t calc.
const chrs = token.toLowerCase().split(''); // num of subbed chars
const subbedCount = chrs.filter(char => char === subbed).length; // num of unsubbed chars
const unsubbed = subs[subbed];
// lower-case match.token before calculating: capitalization shouldn't affect l33t calc.
const chrs = token.toLowerCase().split('');
// num of subbed chars
const subbedCount = chrs.filter(char => char === subbed).length;
// num of unsubbed chars
const unsubbedCount = chrs.filter(char => char === unsubbed).length;

@@ -23,3 +23,2 @@ return {

};
var l33tVariant = (({

@@ -33,3 +32,2 @@ l33t,

}
let variations = 1;

@@ -46,3 +44,2 @@ const subs = sub;

});
if (subbedCount === 0 || unsubbedCount === 0) {

@@ -58,7 +55,5 @@ // for this sub, password is either fully subbed (444) or fully unsubbed (aaa)

let possibilities = 0;
for (let i = 1; i <= p; i += 1) {
possibilities += utils.nCk(unsubbedCount + subbedCount, i);
}
variations *= possibilities;

@@ -65,0 +60,0 @@ }

@@ -10,35 +10,27 @@ import utils from '../../../../scoring/utils.esm.js';

const variationLength = Math.min(upperCaseCount, lowerCaseCount);
for (let i = 1; i <= variationLength; i += 1) {
variations += utils.nCk(upperCaseCount + lowerCaseCount, i);
}
return variations;
};
var uppercaseVariant = (word => {
// clean words of non alpha characters to remove the reward effekt to capitalize the first letter https://github.com/dropbox/zxcvbn/issues/232
const cleanedWord = word.replace(ALPHA_INVERTED, '');
if (cleanedWord.match(ALL_LOWER_INVERTED) || cleanedWord.toLowerCase() === cleanedWord) {
return 1;
} // a capitalized word is the most common capitalization scheme,
}
// a capitalized word is the most common capitalization scheme,
// so it only doubles the search space (uncapitalized + capitalized).
// all caps and end-capitalized are common enough too, underestimate as 2x factor to be safe.
const commonCases = [START_UPPER, END_UPPER, ALL_UPPER_INVERTED];
const commonCasesLength = commonCases.length;
for (let i = 0; i < commonCasesLength; i += 1) {
const regex = commonCases[i];
if (cleanedWord.match(regex)) {
return 2;
}
} // otherwise calculate the number of ways to capitalize U+L uppercase+lowercase letters
}
// otherwise calculate the number of ways to capitalize U+L uppercase+lowercase letters
// with U uppercase letters or less. or, if there's more uppercase than lower (for eg. PASSwORD),
// the number of ways to lowercase U+L letters with L lowercase letters or less.
return getVariations(cleanedWord);

@@ -45,0 +37,0 @@ });

@@ -12,35 +12,27 @@ 'use strict';

const variationLength = Math.min(upperCaseCount, lowerCaseCount);
for (let i = 1; i <= variationLength; i += 1) {
variations += utils.nCk(upperCaseCount + lowerCaseCount, i);
}
return variations;
};
var uppercaseVariant = (word => {
// clean words of non alpha characters to remove the reward effekt to capitalize the first letter https://github.com/dropbox/zxcvbn/issues/232
const cleanedWord = word.replace(_const.ALPHA_INVERTED, '');
if (cleanedWord.match(_const.ALL_LOWER_INVERTED) || cleanedWord.toLowerCase() === cleanedWord) {
return 1;
} // a capitalized word is the most common capitalization scheme,
}
// a capitalized word is the most common capitalization scheme,
// so it only doubles the search space (uncapitalized + capitalized).
// all caps and end-capitalized are common enough too, underestimate as 2x factor to be safe.
const commonCases = [_const.START_UPPER, _const.END_UPPER, _const.ALL_UPPER_INVERTED];
const commonCasesLength = commonCases.length;
for (let i = 0; i < commonCasesLength; i += 1) {
const regex = commonCases[i];
if (cleanedWord.match(regex)) {
return 2;
}
} // otherwise calculate the number of ways to capitalize U+L uppercase+lowercase letters
}
// otherwise calculate the number of ways to capitalize U+L uppercase+lowercase letters
// with U uppercase letters or less. or, if there's more uppercase than lower (for eg. PASSwORD),
// the number of ways to lowercase U+L letters with L lowercase letters or less.
return getVariations(cleanedWord);

@@ -47,0 +39,0 @@ });

@@ -10,3 +10,2 @@ import zxcvbnOptions from '../../Options.esm.js';

}
return {

@@ -13,0 +12,0 @@ warning: '',

@@ -8,7 +8,6 @@ 'use strict';

return {
warning: Options["default"].translations.warnings.recentYears,
suggestions: [Options["default"].translations.suggestions.recentYears, Options["default"].translations.suggestions.associatedYears]
warning: Options.default.translations.warnings.recentYears,
suggestions: [Options.default.translations.suggestions.recentYears, Options.default.translations.suggestions.associatedYears]
};
}
return {

@@ -15,0 +14,0 @@ warning: '',

@@ -9,3 +9,2 @@ import { REGEXEN } from '../../data/const.esm.js';

*/
class MatchRegex {

@@ -20,5 +19,3 @@ match({

regex.lastIndex = 0; // keeps regexMatch stateless
const regexMatch = regex.exec(password);
if (regexMatch) {

@@ -38,3 +35,2 @@ const token = regexMatch[0];

}
}

@@ -41,0 +37,0 @@

@@ -11,3 +11,2 @@ 'use strict';

*/
class MatchRegex {

@@ -22,5 +21,3 @@ match({

regex.lastIndex = 0; // keeps regexMatch stateless
const regexMatch = regex.exec(password);
if (regexMatch) {

@@ -40,3 +37,2 @@ const token = regexMatch[0];

}
}

@@ -43,0 +39,0 @@

@@ -16,9 +16,7 @@ import { REFERENCE_YEAR, MIN_YEAR_SPACE } from '../../data/const.esm.js';

};
if (regexName in charClassBases) {
return charClassBases[regexName] ** token.length;
} // TODO add more regex types for example special dates like 09.11
}
// TODO add more regex types for example special dates like 09.11
// eslint-disable-next-line default-case
switch (regexName) {

@@ -30,3 +28,2 @@ case 'recentYear':

}
return 0;

@@ -33,0 +30,0 @@ });

@@ -18,9 +18,7 @@ 'use strict';

};
if (regexName in charClassBases) {
return charClassBases[regexName] ** token.length;
} // TODO add more regex types for example special dates like 09.11
}
// TODO add more regex types for example special dates like 09.11
// eslint-disable-next-line default-case
switch (regexName) {

@@ -32,3 +30,2 @@ case 'recentYear':

}
return 0;

@@ -35,0 +32,0 @@ });

@@ -5,7 +5,5 @@ import zxcvbnOptions from '../../Options.esm.js';

let warning = zxcvbnOptions.translations.warnings.extendedRepeat;
if (match.baseToken.length === 1) {
warning = zxcvbnOptions.translations.warnings.simpleRepeat;
}
return {

@@ -12,0 +10,0 @@ warning,

@@ -6,11 +6,9 @@ 'use strict';

var repeatMatcher = (match => {
let warning = Options["default"].translations.warnings.extendedRepeat;
let warning = Options.default.translations.warnings.extendedRepeat;
if (match.baseToken.length === 1) {
warning = Options["default"].translations.warnings.simpleRepeat;
warning = Options.default.translations.warnings.simpleRepeat;
}
return {
warning,
suggestions: [Options["default"].translations.suggestions.repeated]
suggestions: [Options.default.translations.suggestions.repeated]
};

@@ -17,0 +15,0 @@ });

@@ -8,3 +8,2 @@ import scoring from '../../scoring/index.esm.js';

*/
class MatchRepeat {

@@ -18,11 +17,8 @@ // eslint-disable-next-line max-statements

let lastIndex = 0;
while (lastIndex < password.length) {
const greedyMatch = this.getGreedyMatch(password, lastIndex);
const lazyMatch = this.getLazyMatch(password, lastIndex);
if (greedyMatch == null) {
break;
}
const {

@@ -32,3 +28,2 @@ match,

} = this.setMatchToken(greedyMatch, lazyMatch);
if (match) {

@@ -41,15 +36,11 @@ const j = match.index + match[0].length - 1;

}
const hasPromises = matches.some(match => {
return match instanceof Promise;
});
if (hasPromises) {
return Promise.all(matches);
}
return matches;
} // eslint-disable-next-line max-params
}
// eslint-disable-next-line max-params
normalizeMatch(baseToken, j, match, baseGuesses) {

@@ -65,6 +56,6 @@ const baseMatch = {

};
if (baseGuesses instanceof Promise) {
return baseGuesses.then(resolvedBaseGuesses => {
return { ...baseMatch,
return {
...baseMatch,
baseGuesses: resolvedBaseGuesses

@@ -74,8 +65,7 @@ };

}
return { ...baseMatch,
return {
...baseMatch,
baseGuesses
};
}
getGreedyMatch(password, lastIndex) {

@@ -86,3 +76,2 @@ const greedy = /(.+)\1+/g;

}
getLazyMatch(password, lastIndex) {

@@ -93,3 +82,2 @@ const lazy = /(.+?)\1+/g;

}
setMatchToken(greedyMatch, lazyMatch) {

@@ -99,3 +87,2 @@ const lazyAnchored = /^(.+?)\1+$/;

let baseToken = '';
if (lazyMatch && greedyMatch[0].length > lazyMatch[0].length) {

@@ -105,9 +92,8 @@ // greedy beats lazy for 'aabaab'

// lazy: [aa, a]
match = greedyMatch; // greedy's repeated string might itself be repeated, eg.
match = greedyMatch;
// greedy's repeated string might itself be repeated, eg.
// aabaab in aabaabaabaab.
// run an anchored lazy match on greedy's repeated string
// to find the shortest repeated string
const temp = lazyAnchored.exec(match[0]);
if (temp) {

@@ -121,3 +107,2 @@ baseToken = temp[1];

match = lazyMatch;
if (match) {

@@ -127,3 +112,2 @@ baseToken = match[1];

}
return {

@@ -134,6 +118,4 @@ match,

}
getBaseGuesses(baseToken, omniMatch) {
const matches = omniMatch.match(baseToken);
if (matches instanceof Promise) {

@@ -145,7 +127,5 @@ return matches.then(resolvedMatches => {

}
const baseAnalysis = scoring.mostGuessableMatchSequence(baseToken, matches);
return baseAnalysis.guesses;
}
}

@@ -152,0 +132,0 @@

@@ -10,3 +10,2 @@ 'use strict';

*/
class MatchRepeat {

@@ -20,11 +19,8 @@ // eslint-disable-next-line max-statements

let lastIndex = 0;
while (lastIndex < password.length) {
const greedyMatch = this.getGreedyMatch(password, lastIndex);
const lazyMatch = this.getLazyMatch(password, lastIndex);
if (greedyMatch == null) {
break;
}
const {

@@ -34,3 +30,2 @@ match,

} = this.setMatchToken(greedyMatch, lazyMatch);
if (match) {

@@ -43,15 +38,11 @@ const j = match.index + match[0].length - 1;

}
const hasPromises = matches.some(match => {
return match instanceof Promise;
});
if (hasPromises) {
return Promise.all(matches);
}
return matches;
} // eslint-disable-next-line max-params
}
// eslint-disable-next-line max-params
normalizeMatch(baseToken, j, match, baseGuesses) {

@@ -67,6 +58,6 @@ const baseMatch = {

};
if (baseGuesses instanceof Promise) {
return baseGuesses.then(resolvedBaseGuesses => {
return { ...baseMatch,
return {
...baseMatch,
baseGuesses: resolvedBaseGuesses

@@ -76,8 +67,7 @@ };

}
return { ...baseMatch,
return {
...baseMatch,
baseGuesses
};
}
getGreedyMatch(password, lastIndex) {

@@ -88,3 +78,2 @@ const greedy = /(.+)\1+/g;

}
getLazyMatch(password, lastIndex) {

@@ -95,3 +84,2 @@ const lazy = /(.+?)\1+/g;

}
setMatchToken(greedyMatch, lazyMatch) {

@@ -101,3 +89,2 @@ const lazyAnchored = /^(.+?)\1+$/;

let baseToken = '';
if (lazyMatch && greedyMatch[0].length > lazyMatch[0].length) {

@@ -107,9 +94,8 @@ // greedy beats lazy for 'aabaab'

// lazy: [aa, a]
match = greedyMatch; // greedy's repeated string might itself be repeated, eg.
match = greedyMatch;
// greedy's repeated string might itself be repeated, eg.
// aabaab in aabaabaabaab.
// run an anchored lazy match on greedy's repeated string
// to find the shortest repeated string
const temp = lazyAnchored.exec(match[0]);
if (temp) {

@@ -123,3 +109,2 @@ baseToken = temp[1];

match = lazyMatch;
if (match) {

@@ -129,3 +114,2 @@ baseToken = match[1];

}
return {

@@ -136,6 +120,4 @@ match,

}
getBaseGuesses(baseToken, omniMatch) {
const matches = omniMatch.match(baseToken);
if (matches instanceof Promise) {

@@ -147,7 +129,5 @@ return matches.then(resolvedMatches => {

}
const baseAnalysis = index.mostGuessableMatchSequence(baseToken, matches);
return baseAnalysis.guesses;
}
}

@@ -154,0 +134,0 @@

@@ -7,4 +7,4 @@ 'use strict';

return {
warning: Options["default"].translations.warnings.sequences,
suggestions: [Options["default"].translations.suggestions.sequences]
warning: Options.default.translations.warnings.sequences,
suggestions: [Options.default.translations.suggestions.sequences]
};

@@ -11,0 +11,0 @@ });

import { SequenceMatch } from '../../types';
declare type UpdateParams = {
type UpdateParams = {
i: number;

@@ -4,0 +4,0 @@ j: number;

@@ -8,9 +8,7 @@ import { ALL_LOWER, ALL_UPPER, ALL_DIGIT } from '../../data/const.esm.js';

*/
class MatchSequence {
constructor() {
this.MAX_DELTA = 5;
} // eslint-disable-next-line max-statements
}
// eslint-disable-next-line max-statements
match({

@@ -34,18 +32,13 @@ password

const result = [];
if (password.length === 1) {
return [];
}
let i = 0;
let lastDelta = null;
const passwordLength = password.length;
for (let k = 1; k < passwordLength; k += 1) {
const delta = password.charCodeAt(k) - password.charCodeAt(k - 1);
if (lastDelta == null) {
lastDelta = delta;
}
if (delta !== lastDelta) {

@@ -64,3 +57,2 @@ const j = k - 1;

}
this.update({

@@ -75,3 +67,2 @@ i,

}
update({

@@ -86,3 +77,2 @@ i,

const absoluteDelta = Math.abs(delta);
if (absoluteDelta > 0 && absoluteDelta <= this.MAX_DELTA) {

@@ -105,6 +95,4 @@ const token = password.slice(i, +j + 1 || 9e9);

}
return null;
}
getSequence(token) {

@@ -115,3 +103,2 @@ // TODO conservatively stick with roman alphabet size.

let sequenceSpace = 26;
if (ALL_LOWER.test(token)) {

@@ -127,3 +114,2 @@ sequenceName = 'lower';

}
return {

@@ -134,3 +120,2 @@ sequenceName,

}
}

@@ -137,0 +122,0 @@

@@ -10,9 +10,7 @@ 'use strict';

*/
class MatchSequence {
constructor() {
this.MAX_DELTA = 5;
} // eslint-disable-next-line max-statements
}
// eslint-disable-next-line max-statements
match({

@@ -36,18 +34,13 @@ password

const result = [];
if (password.length === 1) {
return [];
}
let i = 0;
let lastDelta = null;
const passwordLength = password.length;
for (let k = 1; k < passwordLength; k += 1) {
const delta = password.charCodeAt(k) - password.charCodeAt(k - 1);
if (lastDelta == null) {
lastDelta = delta;
}
if (delta !== lastDelta) {

@@ -66,3 +59,2 @@ const j = k - 1;

}
this.update({

@@ -77,3 +69,2 @@ i,

}
update({

@@ -88,3 +79,2 @@ i,

const absoluteDelta = Math.abs(delta);
if (absoluteDelta > 0 && absoluteDelta <= this.MAX_DELTA) {

@@ -107,6 +97,4 @@ const token = password.slice(i, +j + 1 || 9e9);

}
return null;
}
getSequence(token) {

@@ -117,3 +105,2 @@ // TODO conservatively stick with roman alphabet size.

let sequenceSpace = 26;
if (_const.ALL_LOWER.test(token)) {

@@ -129,3 +116,2 @@ sequenceName = 'lower';

}
return {

@@ -136,3 +122,2 @@ sequenceName,

}
}

@@ -139,0 +124,0 @@

@@ -7,4 +7,4 @@ var sequenceMatcher = (({

let baseGuesses = 0;
const startingPoints = ['a', 'A', 'z', 'Z', '0', '1', '9']; // lower guesses for obvious starting points
const startingPoints = ['a', 'A', 'z', 'Z', '0', '1', '9'];
// lower guesses for obvious starting points
if (startingPoints.includes(firstChr)) {

@@ -18,10 +18,8 @@ baseGuesses = 4;

baseGuesses = 26;
} // need to try a descending sequence in addition to every ascending sequence ->
}
// need to try a descending sequence in addition to every ascending sequence ->
// 2x guesses
if (!ascending) {
baseGuesses *= 2;
}
return baseGuesses * token.length;

@@ -28,0 +26,0 @@ });

@@ -9,4 +9,4 @@ 'use strict';

let baseGuesses = 0;
const startingPoints = ['a', 'A', 'z', 'Z', '0', '1', '9']; // lower guesses for obvious starting points
const startingPoints = ['a', 'A', 'z', 'Z', '0', '1', '9'];
// lower guesses for obvious starting points
if (startingPoints.includes(firstChr)) {

@@ -20,10 +20,8 @@ baseGuesses = 4;

baseGuesses = 26;
} // need to try a descending sequence in addition to every ascending sequence ->
}
// need to try a descending sequence in addition to every ascending sequence ->
// 2x guesses
if (!ascending) {
baseGuesses *= 2;
}
return baseGuesses * token.length;

@@ -30,0 +28,0 @@ });

@@ -5,7 +5,5 @@ import zxcvbnOptions from '../../Options.esm.js';

let warning = zxcvbnOptions.translations.warnings.keyPattern;
if (match.turns === 1) {
warning = zxcvbnOptions.translations.warnings.straightRow;
}
return {

@@ -12,0 +10,0 @@ warning,

@@ -6,11 +6,9 @@ 'use strict';

var spatialMatcher = (match => {
let warning = Options["default"].translations.warnings.keyPattern;
let warning = Options.default.translations.warnings.keyPattern;
if (match.turns === 1) {
warning = Options["default"].translations.warnings.straightRow;
warning = Options.default.translations.warnings.straightRow;
}
return {
warning,
suggestions: [Options["default"].translations.suggestions.longerKeyboardPattern]
suggestions: [Options.default.translations.suggestions.longerKeyboardPattern]
};

@@ -17,0 +15,0 @@ });

@@ -9,3 +9,2 @@ import { extend, sorted } from '../../helper.esm.js';

*/
class MatchSpatial {

@@ -15,3 +14,2 @@ constructor() {

}
match({

@@ -27,13 +25,11 @@ password

}
checkIfShifted(graphName, password, index) {
if (!graphName.includes('keypad') && // initial character is shifted
if (!graphName.includes('keypad') &&
// initial character is shifted
this.SHIFTED_RX.test(password.charAt(index))) {
return 1;
}
return 0;
} // eslint-disable-next-line complexity, max-statements
}
// eslint-disable-next-line complexity, max-statements
helper(password, graph, graphName) {

@@ -44,3 +40,2 @@ let shiftedCount;

const passwordLength = password.length;
while (i < passwordLength - 1) {

@@ -50,4 +45,4 @@ let j = i + 1;

let turns = 0;
shiftedCount = this.checkIfShifted(graphName, password, i); // eslint-disable-next-line no-constant-condition
shiftedCount = this.checkIfShifted(graphName, password, i);
// eslint-disable-next-line no-constant-condition
while (true) {

@@ -58,19 +53,18 @@ const prevChar = password.charAt(j - 1);

let foundDirection = -1;
let curDirection = -1; // consider growing pattern by one character if j hasn't gone over the edge.
let curDirection = -1;
// consider growing pattern by one character if j hasn't gone over the edge.
if (j < passwordLength) {
const curChar = password.charAt(j);
const adjacentsLength = adjacents.length;
for (let k = 0; k < adjacentsLength; k += 1) {
const adjacent = adjacents[k];
curDirection += 1; // eslint-disable-next-line max-depth
curDirection += 1;
// eslint-disable-next-line max-depth
if (adjacent) {
const adjacentIndex = adjacent.indexOf(curChar); // eslint-disable-next-line max-depth
const adjacentIndex = adjacent.indexOf(curChar);
// eslint-disable-next-line max-depth
if (adjacentIndex !== -1) {
found = true;
foundDirection = curDirection; // eslint-disable-next-line max-depth
foundDirection = curDirection;
// eslint-disable-next-line max-depth
if (adjacentIndex === 1) {

@@ -82,5 +76,4 @@ // # index 1 in the adjacency means the key is shifted,

shiftedCount += 1;
} // eslint-disable-next-line max-depth
}
// eslint-disable-next-line max-depth
if (lastDirection !== foundDirection) {

@@ -93,3 +86,2 @@ // # adding a turn is correct even in the initial

}
break;

@@ -99,7 +91,7 @@ }

}
} // if the current pattern continued, extend j and try to grow again
}
// if the current pattern continued, extend j and try to grow again
if (found) {
j += 1; // otherwise push the pattern discovered so far, if any...
j += 1;
// otherwise push the pattern discovered so far, if any...
} else {

@@ -117,5 +109,4 @@ // don't consider length 1 or 2 chains.

});
} // ...and then start a new search for the rest of the password.
}
// ...and then start a new search for the rest of the password.
i = j;

@@ -126,6 +117,4 @@ break;

}
return matches;
}
}

@@ -132,0 +121,0 @@

@@ -11,3 +11,2 @@ 'use strict';

*/
class MatchSpatial {

@@ -17,3 +16,2 @@ constructor() {

}
match({

@@ -23,4 +21,4 @@ password

const matches = [];
Object.keys(Options["default"].graphs).forEach(graphName => {
const graph = Options["default"].graphs[graphName];
Object.keys(Options.default.graphs).forEach(graphName => {
const graph = Options.default.graphs[graphName];
helper.extend(matches, this.helper(password, graph, graphName));

@@ -30,13 +28,11 @@ });

}
checkIfShifted(graphName, password, index) {
if (!graphName.includes('keypad') && // initial character is shifted
if (!graphName.includes('keypad') &&
// initial character is shifted
this.SHIFTED_RX.test(password.charAt(index))) {
return 1;
}
return 0;
} // eslint-disable-next-line complexity, max-statements
}
// eslint-disable-next-line complexity, max-statements
helper(password, graph, graphName) {

@@ -47,3 +43,2 @@ let shiftedCount;

const passwordLength = password.length;
while (i < passwordLength - 1) {

@@ -53,4 +48,4 @@ let j = i + 1;

let turns = 0;
shiftedCount = this.checkIfShifted(graphName, password, i); // eslint-disable-next-line no-constant-condition
shiftedCount = this.checkIfShifted(graphName, password, i);
// eslint-disable-next-line no-constant-condition
while (true) {

@@ -61,19 +56,18 @@ const prevChar = password.charAt(j - 1);

let foundDirection = -1;
let curDirection = -1; // consider growing pattern by one character if j hasn't gone over the edge.
let curDirection = -1;
// consider growing pattern by one character if j hasn't gone over the edge.
if (j < passwordLength) {
const curChar = password.charAt(j);
const adjacentsLength = adjacents.length;
for (let k = 0; k < adjacentsLength; k += 1) {
const adjacent = adjacents[k];
curDirection += 1; // eslint-disable-next-line max-depth
curDirection += 1;
// eslint-disable-next-line max-depth
if (adjacent) {
const adjacentIndex = adjacent.indexOf(curChar); // eslint-disable-next-line max-depth
const adjacentIndex = adjacent.indexOf(curChar);
// eslint-disable-next-line max-depth
if (adjacentIndex !== -1) {
found = true;
foundDirection = curDirection; // eslint-disable-next-line max-depth
foundDirection = curDirection;
// eslint-disable-next-line max-depth
if (adjacentIndex === 1) {

@@ -85,5 +79,4 @@ // # index 1 in the adjacency means the key is shifted,

shiftedCount += 1;
} // eslint-disable-next-line max-depth
}
// eslint-disable-next-line max-depth
if (lastDirection !== foundDirection) {

@@ -96,3 +89,2 @@ // # adding a turn is correct even in the initial

}
break;

@@ -102,7 +94,7 @@ }

}
} // if the current pattern continued, extend j and try to grow again
}
// if the current pattern continued, extend j and try to grow again
if (found) {
j += 1; // otherwise push the pattern discovered so far, if any...
j += 1;
// otherwise push the pattern discovered so far, if any...
} else {

@@ -120,5 +112,4 @@ // don't consider length 1 or 2 chains.

});
} // ...and then start a new search for the rest of the password.
}
// ...and then start a new search for the rest of the password.
i = j;

@@ -129,6 +120,4 @@ break;

}
return matches;
}
}

@@ -135,0 +124,0 @@

@@ -13,3 +13,2 @@ import utils from '../../scoring/utils.esm.js';

};
const estimatePossiblePatterns = ({

@@ -23,7 +22,6 @@ token,

let guesses = 0;
const tokenLength = token.length; // # estimate the number of possible patterns w/ tokenLength or less with turns or less.
const tokenLength = token.length;
// # estimate the number of possible patterns w/ tokenLength or less with turns or less.
for (let i = 2; i <= tokenLength; i += 1) {
const possibleTurns = Math.min(turns, i - 1);
for (let j = 1; j <= possibleTurns; j += 1) {

@@ -33,6 +31,4 @@ guesses += utils.nCk(i - 1, j - 1) * startingPosition * averageDegree ** j;

}
return guesses;
};
var spatialMatcher = (({

@@ -48,8 +44,7 @@ graph,

turns
}); // add extra guesses for shifted keys. (% instead of 5, A instead of a.)
});
// add extra guesses for shifted keys. (% instead of 5, A instead of a.)
// math is similar to extra guesses of l33t substitutions in dictionary matches.
if (shiftedCount) {
const unShiftedCount = token.length - shiftedCount;
if (shiftedCount === 0 || unShiftedCount === 0) {

@@ -59,11 +54,8 @@ guesses *= 2;

let shiftedVariations = 0;
for (let i = 1; i <= Math.min(shiftedCount, unShiftedCount); i += 1) {
shiftedVariations += utils.nCk(shiftedCount + unShiftedCount, i);
}
guesses *= shiftedVariations;
}
}
return Math.round(guesses);

@@ -70,0 +62,0 @@ });

@@ -15,3 +15,2 @@ 'use strict';

};
const estimatePossiblePatterns = ({

@@ -22,10 +21,9 @@ token,

}) => {
const startingPosition = Object.keys(Options["default"].graphs[graph]).length;
const averageDegree = calcAverageDegree(Options["default"].graphs[graph]);
const startingPosition = Object.keys(Options.default.graphs[graph]).length;
const averageDegree = calcAverageDegree(Options.default.graphs[graph]);
let guesses = 0;
const tokenLength = token.length; // # estimate the number of possible patterns w/ tokenLength or less with turns or less.
const tokenLength = token.length;
// # estimate the number of possible patterns w/ tokenLength or less with turns or less.
for (let i = 2; i <= tokenLength; i += 1) {
const possibleTurns = Math.min(turns, i - 1);
for (let j = 1; j <= possibleTurns; j += 1) {

@@ -35,6 +33,4 @@ guesses += utils.nCk(i - 1, j - 1) * startingPosition * averageDegree ** j;

}
return guesses;
};
var spatialMatcher = (({

@@ -50,8 +46,7 @@ graph,

turns
}); // add extra guesses for shifted keys. (% instead of 5, A instead of a.)
});
// add extra guesses for shifted keys. (% instead of 5, A instead of a.)
// math is similar to extra guesses of l33t substitutions in dictionary matches.
if (shiftedCount) {
const unShiftedCount = token.length - shiftedCount;
if (shiftedCount === 0 || unShiftedCount === 0) {

@@ -61,11 +56,8 @@ guesses *= 2;

let shiftedVariations = 0;
for (let i = 1; i <= Math.min(shiftedCount, unShiftedCount); i += 1) {
shiftedVariations += utils.nCk(shiftedCount + unShiftedCount, i);
}
guesses *= shiftedVariations;
}
}
return Math.round(guesses);

@@ -72,0 +64,0 @@ });

import { MatchExtended, MatchingType } from './types';
declare type Matchers = {
type Matchers = {
[key: string]: MatchingType;

@@ -4,0 +4,0 @@ };

@@ -22,3 +22,2 @@ import { extend, sorted } from './helper.esm.js';

}
match(password) {

@@ -32,3 +31,2 @@ const matches = [];

}
const Matcher = this.matchers[key] ? this.matchers[key] : zxcvbnOptions.matchers[key].Matching;

@@ -40,3 +38,2 @@ const usedMatcher = new Matcher();

});
if (result instanceof Promise) {

@@ -51,3 +48,2 @@ result.then(response => {

});
if (promises.length > 0) {

@@ -60,6 +56,4 @@ return new Promise(resolve => {

}
return sorted(matches);
}
}

@@ -66,0 +60,0 @@

@@ -24,13 +24,11 @@ 'use strict';

}
match(password) {
const matches = [];
const promises = [];
const matchers = [...Object.keys(this.matchers), ...Object.keys(Options["default"].matchers)];
const matchers = [...Object.keys(this.matchers), ...Object.keys(Options.default.matchers)];
matchers.forEach(key => {
if (!this.matchers[key] && !Options["default"].matchers[key]) {
if (!this.matchers[key] && !Options.default.matchers[key]) {
return;
}
const Matcher = this.matchers[key] ? this.matchers[key] : Options["default"].matchers[key].Matching;
const Matcher = this.matchers[key] ? this.matchers[key] : Options.default.matchers[key].Matching;
const usedMatcher = new Matcher();

@@ -41,3 +39,2 @@ const result = usedMatcher.match({

});
if (result instanceof Promise) {

@@ -52,3 +49,2 @@ result.then(response => {

});
if (promises.length > 0) {

@@ -61,6 +57,4 @@ return new Promise(resolve => {

}
return helper.sorted(matches);
}
}

@@ -67,0 +61,0 @@

@@ -7,2 +7,3 @@ import { TranslationKeys, OptionsType, OptionsDictionary, OptionsL33tTable, OptionsGraph, RankedDictionaries, Matchers, Matcher } from './types';

rankedDictionaries: RankedDictionaries;
rankedDictionariesMaxWordSize: Record<string, number>;
translations: TranslationKeys;

@@ -13,2 +14,3 @@ graphs: OptionsGraph;

levenshteinThreshold: number;
l33tMaxSubstitutions: number;
constructor();

@@ -19,2 +21,3 @@ setOptions(options?: OptionsType): void;

setRankedDictionaries(): void;
getRankedDictionariesMaxWordSize(name: string): number;
getRankedDictionary(name: string): import("./types").LooseObject;

@@ -21,0 +24,0 @@ extendUserInputsDictionary(dictionary: (string | number)[]): void;

@@ -13,2 +13,3 @@ import { buildRankedDictionary } from './helper.esm.js';

this.rankedDictionaries = {};
this.rankedDictionariesMaxWordSize = {};
this.translations = translationKeys;

@@ -19,5 +20,6 @@ this.graphs = {};

this.levenshteinThreshold = 2;
this.l33tMaxSubstitutions = 100;
this.setRankedDictionaries();
}
// eslint-disable-next-line max-statements
setOptions(options = {}) {

@@ -27,3 +29,2 @@ if (options.l33tTable) {

}
if (options.dictionary) {

@@ -33,20 +34,18 @@ this.dictionary = options.dictionary;

}
if (options.translations) {
this.setTranslations(options.translations);
}
if (options.graphs) {
this.graphs = options.graphs;
}
if (options.useLevenshteinDistance !== undefined) {
this.useLevenshteinDistance = options.useLevenshteinDistance;
}
if (options.levenshteinThreshold !== undefined) {
this.levenshteinThreshold = options.levenshteinThreshold;
}
if (options.l33tMaxSubstitutions !== undefined) {
this.l33tMaxSubstitutions = options.l33tMaxSubstitutions;
}
}
setTranslations(translations) {

@@ -59,3 +58,2 @@ if (this.checkCustomTranslations(translations)) {

}
checkCustomTranslations(translations) {

@@ -77,14 +75,24 @@ let valid = true;

}
setRankedDictionaries() {
const rankedDictionaries = {};
const rankedDictionariesMaxWorkSize = {};
Object.keys(this.dictionary).forEach(name => {
rankedDictionaries[name] = this.getRankedDictionary(name);
rankedDictionariesMaxWorkSize[name] = this.getRankedDictionariesMaxWordSize(name);
});
this.rankedDictionaries = rankedDictionaries;
this.rankedDictionariesMaxWordSize = rankedDictionariesMaxWorkSize;
}
getRankedDictionariesMaxWordSize(name) {
const data = this.dictionary[name].map(el => {
if (typeof el !== 'string') {
return el.toString().length;
}
return el.length;
});
const result = data.length === 0 ? 0 : Math.max(...data);
return result;
}
getRankedDictionary(name) {
const list = this.dictionary[name];
if (name === 'userInputs') {

@@ -94,3 +102,2 @@ const sanitizedInputs = [];

const inputType = typeof input;
if (inputType === 'string' || inputType === 'number' || inputType === 'boolean') {

@@ -102,6 +109,4 @@ sanitizedInputs.push(input.toString().toLowerCase());

}
return buildRankedDictionary(list);
}
extendUserInputsDictionary(dictionary) {

@@ -113,6 +118,5 @@ if (this.dictionary.userInputs) {

}
this.rankedDictionaries.userInputs = this.getRankedDictionary('userInputs');
this.rankedDictionariesMaxWordSize.userInputs = this.getRankedDictionariesMaxWordSize('userInputs');
}
addMatcher(name, matcher) {

@@ -125,3 +129,2 @@ if (this.matchers[name]) {

}
}

@@ -128,0 +131,0 @@ const zxcvbnOptions = new Options();

@@ -17,2 +17,3 @@ 'use strict';

this.rankedDictionaries = {};
this.rankedDictionariesMaxWordSize = {};
this.translations = translationKeys;

@@ -23,5 +24,6 @@ this.graphs = {};

this.levenshteinThreshold = 2;
this.l33tMaxSubstitutions = 100;
this.setRankedDictionaries();
}
// eslint-disable-next-line max-statements
setOptions(options = {}) {

@@ -31,3 +33,2 @@ if (options.l33tTable) {

}
if (options.dictionary) {

@@ -37,20 +38,18 @@ this.dictionary = options.dictionary;

}
if (options.translations) {
this.setTranslations(options.translations);
}
if (options.graphs) {
this.graphs = options.graphs;
}
if (options.useLevenshteinDistance !== undefined) {
this.useLevenshteinDistance = options.useLevenshteinDistance;
}
if (options.levenshteinThreshold !== undefined) {
this.levenshteinThreshold = options.levenshteinThreshold;
}
if (options.l33tMaxSubstitutions !== undefined) {
this.l33tMaxSubstitutions = options.l33tMaxSubstitutions;
}
}
setTranslations(translations) {

@@ -63,3 +62,2 @@ if (this.checkCustomTranslations(translations)) {

}
checkCustomTranslations(translations) {

@@ -81,14 +79,24 @@ let valid = true;

}
setRankedDictionaries() {
const rankedDictionaries = {};
const rankedDictionariesMaxWorkSize = {};
Object.keys(this.dictionary).forEach(name => {
rankedDictionaries[name] = this.getRankedDictionary(name);
rankedDictionariesMaxWorkSize[name] = this.getRankedDictionariesMaxWordSize(name);
});
this.rankedDictionaries = rankedDictionaries;
this.rankedDictionariesMaxWordSize = rankedDictionariesMaxWorkSize;
}
getRankedDictionariesMaxWordSize(name) {
const data = this.dictionary[name].map(el => {
if (typeof el !== 'string') {
return el.toString().length;
}
return el.length;
});
const result = data.length === 0 ? 0 : Math.max(...data);
return result;
}
getRankedDictionary(name) {
const list = this.dictionary[name];
if (name === 'userInputs') {

@@ -98,3 +106,2 @@ const sanitizedInputs = [];

const inputType = typeof input;
if (inputType === 'string' || inputType === 'number' || inputType === 'boolean') {

@@ -106,6 +113,4 @@ sanitizedInputs.push(input.toString().toLowerCase());

}
return helper.buildRankedDictionary(list);
}
extendUserInputsDictionary(dictionary) {

@@ -117,6 +122,5 @@ if (this.dictionary.userInputs) {

}
this.rankedDictionaries.userInputs = this.getRankedDictionary('userInputs');
this.rankedDictionariesMaxWordSize.userInputs = this.getRankedDictionariesMaxWordSize('userInputs');
}
addMatcher(name, matcher) {

@@ -129,3 +133,2 @@ if (this.matchers[name]) {

}
}

@@ -135,3 +138,3 @@ const zxcvbnOptions = new Options();

exports.Options = Options;
exports["default"] = zxcvbnOptions;
exports.default = zxcvbnOptions;
//# sourceMappingURL=Options.js.map

@@ -14,3 +14,2 @@ import { MIN_SUBMATCH_GUESSES_SINGLE_CHAR, MIN_SUBMATCH_GUESSES_MULTI_CHAR } from '../data/const.esm.js';

let minGuesses = 1;
if (match.token.length < password.length) {

@@ -23,6 +22,4 @@ if (match.token.length === 1) {

}
return minGuesses;
};
const matchers = {

@@ -37,3 +34,2 @@ bruteforce: bruteforceMatcher,

};
const getScoring = (name, match) => {

@@ -43,24 +39,19 @@ if (matchers[name]) {

}
if (zxcvbnOptions.matchers[name] && 'scoring' in zxcvbnOptions.matchers[name]) {
return zxcvbnOptions.matchers[name].scoring(match);
}
return 0;
}; // ------------------------------------------------------------------------------
};
// ------------------------------------------------------------------------------
// guess estimation -- one function per match pattern ---------------------------
// ------------------------------------------------------------------------------
var estimateGuesses = ((match, password) => {
const extraData = {}; // a match's guess estimate doesn't change. cache it.
const extraData = {};
// a match's guess estimate doesn't change. cache it.
if ('guesses' in match && match.guesses != null) {
return match;
}
const minGuesses = getMinGuesses(match, password);
const estimationResult = getScoring(match.pattern, match);
let guesses = 0;
if (typeof estimationResult === 'number') {

@@ -74,5 +65,5 @@ guesses = estimationResult;

}
const matchGuesses = Math.max(guesses, minGuesses);
return { ...match,
return {
...match,
...extraData,

@@ -79,0 +70,0 @@ guesses: matchGuesses,

@@ -16,3 +16,2 @@ 'use strict';

let minGuesses = 1;
if (match.token.length < password.length) {

@@ -25,6 +24,4 @@ if (match.token.length === 1) {

}
return minGuesses;
};
const matchers = {

@@ -39,3 +36,2 @@ bruteforce: scoring,

};
const getScoring = (name, match) => {

@@ -45,24 +41,19 @@ if (matchers[name]) {

}
if (Options["default"].matchers[name] && 'scoring' in Options["default"].matchers[name]) {
return Options["default"].matchers[name].scoring(match);
if (Options.default.matchers[name] && 'scoring' in Options.default.matchers[name]) {
return Options.default.matchers[name].scoring(match);
}
return 0;
}; // ------------------------------------------------------------------------------
};
// ------------------------------------------------------------------------------
// guess estimation -- one function per match pattern ---------------------------
// ------------------------------------------------------------------------------
var estimateGuesses = ((match, password) => {
const extraData = {}; // a match's guess estimate doesn't change. cache it.
const extraData = {};
// a match's guess estimate doesn't change. cache it.
if ('guesses' in match && match.guesses != null) {
return match;
}
const minGuesses = getMinGuesses(match, password);
const estimationResult = getScoring(match.pattern, match);
let guesses = 0;
if (typeof estimationResult === 'number') {

@@ -76,5 +67,5 @@ guesses = estimationResult;

}
const matchGuesses = Math.max(guesses, minGuesses);
return { ...match,
return {
...match,
...extraData,

@@ -81,0 +72,0 @@ guesses: matchGuesses,

@@ -9,19 +9,13 @@ import utils from './utils.esm.js';

excludeAdditive: false,
fillArray(size, valueType) {
const result = [];
for (let i = 0; i < size; i += 1) {
let value = [];
if (valueType === 'object') {
value = {};
}
result.push(value);
}
return result;
},
// helper: make bruteforce match objects spanning i to j, inclusive.

@@ -36,3 +30,2 @@ makeBruteforceMatch(i, j) {

},
// helper: considers whether a length-sequenceLength

@@ -45,3 +38,2 @@ // sequence ending at match m is better (fewer guesses)

let pi = estimatedMatch.guesses;
if (sequenceLength > 1) {

@@ -53,19 +45,15 @@ // we're considering a length-sequenceLength sequence ending with match m:

pi *= this.optimal.pi[estimatedMatch.i - 1][sequenceLength - 1];
} // calculate the minimization func
}
// calculate the minimization func
let g = utils.factorial(sequenceLength) * pi;
if (!this.excludeAdditive) {
g += MIN_GUESSES_BEFORE_GROWING_SEQUENCE ** (sequenceLength - 1);
} // update state if new best.
}
// update state if new best.
// first see if any competing sequences covering this prefix,
// with sequenceLength or fewer matches,
// fare better than this sequence. if so, skip it and return.
let shouldSkip = false;
Object.keys(this.optimal.g[k]).forEach(competingPatternLength => {
const competingMetricMatch = this.optimal.g[k][competingPatternLength];
if (parseInt(competingPatternLength, 10) <= sequenceLength) {

@@ -77,3 +65,2 @@ if (competingMetricMatch <= g) {

});
if (!shouldSkip) {

@@ -86,3 +73,2 @@ // this sequence might be part of the final optimal sequence.

},
// helper: evaluate bruteforce matches ending at passwordCharIndex.

@@ -93,3 +79,2 @@ bruteforceUpdate(passwordCharIndex) {

this.update(match, 1);
for (let i = 1; i <= passwordCharIndex; i += 1) {

@@ -100,10 +85,10 @@ // generate passwordCharIndex bruteforce matches, spanning from (i=1, j=passwordCharIndex) up to (i=passwordCharIndex, j=passwordCharIndex).

match = this.makeBruteforceMatch(i, passwordCharIndex);
const tmp = this.optimal.m[i - 1]; // eslint-disable-next-line no-loop-func
const tmp = this.optimal.m[i - 1];
// eslint-disable-next-line no-loop-func
Object.keys(tmp).forEach(sequenceLength => {
const lastMatch = tmp[sequenceLength]; // corner: an optimal sequence will never have two adjacent bruteforce matches.
const lastMatch = tmp[sequenceLength];
// corner: an optimal sequence will never have two adjacent bruteforce matches.
// it is strictly better to have a single bruteforce match spanning the same region:
// same contribution to the guess product with a lower length.
// --> safe to skip those cases.
if (lastMatch.pattern !== 'bruteforce') {

@@ -116,3 +101,2 @@ // try adding m to this length-sequenceLength sequence.

},
// helper: step backwards through optimal.m starting at the end,

@@ -122,13 +106,12 @@ // constructing the final optimal match sequence.

const optimalMatchSequence = [];
let k = passwordLength - 1; // find the final best sequence length and score
let sequenceLength = 0; // eslint-disable-next-line no-loss-of-precision
let k = passwordLength - 1;
// find the final best sequence length and score
let sequenceLength = 0;
// eslint-disable-next-line no-loss-of-precision
let g = 2e308;
const temp = this.optimal.g[k]; // safety check for empty passwords
const temp = this.optimal.g[k];
// safety check for empty passwords
if (temp) {
Object.keys(temp).forEach(candidateSequenceLength => {
const candidateMetricMatch = temp[candidateSequenceLength];
if (candidateMetricMatch < g) {

@@ -140,3 +123,2 @@ sequenceLength = parseInt(candidateSequenceLength, 10);

}
while (k >= 0) {

@@ -148,6 +130,4 @@ const match = this.optimal.m[k][sequenceLength];

}
return optimalMatchSequence;
}
};

@@ -190,9 +170,9 @@ var scoring = {

scoringHelper.excludeAdditive = excludeAdditive;
const passwordLength = password.length; // partition matches into sublists according to ending index j
const passwordLength = password.length;
// partition matches into sublists according to ending index j
let matchesByCoordinateJ = scoringHelper.fillArray(passwordLength, 'array');
matches.forEach(match => {
matchesByCoordinateJ[match.j].push(match);
}); // small detail: for deterministic output, sort each sublist by i.
});
// small detail: for deterministic output, sort each sublist by i.
matchesByCoordinateJ = matchesByCoordinateJ.map(match => match.sort((m1, m2) => m1.i - m2.i));

@@ -213,3 +193,2 @@ scoringHelper.optimal = {

};
for (let k = 0; k < passwordLength; k += 1) {

@@ -227,3 +206,2 @@ matchesByCoordinateJ[k].forEach(match => {

}
const optimalMatchSequence = scoringHelper.unwind(passwordLength);

@@ -239,7 +217,5 @@ const optimalSequenceLength = optimalMatchSequence.length;

},
getGuesses(password, optimalSequenceLength) {
const passwordLength = password.length;
let guesses = 0;
if (password.length === 0) {

@@ -250,6 +226,4 @@ guesses = 1;

}
return guesses;
}
};

@@ -256,0 +230,0 @@

@@ -11,19 +11,13 @@ 'use strict';

excludeAdditive: false,
fillArray(size, valueType) {
const result = [];
for (let i = 0; i < size; i += 1) {
let value = [];
if (valueType === 'object') {
value = {};
}
result.push(value);
}
return result;
},
// helper: make bruteforce match objects spanning i to j, inclusive.

@@ -38,3 +32,2 @@ makeBruteforceMatch(i, j) {

},
// helper: considers whether a length-sequenceLength

@@ -47,3 +40,2 @@ // sequence ending at match m is better (fewer guesses)

let pi = estimatedMatch.guesses;
if (sequenceLength > 1) {

@@ -55,19 +47,15 @@ // we're considering a length-sequenceLength sequence ending with match m:

pi *= this.optimal.pi[estimatedMatch.i - 1][sequenceLength - 1];
} // calculate the minimization func
}
// calculate the minimization func
let g = utils.factorial(sequenceLength) * pi;
if (!this.excludeAdditive) {
g += _const.MIN_GUESSES_BEFORE_GROWING_SEQUENCE ** (sequenceLength - 1);
} // update state if new best.
}
// update state if new best.
// first see if any competing sequences covering this prefix,
// with sequenceLength or fewer matches,
// fare better than this sequence. if so, skip it and return.
let shouldSkip = false;
Object.keys(this.optimal.g[k]).forEach(competingPatternLength => {
const competingMetricMatch = this.optimal.g[k][competingPatternLength];
if (parseInt(competingPatternLength, 10) <= sequenceLength) {

@@ -79,3 +67,2 @@ if (competingMetricMatch <= g) {

});
if (!shouldSkip) {

@@ -88,3 +75,2 @@ // this sequence might be part of the final optimal sequence.

},
// helper: evaluate bruteforce matches ending at passwordCharIndex.

@@ -95,3 +81,2 @@ bruteforceUpdate(passwordCharIndex) {

this.update(match, 1);
for (let i = 1; i <= passwordCharIndex; i += 1) {

@@ -102,10 +87,10 @@ // generate passwordCharIndex bruteforce matches, spanning from (i=1, j=passwordCharIndex) up to (i=passwordCharIndex, j=passwordCharIndex).

match = this.makeBruteforceMatch(i, passwordCharIndex);
const tmp = this.optimal.m[i - 1]; // eslint-disable-next-line no-loop-func
const tmp = this.optimal.m[i - 1];
// eslint-disable-next-line no-loop-func
Object.keys(tmp).forEach(sequenceLength => {
const lastMatch = tmp[sequenceLength]; // corner: an optimal sequence will never have two adjacent bruteforce matches.
const lastMatch = tmp[sequenceLength];
// corner: an optimal sequence will never have two adjacent bruteforce matches.
// it is strictly better to have a single bruteforce match spanning the same region:
// same contribution to the guess product with a lower length.
// --> safe to skip those cases.
if (lastMatch.pattern !== 'bruteforce') {

@@ -118,3 +103,2 @@ // try adding m to this length-sequenceLength sequence.

},
// helper: step backwards through optimal.m starting at the end,

@@ -124,13 +108,12 @@ // constructing the final optimal match sequence.

const optimalMatchSequence = [];
let k = passwordLength - 1; // find the final best sequence length and score
let sequenceLength = 0; // eslint-disable-next-line no-loss-of-precision
let k = passwordLength - 1;
// find the final best sequence length and score
let sequenceLength = 0;
// eslint-disable-next-line no-loss-of-precision
let g = 2e308;
const temp = this.optimal.g[k]; // safety check for empty passwords
const temp = this.optimal.g[k];
// safety check for empty passwords
if (temp) {
Object.keys(temp).forEach(candidateSequenceLength => {
const candidateMetricMatch = temp[candidateSequenceLength];
if (candidateMetricMatch < g) {

@@ -142,3 +125,2 @@ sequenceLength = parseInt(candidateSequenceLength, 10);

}
while (k >= 0) {

@@ -150,6 +132,4 @@ const match = this.optimal.m[k][sequenceLength];

}
return optimalMatchSequence;
}
};

@@ -192,9 +172,9 @@ var scoring = {

scoringHelper.excludeAdditive = excludeAdditive;
const passwordLength = password.length; // partition matches into sublists according to ending index j
const passwordLength = password.length;
// partition matches into sublists according to ending index j
let matchesByCoordinateJ = scoringHelper.fillArray(passwordLength, 'array');
matches.forEach(match => {
matchesByCoordinateJ[match.j].push(match);
}); // small detail: for deterministic output, sort each sublist by i.
});
// small detail: for deterministic output, sort each sublist by i.
matchesByCoordinateJ = matchesByCoordinateJ.map(match => match.sort((m1, m2) => m1.i - m2.i));

@@ -215,3 +195,2 @@ scoringHelper.optimal = {

};
for (let k = 0; k < passwordLength; k += 1) {

@@ -229,3 +208,2 @@ matchesByCoordinateJ[k].forEach(match => {

}
const optimalMatchSequence = scoringHelper.unwind(passwordLength);

@@ -241,7 +219,5 @@ const optimalSequenceLength = optimalMatchSequence.length;

},
getGuesses(password, optimalSequenceLength) {
const passwordLength = password.length;
let guesses = 0;
if (password.length === 0) {

@@ -252,6 +228,4 @@ guesses = 1;

}
return guesses;
}
};

@@ -258,0 +232,0 @@

@@ -6,13 +6,9 @@ var utils = {

let count = n;
if (k > count) {
return 0;
}
if (k === 0) {
return 1;
}
let coEff = 1;
for (let i = 1; i <= k; i += 1) {

@@ -23,6 +19,4 @@ coEff *= count;

}
return coEff;
},
log10(n) {

@@ -35,11 +29,7 @@ return Math.log(n) / Math.log(10); // IE doesn't support Math.log10 :(

},
factorial(num) {
let rval = 1;
for (let i = 2; i <= num; i += 1) rval *= i;
return rval;
}
};

@@ -46,0 +36,0 @@

@@ -8,13 +8,9 @@ 'use strict';

let count = n;
if (k > count) {
return 0;
}
if (k === 0) {
return 1;
}
let coEff = 1;
for (let i = 1; i <= k; i += 1) {

@@ -25,6 +21,4 @@ coEff *= count;

}
return coEff;
},
log10(n) {

@@ -37,11 +31,7 @@ return Math.log(n) / Math.log(10); // IE doesn't support Math.log10 :(

},
factorial(num) {
let rval = 1;
for (let i = 2; i <= num; i += 1) rval *= i;
return rval;
}
};

@@ -48,0 +38,0 @@

@@ -1,2 +0,2 @@

import { CrackTimesDisplay, CrackTimesSeconds } from './types';
import { CrackTimesDisplay, CrackTimesSeconds, Score } from './types';
declare class TimeEstimates {

@@ -7,7 +7,7 @@ translate(displayStr: string, value: number | undefined): string;

crackTimesDisplay: CrackTimesDisplay;
score: number;
score: Score;
};
guessesToScore(guesses: number): 1 | 2 | 3 | 4 | 0;
guessesToScore(guesses: number): Score;
displayTime(seconds: number): string;
}
export default TimeEstimates;

@@ -24,11 +24,8 @@ import zxcvbnOptions from './Options.esm.js';

*/
class TimeEstimates {
translate(displayStr, value) {
let key = displayStr;
if (value !== undefined && value !== 1) {
key += 's';
}
const {

@@ -39,3 +36,2 @@ timeEstimation

}
estimateAttackTimes(guesses) {

@@ -64,6 +60,4 @@ const crackTimesSeconds = {

}
guessesToScore(guesses) {
const DELTA = 5;
if (guesses < 1e3 + DELTA) {

@@ -73,3 +67,2 @@ // risky password: "too guessable"

}
if (guesses < 1e6 + DELTA) {

@@ -79,3 +72,2 @@ // modest protection from throttled online attacks: "very guessable"

}
if (guesses < 1e8 + DELTA) {

@@ -85,3 +77,2 @@ // modest protection from unthrottled online attacks: "somewhat guessable"

}
if (guesses < 1e10 + DELTA) {

@@ -91,8 +82,6 @@ // modest protection from offline attacks: "safely unguessable"

return 3;
} // strong protection from offline attacks under same scenario: "very unguessable"
}
// strong protection from offline attacks under same scenario: "very unguessable"
return 4;
}
displayTime(seconds) {

@@ -103,6 +92,4 @@ let displayStr = 'centuries';

const foundIndex = timeKeys.findIndex(time => seconds < times[time]);
if (foundIndex > -1) {
displayStr = timeKeys[foundIndex - 1];
if (foundIndex !== 0) {

@@ -114,6 +101,4 @@ base = Math.round(seconds / times[displayStr]);

}
return this.translate(displayStr, base);
}
}

@@ -120,0 +105,0 @@

@@ -26,17 +26,13 @@ 'use strict';

*/
class TimeEstimates {
translate(displayStr, value) {
let key = displayStr;
if (value !== undefined && value !== 1) {
key += 's';
}
const {
timeEstimation
} = Options["default"].translations;
} = Options.default.translations;
return timeEstimation[key].replace('{base}', `${value}`);
}
estimateAttackTimes(guesses) {

@@ -65,6 +61,4 @@ const crackTimesSeconds = {

}
guessesToScore(guesses) {
const DELTA = 5;
if (guesses < 1e3 + DELTA) {

@@ -74,3 +68,2 @@ // risky password: "too guessable"

}
if (guesses < 1e6 + DELTA) {

@@ -80,3 +73,2 @@ // modest protection from throttled online attacks: "very guessable"

}
if (guesses < 1e8 + DELTA) {

@@ -86,3 +78,2 @@ // modest protection from unthrottled online attacks: "somewhat guessable"

}
if (guesses < 1e10 + DELTA) {

@@ -92,8 +83,6 @@ // modest protection from offline attacks: "safely unguessable"

return 3;
} // strong protection from offline attacks under same scenario: "very unguessable"
}
// strong protection from offline attacks under same scenario: "very unguessable"
return 4;
}
displayTime(seconds) {

@@ -104,6 +93,4 @@ let displayStr = 'centuries';

const foundIndex = timeKeys.findIndex(time => seconds < times[time]);
if (foundIndex > -1) {
displayStr = timeKeys[foundIndex - 1];
if (foundIndex !== 0) {

@@ -115,6 +102,4 @@ base = Math.round(seconds / times[displayStr]);

}
return this.translate(displayStr, base);
}
}

@@ -121,0 +106,0 @@

@@ -6,9 +6,9 @@ import translationKeys from './data/translationKeys';

import Matching from './Matching';
export declare type TranslationKeys = typeof translationKeys;
export declare type L33tTableDefault = typeof l33tTableDefault;
export type TranslationKeys = typeof translationKeys;
export type L33tTableDefault = typeof l33tTableDefault;
export interface LooseObject {
[key: string]: any;
}
export declare type Pattern = 'dictionary' | 'spatial' | 'repeat' | 'sequence' | 'regex' | 'date' | 'bruteforce' | string;
export declare type DictionaryNames = 'passwords' | 'commonWords' | 'firstnames' | 'lastnames' | 'wikipedia' | 'userInputs';
export type Pattern = 'dictionary' | 'spatial' | 'repeat' | 'sequence' | 'regex' | 'date' | 'bruteforce' | string;
export type DictionaryNames = 'passwords' | 'commonWords' | 'firstnames' | 'lastnames' | 'wikipedia' | 'userInputs';
export interface Match {

@@ -66,3 +66,3 @@ pattern: Pattern;

}
export declare type MatchExtended = DictionaryMatch | L33tMatch | SpatialMatch | RepeatMatch | SequenceMatch | RegexMatch | DateMatch | BruteForceMatch | Match;
export type MatchExtended = DictionaryMatch | L33tMatch | SpatialMatch | RepeatMatch | SequenceMatch | RegexMatch | DateMatch | BruteForceMatch | Match;
export interface Estimate {

@@ -75,3 +75,3 @@ guesses: number;

}
export declare type MatchEstimated = MatchExtended & Estimate;
export type MatchEstimated = MatchExtended & Estimate;
export interface Optimal {

@@ -98,6 +98,6 @@ m: Match;

}
export declare type OptionsL33tTable = L33tTableDefault | {
export type OptionsL33tTable = L33tTableDefault | {
[key: string]: string[];
};
export declare type OptionsDictionary = {
export type OptionsDictionary = {
[key: string]: (string | number)[];

@@ -118,2 +118,3 @@ };

levenshteinThreshold?: number;
l33tMaxSubstitutions?: number;
}

@@ -126,4 +127,4 @@ export interface RankedDictionary {

}
export declare type DefaultFeedbackFunction = (match: MatchEstimated, isSoleMatch?: Boolean) => FeedbackType | null;
export declare type DefaultScoringFunction = (match: MatchExtended | MatchEstimated) => number | DictionaryReturn;
export type DefaultFeedbackFunction = (match: MatchEstimated, isSoleMatch?: boolean) => FeedbackType | null;
export type DefaultScoringFunction = (match: MatchExtended | MatchEstimated) => number | DictionaryReturn;
export interface MatchOptions {

@@ -133,3 +134,3 @@ password: string;

}
export declare type MatchingType = new () => {
export type MatchingType = new () => {
match({ password, omniMatch, }: MatchOptions): MatchExtended[] | Promise<MatchExtended[]>;

@@ -145,2 +146,3 @@ };

}
export type Score = 0 | 1 | 2 | 3 | 4;
export interface ZxcvbnResult {

@@ -150,3 +152,3 @@ feedback: FeedbackType;

crackTimesDisplay: CrackTimesDisplay;
score: number;
score: Score;
password: string;

@@ -153,0 +155,0 @@ guesses: number;

{
"name": "@zxcvbn-ts/core",
"version": "2.1.0",
"version": "2.2.0",
"main": "dist/index.js",

@@ -22,2 +22,5 @@ "module": "dist/index.esm.js",

},
"dependencies": {
"fastest-levenshtein": "1.0.16"
},
"keywords": [

@@ -38,3 +41,3 @@ "password",

],
"gitHead": "9f30e0aaab33ff51e3c3f4d4bbab23186e569008"
"gitHead": "a0315646a0e1f82771d9ac26ad0cac21f48ac0fe"
}

@@ -86,3 +86,3 @@ import zxcvbnOptions from './Options'

getMatchFeedback(match: MatchEstimated, isSoleMatch: Boolean) {
getMatchFeedback(match: MatchEstimated, isSoleMatch: boolean) {
if (this.matchers[match.pattern]) {

@@ -89,0 +89,0 @@ return this.matchers[match.pattern](match, isSoleMatch)

@@ -5,5 +5,5 @@ import Matching from './Matching'

import Feedback from './Feedback'
import zxcvbnOptions from './Options'
import zxcvbnOptions, { Options } from './Options'
import debounce from './debounce'
import { MatchExtended, ZxcvbnResult } from './types'
import { MatchExtended, ZxcvbnResult, Matcher, MatchOptions } from './types'

@@ -66,2 +66,10 @@ const time = () => new Date().getTime()

export { zxcvbnOptions, ZxcvbnResult, debounce }
export {
zxcvbnOptions,
ZxcvbnResult,
debounce,
Options,
Matcher,
MatchOptions,
MatchExtended,
}

@@ -1,2 +0,2 @@

import { distance } from './vendor/fastest-levenshtein'
import { distance } from 'fastest-levenshtein'
import { LooseObject } from './types'

@@ -3,0 +3,0 @@

@@ -7,3 +7,3 @@ import zxcvbnOptions from '../../Options'

match: MatchEstimated,
isSoleMatch?: Boolean,
isSoleMatch?: boolean,
) => {

@@ -27,3 +27,3 @@ let warning = ''

match: MatchEstimated,
isSoleMatch?: Boolean,
isSoleMatch?: boolean,
) => {

@@ -39,3 +39,3 @@ let warning = ''

match: MatchEstimated,
isSoleMatch?: Boolean,
isSoleMatch?: boolean,
) => {

@@ -48,3 +48,3 @@ if (isSoleMatch) {

const getDictionaryWarning = (match: MatchEstimated, isSoleMatch?: Boolean) => {
const getDictionaryWarning = (match: MatchEstimated, isSoleMatch?: boolean) => {
let warning = ''

@@ -66,3 +66,3 @@ const dictName = match.dictionaryName

export default (match: MatchEstimated, isSoleMatch?: Boolean) => {
export default (match: MatchEstimated, isSoleMatch?: boolean) => {
const warning = getDictionaryWarning(match, isSoleMatch)

@@ -69,0 +69,0 @@ const suggestions: string[] = []

@@ -9,7 +9,4 @@ import findLevenshteinDistance, {

import L33t from './variants/matching/l33t'
import { DictionaryMatchOptions } from './types'
interface DictionaryMatchOptions {
password: string
}
class MatchDictionary {

@@ -39,8 +36,12 @@ l33t: L33t

// eslint-disable-next-line complexity
// eslint-disable-next-line complexity,max-statements
Object.keys(zxcvbnOptions.rankedDictionaries).forEach((dictionaryName) => {
const rankedDict =
zxcvbnOptions.rankedDictionaries[dictionaryName as DictionaryNames]
const longestDictionaryWordSize =
zxcvbnOptions.rankedDictionariesMaxWordSize[dictionaryName]
const searchWidth = Math.min(longestDictionaryWordSize, passwordLength)
for (let i = 0; i < passwordLength; i += 1) {
for (let j = i; j < passwordLength; j += 1) {
const searchEnd = Math.min(i + searchWidth, passwordLength)
for (let j = i; j < searchEnd; j += 1) {
const usedPassword = passwordLower.slice(i, +j + 1 || 9e9)

@@ -47,0 +48,0 @@ const isInDictionary = usedPassword in rankedDict

@@ -9,2 +9,3 @@ import { empty, translate } from '../../../../helper'

} from '../../../../types'
import { DefaultMatch } from '../../types'

@@ -19,5 +20,5 @@ type Subs = string[][][]

class MatchL33t {
defaultMatch: Function
defaultMatch: DefaultMatch
constructor(defaultMatch: Function) {
constructor(defaultMatch: DefaultMatch) {
this.defaultMatch = defaultMatch

@@ -31,3 +32,7 @@ }

)
for (let i = 0; i < enumeratedSubs.length; i += 1) {
const length = Math.min(
enumeratedSubs.length,
zxcvbnOptions.l33tMaxSubstitutions,
)
for (let i = 0; i < length; i += 1) {
const sub = enumeratedSubs[i]

@@ -34,0 +39,0 @@ // corner case: password has no relevant subs.

import { DictionaryMatch } from '../../../../types'
import { DefaultMatch } from '../../types'

@@ -8,6 +9,6 @@ /*

*/
class MatchL33t {
defaultMatch: Function
class MatchReverse {
defaultMatch: DefaultMatch
constructor(defaultMatch: Function) {
constructor(defaultMatch: DefaultMatch) {
this.defaultMatch = defaultMatch

@@ -31,2 +32,2 @@ }

export default MatchL33t
export default MatchReverse

@@ -26,2 +26,4 @@ import { buildRankedDictionary } from './helper'

rankedDictionariesMaxWordSize: Record<string, number> = {}
translations: TranslationKeys = translationKeys

@@ -37,2 +39,4 @@

l33tMaxSubstitutions: number = 100
constructor() {

@@ -42,2 +46,3 @@ this.setRankedDictionaries()

// eslint-disable-next-line max-statements
setOptions(options: OptionsType = {}) {

@@ -69,2 +74,6 @@ if (options.l33tTable) {

}
if (options.l33tMaxSubstitutions !== undefined) {
this.l33tMaxSubstitutions = options.l33tMaxSubstitutions
}
}

@@ -99,8 +108,24 @@

const rankedDictionaries: RankedDictionaries = {}
const rankedDictionariesMaxWorkSize: Record<string, number> = {}
Object.keys(this.dictionary).forEach((name) => {
rankedDictionaries[name] = this.getRankedDictionary(name)
rankedDictionariesMaxWorkSize[name] =
this.getRankedDictionariesMaxWordSize(name)
})
this.rankedDictionaries = rankedDictionaries
this.rankedDictionariesMaxWordSize = rankedDictionariesMaxWorkSize
}
getRankedDictionariesMaxWordSize(name: string) {
const data = this.dictionary[name].map((el) => {
if (typeof el !== 'string') {
return el.toString().length
}
return el.length
})
const result = data.length === 0 ? 0 : Math.max(...data)
return result
}
getRankedDictionary(name: string) {

@@ -138,2 +163,4 @@ const list = this.dictionary[name]

this.rankedDictionaries.userInputs = this.getRankedDictionary('userInputs')
this.rankedDictionariesMaxWordSize.userInputs =
this.getRankedDictionariesMaxWordSize('userInputs')
}

@@ -140,0 +167,0 @@

import utils from './utils'
import estimateGuesses from './estimate'
import { MIN_GUESSES_BEFORE_GROWING_SEQUENCE } from '../data/const'
import { MatchExtended, BruteForceMatch, MatchEstimated } from '../types'
import {
MatchExtended,
BruteForceMatch,
MatchEstimated,
LooseObject,
} from '../types'

@@ -11,5 +16,6 @@ const scoringHelper = {

fillArray(size: number, valueType: 'object' | 'array') {
const result: typeof valueType extends 'array' ? string[] : {}[] = []
const result: typeof valueType extends 'array' ? string[] : LooseObject[] =
[]
for (let i = 0; i < size; i += 1) {
let value: [] | {} = []
let value: [] | LooseObject = []
if (valueType === 'object') {

@@ -16,0 +22,0 @@ value = {}

import zxcvbnOptions from './Options'
import { CrackTimesDisplay, CrackTimesSeconds } from './types'
import { CrackTimesDisplay, CrackTimesSeconds, Score } from './types'

@@ -65,3 +65,3 @@ const SECOND = 1

guessesToScore(guesses: number) {
guessesToScore(guesses: number): Score {
const DELTA = 5

@@ -68,0 +68,0 @@ if (guesses < 1e3 + DELTA) {

@@ -163,2 +163,3 @@ import translationKeys from './data/translationKeys'

levenshteinThreshold?: number
l33tMaxSubstitutions?: number
}

@@ -176,3 +177,3 @@

match: MatchEstimated,
isSoleMatch?: Boolean,
isSoleMatch?: boolean,
) => FeedbackType | null

@@ -206,2 +207,4 @@

export type Score = 0 | 1 | 2 | 3 | 4
export interface ZxcvbnResult {

@@ -211,3 +214,3 @@ feedback: FeedbackType

crackTimesDisplay: CrackTimesDisplay
score: number
score: Score
password: string

@@ -214,0 +217,0 @@ guesses: number

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc