mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 19:35:51 +00:00
Bug 1686071 - Add PasswordRulesParser module. r=dimi
Differential Revision: https://phabricator.services.mozilla.com/D114110
This commit is contained in:
parent
72e5df1cbf
commit
0180e3b96d
699
toolkit/components/passwordmgr/PasswordRulesParser.jsm
Normal file
699
toolkit/components/passwordmgr/PasswordRulesParser.jsm
Normal file
@ -0,0 +1,699 @@
|
||||
// Sourced from https://github.com/apple/password-manager-resources/blob/5f6da89483e75cdc4165a6fc4756796e0ced7a21/tools/PasswordRulesParser.js
|
||||
// Copyright (c) 2019 - 2020 Apple Inc. Licensed under MIT License.
|
||||
|
||||
"use strict";
|
||||
|
||||
const EXPORTED_SYMBOLS = ["PasswordRulesParser"];
|
||||
|
||||
this.PasswordRulesParser = {
|
||||
parsePasswordRules,
|
||||
};
|
||||
|
||||
const Identifier = {
|
||||
ASCII_PRINTABLE: "ascii-printable",
|
||||
DIGIT: "digit",
|
||||
LOWER: "lower",
|
||||
SPECIAL: "special",
|
||||
UNICODE: "unicode",
|
||||
UPPER: "upper",
|
||||
};
|
||||
|
||||
const RuleName = {
|
||||
ALLOWED: "allowed",
|
||||
MAX_CONSECUTIVE: "max-consecutive",
|
||||
REQUIRED: "required",
|
||||
MIN_LENGTH: "minlength",
|
||||
MAX_LENGTH: "maxlength",
|
||||
};
|
||||
|
||||
const CHARACTER_CLASS_START_SENTINEL = "[";
|
||||
const CHARACTER_CLASS_END_SENTINEL = "]";
|
||||
const PROPERTY_VALUE_SEPARATOR = ",";
|
||||
const PROPERTY_SEPARATOR = ";";
|
||||
const PROPERTY_VALUE_START_SENTINEL = ":";
|
||||
|
||||
const SPACE_CODE_POINT = " ".codePointAt(0);
|
||||
|
||||
const SHOULD_NOT_BE_REACHED = "Should not be reached";
|
||||
|
||||
class Rule {
|
||||
constructor(name, value) {
|
||||
this._name = name;
|
||||
this.value = value;
|
||||
}
|
||||
get name() {
|
||||
return this._name;
|
||||
}
|
||||
toString() {
|
||||
return JSON.stringify(this);
|
||||
}
|
||||
}
|
||||
|
||||
class NamedCharacterClass {
|
||||
constructor(name) {
|
||||
console.assert(_isValidRequiredOrAllowedPropertyValueIdentifier(name));
|
||||
this._name = name;
|
||||
}
|
||||
get name() {
|
||||
return this._name.toLowerCase();
|
||||
}
|
||||
toString() {
|
||||
return this._name;
|
||||
}
|
||||
toHTMLString() {
|
||||
return this._name;
|
||||
}
|
||||
}
|
||||
|
||||
class CustomCharacterClass {
|
||||
constructor(characters) {
|
||||
console.assert(characters instanceof Array);
|
||||
this._characters = characters;
|
||||
}
|
||||
get characters() {
|
||||
return this._characters;
|
||||
}
|
||||
toString() {
|
||||
return `[${this._characters.join("")}]`;
|
||||
}
|
||||
toHTMLString() {
|
||||
return `[${this._characters.join("").replace('"', """)}]`;
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Lexer functions
|
||||
|
||||
function _isIdentifierCharacter(c) {
|
||||
console.assert(c.length === 1);
|
||||
return (c >= "a" && c <= "z") || (c >= "A" && c <= "Z") || c === "-";
|
||||
}
|
||||
|
||||
function _isASCIIDigit(c) {
|
||||
console.assert(c.length === 1);
|
||||
return c >= "0" && c <= "9";
|
||||
}
|
||||
|
||||
function _isASCIIPrintableCharacter(c) {
|
||||
console.assert(c.length === 1);
|
||||
return c >= " " && c <= "~";
|
||||
}
|
||||
|
||||
function _isASCIIWhitespace(c) {
|
||||
console.assert(c.length === 1);
|
||||
return c === " " || c === "\f" || c === "\n" || c === "\r" || c === "\t";
|
||||
}
|
||||
|
||||
// MARK: ASCII printable character bit set and canonicalization functions
|
||||
|
||||
function _bitSetIndexForCharacter(c) {
|
||||
console.assert(c.length == 1);
|
||||
return c.codePointAt(0) - SPACE_CODE_POINT;
|
||||
}
|
||||
|
||||
function _characterAtBitSetIndex(index) {
|
||||
return String.fromCodePoint(index + SPACE_CODE_POINT);
|
||||
}
|
||||
|
||||
function _markBitsForNamedCharacterClass(bitSet, namedCharacterClass) {
|
||||
console.assert(bitSet instanceof Array);
|
||||
console.assert(namedCharacterClass.name !== Identifier.UNICODE);
|
||||
console.assert(namedCharacterClass.name !== Identifier.ASCII_PRINTABLE);
|
||||
if (namedCharacterClass.name === Identifier.UPPER) {
|
||||
bitSet.fill(
|
||||
true,
|
||||
_bitSetIndexForCharacter("A"),
|
||||
_bitSetIndexForCharacter("Z") + 1
|
||||
);
|
||||
} else if (namedCharacterClass.name === Identifier.LOWER) {
|
||||
bitSet.fill(
|
||||
true,
|
||||
_bitSetIndexForCharacter("a"),
|
||||
_bitSetIndexForCharacter("z") + 1
|
||||
);
|
||||
} else if (namedCharacterClass.name === Identifier.DIGIT) {
|
||||
bitSet.fill(
|
||||
true,
|
||||
_bitSetIndexForCharacter("0"),
|
||||
_bitSetIndexForCharacter("9") + 1
|
||||
);
|
||||
} else if (namedCharacterClass.name === Identifier.SPECIAL) {
|
||||
bitSet.fill(
|
||||
true,
|
||||
_bitSetIndexForCharacter(" "),
|
||||
_bitSetIndexForCharacter("/") + 1
|
||||
);
|
||||
bitSet.fill(
|
||||
true,
|
||||
_bitSetIndexForCharacter(":"),
|
||||
_bitSetIndexForCharacter("@") + 1
|
||||
);
|
||||
bitSet.fill(
|
||||
true,
|
||||
_bitSetIndexForCharacter("["),
|
||||
_bitSetIndexForCharacter("`") + 1
|
||||
);
|
||||
bitSet.fill(
|
||||
true,
|
||||
_bitSetIndexForCharacter("{"),
|
||||
_bitSetIndexForCharacter("~") + 1
|
||||
);
|
||||
} else {
|
||||
console.assert(false, SHOULD_NOT_BE_REACHED, namedCharacterClass);
|
||||
}
|
||||
}
|
||||
|
||||
function _markBitsForCustomCharacterClass(bitSet, customCharacterClass) {
|
||||
for (let character of customCharacterClass.characters) {
|
||||
bitSet[_bitSetIndexForCharacter(character)] = true;
|
||||
}
|
||||
}
|
||||
|
||||
function _canonicalizedPropertyValues(
|
||||
propertyValues,
|
||||
keepCustomCharacterClassFormatCompliant
|
||||
) {
|
||||
let asciiPrintableBitSet = new Array(
|
||||
"~".codePointAt(0) - " ".codePointAt(0) + 1
|
||||
);
|
||||
|
||||
for (let propertyValue of propertyValues) {
|
||||
if (propertyValue instanceof NamedCharacterClass) {
|
||||
if (propertyValue.name === Identifier.UNICODE) {
|
||||
return [new NamedCharacterClass(Identifier.UNICODE)];
|
||||
}
|
||||
|
||||
if (propertyValue.name === Identifier.ASCII_PRINTABLE) {
|
||||
return [new NamedCharacterClass(Identifier.ASCII_PRINTABLE)];
|
||||
}
|
||||
|
||||
_markBitsForNamedCharacterClass(asciiPrintableBitSet, propertyValue);
|
||||
} else if (propertyValue instanceof CustomCharacterClass) {
|
||||
_markBitsForCustomCharacterClass(asciiPrintableBitSet, propertyValue);
|
||||
}
|
||||
}
|
||||
|
||||
let charactersSeen = [];
|
||||
|
||||
function checkRange(start, end) {
|
||||
let temp = [];
|
||||
for (
|
||||
let i = _bitSetIndexForCharacter(start);
|
||||
i <= _bitSetIndexForCharacter(end);
|
||||
++i
|
||||
) {
|
||||
if (asciiPrintableBitSet[i]) {
|
||||
temp.push(_characterAtBitSetIndex(i));
|
||||
}
|
||||
}
|
||||
|
||||
let result =
|
||||
temp.length ===
|
||||
_bitSetIndexForCharacter(end) - _bitSetIndexForCharacter(start) + 1;
|
||||
if (!result) {
|
||||
charactersSeen = charactersSeen.concat(temp);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
let hasAllUpper = checkRange("A", "Z");
|
||||
let hasAllLower = checkRange("a", "z");
|
||||
let hasAllDigits = checkRange("0", "9");
|
||||
|
||||
// Check for special characters, accounting for characters that are given special treatment (i.e. '-' and ']')
|
||||
let hasAllSpecial = false;
|
||||
let hasDash = false;
|
||||
let hasRightSquareBracket = false;
|
||||
let temp = [];
|
||||
for (
|
||||
let i = _bitSetIndexForCharacter(" ");
|
||||
i <= _bitSetIndexForCharacter("/");
|
||||
++i
|
||||
) {
|
||||
if (!asciiPrintableBitSet[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let character = _characterAtBitSetIndex(i);
|
||||
if (keepCustomCharacterClassFormatCompliant && character === "-") {
|
||||
hasDash = true;
|
||||
} else {
|
||||
temp.push(character);
|
||||
}
|
||||
}
|
||||
for (
|
||||
let i = _bitSetIndexForCharacter(":");
|
||||
i <= _bitSetIndexForCharacter("@");
|
||||
++i
|
||||
) {
|
||||
if (asciiPrintableBitSet[i]) {
|
||||
temp.push(_characterAtBitSetIndex(i));
|
||||
}
|
||||
}
|
||||
for (
|
||||
let i = _bitSetIndexForCharacter("[");
|
||||
i <= _bitSetIndexForCharacter("`");
|
||||
++i
|
||||
) {
|
||||
if (!asciiPrintableBitSet[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let character = _characterAtBitSetIndex(i);
|
||||
if (keepCustomCharacterClassFormatCompliant && character === "]") {
|
||||
hasRightSquareBracket = true;
|
||||
} else {
|
||||
temp.push(character);
|
||||
}
|
||||
}
|
||||
for (
|
||||
let i = _bitSetIndexForCharacter("{");
|
||||
i <= _bitSetIndexForCharacter("~");
|
||||
++i
|
||||
) {
|
||||
if (asciiPrintableBitSet[i]) {
|
||||
temp.push(_characterAtBitSetIndex(i));
|
||||
}
|
||||
}
|
||||
|
||||
if (hasDash) {
|
||||
temp.unshift("-");
|
||||
}
|
||||
if (hasRightSquareBracket) {
|
||||
temp.push("]");
|
||||
}
|
||||
|
||||
let numberOfSpecialCharacters =
|
||||
_bitSetIndexForCharacter("/") -
|
||||
_bitSetIndexForCharacter(" ") +
|
||||
1 +
|
||||
(_bitSetIndexForCharacter("@") - _bitSetIndexForCharacter(":") + 1) +
|
||||
(_bitSetIndexForCharacter("`") - _bitSetIndexForCharacter("[") + 1) +
|
||||
(_bitSetIndexForCharacter("~") - _bitSetIndexForCharacter("{") + 1);
|
||||
hasAllSpecial = temp.length === numberOfSpecialCharacters;
|
||||
if (!hasAllSpecial) {
|
||||
charactersSeen = charactersSeen.concat(temp);
|
||||
}
|
||||
|
||||
let result = [];
|
||||
if (hasAllUpper && hasAllLower && hasAllDigits && hasAllSpecial) {
|
||||
return [new NamedCharacterClass(Identifier.ASCII_PRINTABLE)];
|
||||
}
|
||||
if (hasAllUpper) {
|
||||
result.push(new NamedCharacterClass(Identifier.UPPER));
|
||||
}
|
||||
if (hasAllLower) {
|
||||
result.push(new NamedCharacterClass(Identifier.LOWER));
|
||||
}
|
||||
if (hasAllDigits) {
|
||||
result.push(new NamedCharacterClass(Identifier.DIGIT));
|
||||
}
|
||||
if (hasAllSpecial) {
|
||||
result.push(new NamedCharacterClass(Identifier.SPECIAL));
|
||||
}
|
||||
if (charactersSeen.length) {
|
||||
result.push(new CustomCharacterClass(charactersSeen));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// MARK: Parser functions
|
||||
|
||||
function _indexOfNonWhitespaceCharacter(input, position = 0) {
|
||||
console.assert(position >= 0);
|
||||
console.assert(position <= input.length);
|
||||
|
||||
let length = input.length;
|
||||
while (position < length && _isASCIIWhitespace(input[position])) {
|
||||
++position;
|
||||
}
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
function _parseIdentifier(input, position) {
|
||||
console.assert(position >= 0);
|
||||
console.assert(position < input.length);
|
||||
console.assert(_isIdentifierCharacter(input[position]));
|
||||
|
||||
let length = input.length;
|
||||
let seenIdentifiers = [];
|
||||
do {
|
||||
let c = input[position];
|
||||
if (!_isIdentifierCharacter(c)) {
|
||||
break;
|
||||
}
|
||||
|
||||
seenIdentifiers.push(c);
|
||||
++position;
|
||||
} while (position < length);
|
||||
|
||||
return [seenIdentifiers.join(""), position];
|
||||
}
|
||||
|
||||
function _isValidRequiredOrAllowedPropertyValueIdentifier(identifier) {
|
||||
return (
|
||||
identifier && Object.values(Identifier).includes(identifier.toLowerCase())
|
||||
);
|
||||
}
|
||||
|
||||
function _parseCustomCharacterClass(input, position) {
|
||||
console.assert(position >= 0);
|
||||
console.assert(position < input.length);
|
||||
console.assert(input[position] === CHARACTER_CLASS_START_SENTINEL);
|
||||
|
||||
let length = input.length;
|
||||
++position;
|
||||
if (position >= length) {
|
||||
console.error("Found end-of-line instead of character class character");
|
||||
return [null, position];
|
||||
}
|
||||
|
||||
let initialPosition = position;
|
||||
let result = [];
|
||||
do {
|
||||
let c = input[position];
|
||||
if (!_isASCIIPrintableCharacter(c)) {
|
||||
++position;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c === "-" && position - initialPosition > 0) {
|
||||
// FIXME: Should this be an error?
|
||||
console.warn(
|
||||
"Ignoring '-'; a '-' may only appear as the first character in a character class"
|
||||
);
|
||||
++position;
|
||||
continue;
|
||||
}
|
||||
|
||||
result.push(c);
|
||||
++position;
|
||||
if (c === CHARACTER_CLASS_END_SENTINEL) {
|
||||
break;
|
||||
}
|
||||
} while (position < length);
|
||||
|
||||
if (
|
||||
(position < length && input[position] !== CHARACTER_CLASS_END_SENTINEL) ||
|
||||
(position == length && input[position - 1] == CHARACTER_CLASS_END_SENTINEL)
|
||||
) {
|
||||
// Fix up result; we over consumed.
|
||||
result.pop();
|
||||
return [result, position];
|
||||
}
|
||||
|
||||
if (position < length && input[position] == CHARACTER_CLASS_END_SENTINEL) {
|
||||
return [result, position + 1];
|
||||
}
|
||||
|
||||
console.error("Found end-of-line instead of end of character class");
|
||||
return [null, position];
|
||||
}
|
||||
|
||||
function _parsePasswordRequiredOrAllowedPropertyValue(input, position) {
|
||||
console.assert(position >= 0);
|
||||
console.assert(position < input.length);
|
||||
|
||||
let length = input.length;
|
||||
let propertyValues = [];
|
||||
while (true) {
|
||||
if (_isIdentifierCharacter(input[position])) {
|
||||
let identifierStartPosition = position;
|
||||
var [propertyValue, position] = _parseIdentifier(input, position);
|
||||
if (!_isValidRequiredOrAllowedPropertyValueIdentifier(propertyValue)) {
|
||||
console.error(
|
||||
"Unrecognized property value identifier: " + propertyValue
|
||||
);
|
||||
return [null, identifierStartPosition];
|
||||
}
|
||||
propertyValues.push(new NamedCharacterClass(propertyValue));
|
||||
} else if (input[position] == CHARACTER_CLASS_START_SENTINEL) {
|
||||
var [propertyValue, position] = _parseCustomCharacterClass(
|
||||
input,
|
||||
position
|
||||
);
|
||||
if (propertyValue && propertyValue.length) {
|
||||
propertyValues.push(new CustomCharacterClass(propertyValue));
|
||||
}
|
||||
} else {
|
||||
console.error(
|
||||
"Failed to find start of property value: " + input.substr(position)
|
||||
);
|
||||
return [null, position];
|
||||
}
|
||||
|
||||
position = _indexOfNonWhitespaceCharacter(input, position);
|
||||
if (position >= length || input[position] === PROPERTY_SEPARATOR) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (input[position] === PROPERTY_VALUE_SEPARATOR) {
|
||||
position = _indexOfNonWhitespaceCharacter(input, position + 1);
|
||||
if (position >= length) {
|
||||
console.error(
|
||||
"Found end-of-line instead of start of next property value"
|
||||
);
|
||||
return [null, position];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
console.error(
|
||||
"Failed to find start of next property or property value: " +
|
||||
input.substr(position)
|
||||
);
|
||||
return [null, position];
|
||||
}
|
||||
return [propertyValues, position];
|
||||
}
|
||||
|
||||
function _parsePasswordRule(input, position) {
|
||||
console.assert(position >= 0);
|
||||
console.assert(position < input.length);
|
||||
console.assert(_isIdentifierCharacter(input[position]));
|
||||
|
||||
let length = input.length;
|
||||
|
||||
let mayBeIdentifierStartPosition = position;
|
||||
var [identifier, position] = _parseIdentifier(input, position);
|
||||
if (!Object.values(RuleName).includes(identifier)) {
|
||||
console.error("Unrecognized property name: " + identifier);
|
||||
return [null, mayBeIdentifierStartPosition];
|
||||
}
|
||||
|
||||
if (position >= length) {
|
||||
console.error("Found end-of-line instead of start of property value");
|
||||
return [null, position];
|
||||
}
|
||||
|
||||
if (input[position] !== PROPERTY_VALUE_START_SENTINEL) {
|
||||
console.error(
|
||||
"Failed to find start of property value: " + input.substr(position)
|
||||
);
|
||||
return [null, position];
|
||||
}
|
||||
|
||||
let property = { name: identifier, value: null };
|
||||
|
||||
position = _indexOfNonWhitespaceCharacter(input, position + 1);
|
||||
// Empty value
|
||||
if (position >= length || input[position] === PROPERTY_SEPARATOR) {
|
||||
return [new Rule(property.name, property.value), position];
|
||||
}
|
||||
|
||||
switch (identifier) {
|
||||
case RuleName.ALLOWED:
|
||||
case RuleName.REQUIRED: {
|
||||
var [
|
||||
propertyValue,
|
||||
position,
|
||||
] = _parsePasswordRequiredOrAllowedPropertyValue(input, position);
|
||||
if (propertyValue) {
|
||||
property.value = propertyValue;
|
||||
}
|
||||
return [new Rule(property.name, property.value), position];
|
||||
}
|
||||
case RuleName.MAX_CONSECUTIVE: {
|
||||
var [propertyValue, position] = _parseMaxConsecutivePropertyValue(
|
||||
input,
|
||||
position
|
||||
);
|
||||
if (propertyValue) {
|
||||
property.value = propertyValue;
|
||||
}
|
||||
return [new Rule(property.name, property.value), position];
|
||||
}
|
||||
case RuleName.MIN_LENGTH:
|
||||
case RuleName.MAX_LENGTH: {
|
||||
var [propertyValue, position] = _parseMinLengthMaxLengthPropertyValue(
|
||||
input,
|
||||
position
|
||||
);
|
||||
if (propertyValue) {
|
||||
property.value = propertyValue;
|
||||
}
|
||||
return [new Rule(property.name, property.value), position];
|
||||
}
|
||||
}
|
||||
console.assert(false, SHOULD_NOT_BE_REACHED);
|
||||
}
|
||||
|
||||
function _parseMinLengthMaxLengthPropertyValue(input, position) {
|
||||
return _parseInteger(input, position);
|
||||
}
|
||||
|
||||
function _parseMaxConsecutivePropertyValue(input, position) {
|
||||
return _parseInteger(input, position);
|
||||
}
|
||||
|
||||
function _parseInteger(input, position) {
|
||||
console.assert(position >= 0);
|
||||
console.assert(position < input.length);
|
||||
|
||||
if (!_isASCIIDigit(input[position])) {
|
||||
console.error(
|
||||
"Failed to parse value of type integer; not a number: " +
|
||||
input.substr(position)
|
||||
);
|
||||
return [null, position];
|
||||
}
|
||||
|
||||
let length = input.length;
|
||||
let initialPosition = position;
|
||||
let result = 0;
|
||||
do {
|
||||
result = 10 * result + parseInt(input[position], 10);
|
||||
++position;
|
||||
} while (
|
||||
position < length &&
|
||||
input[position] !== PROPERTY_SEPARATOR &&
|
||||
_isASCIIDigit(input[position])
|
||||
);
|
||||
|
||||
if (position >= length || input[position] === PROPERTY_SEPARATOR) {
|
||||
return [result, position];
|
||||
}
|
||||
|
||||
console.error(
|
||||
"Failed to parse value of type integer; not a number: " +
|
||||
input.substr(initialPosition)
|
||||
);
|
||||
return [null, position];
|
||||
}
|
||||
|
||||
function _parsePasswordRulesInternal(input) {
|
||||
let parsedProperties = [];
|
||||
let length = input.length;
|
||||
|
||||
var position = _indexOfNonWhitespaceCharacter(input);
|
||||
while (position < length) {
|
||||
if (!_isIdentifierCharacter(input[position])) {
|
||||
console.warn(
|
||||
"Failed to find start of property: " + input.substr(position)
|
||||
);
|
||||
return parsedProperties;
|
||||
}
|
||||
|
||||
var [parsedProperty, position] = _parsePasswordRule(input, position);
|
||||
if (parsedProperty && parsedProperty.value) {
|
||||
parsedProperties.push(parsedProperty);
|
||||
}
|
||||
|
||||
position = _indexOfNonWhitespaceCharacter(input, position);
|
||||
if (position >= length) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (input[position] === PROPERTY_SEPARATOR) {
|
||||
position = _indexOfNonWhitespaceCharacter(input, position + 1);
|
||||
if (position >= length) {
|
||||
return parsedProperties;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
console.error(
|
||||
"Failed to find start of next property: " + input.substr(position)
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
return parsedProperties;
|
||||
}
|
||||
|
||||
function parsePasswordRules(input, formatRulesForMinifiedVersion) {
|
||||
let passwordRules = _parsePasswordRulesInternal(input) || [];
|
||||
|
||||
// When formatting rules for minified version, we should keep the formatted rules
|
||||
// as similar to the input as possible. Avoid copying required rules to allowed rules.
|
||||
let suppressCopyingRequiredToAllowed = formatRulesForMinifiedVersion;
|
||||
|
||||
let newPasswordRules = [];
|
||||
let newAllowedValues = [];
|
||||
let minimumMaximumConsecutiveCharacters = null;
|
||||
let maximumMinLength = 0;
|
||||
let minimumMaxLength = null;
|
||||
|
||||
for (let rule of passwordRules) {
|
||||
switch (rule.name) {
|
||||
case RuleName.MAX_CONSECUTIVE:
|
||||
minimumMaximumConsecutiveCharacters = minimumMaximumConsecutiveCharacters
|
||||
? Math.min(rule.value, minimumMaximumConsecutiveCharacters)
|
||||
: rule.value;
|
||||
break;
|
||||
|
||||
case RuleName.MIN_LENGTH:
|
||||
maximumMinLength = Math.max(rule.value, maximumMinLength);
|
||||
break;
|
||||
|
||||
case RuleName.MAX_LENGTH:
|
||||
minimumMaxLength = minimumMaxLength
|
||||
? Math.min(rule.value, minimumMaxLength)
|
||||
: rule.value;
|
||||
break;
|
||||
|
||||
case RuleName.REQUIRED:
|
||||
rule.value = _canonicalizedPropertyValues(
|
||||
rule.value,
|
||||
formatRulesForMinifiedVersion
|
||||
);
|
||||
newPasswordRules.push(rule);
|
||||
if (!suppressCopyingRequiredToAllowed) {
|
||||
newAllowedValues = newAllowedValues.concat(rule.value);
|
||||
}
|
||||
break;
|
||||
|
||||
case RuleName.ALLOWED:
|
||||
newAllowedValues = newAllowedValues.concat(rule.value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
newAllowedValues = _canonicalizedPropertyValues(
|
||||
newAllowedValues,
|
||||
suppressCopyingRequiredToAllowed
|
||||
);
|
||||
if (!suppressCopyingRequiredToAllowed && !newAllowedValues.length) {
|
||||
newAllowedValues = [new NamedCharacterClass(Identifier.ASCII_PRINTABLE)];
|
||||
}
|
||||
if (newAllowedValues.length) {
|
||||
newPasswordRules.push(new Rule(RuleName.ALLOWED, newAllowedValues));
|
||||
}
|
||||
|
||||
if (minimumMaximumConsecutiveCharacters !== null) {
|
||||
newPasswordRules.push(
|
||||
new Rule(RuleName.MAX_CONSECUTIVE, minimumMaximumConsecutiveCharacters)
|
||||
);
|
||||
}
|
||||
|
||||
if (maximumMinLength > 0) {
|
||||
newPasswordRules.push(new Rule(RuleName.MIN_LENGTH, maximumMinLength));
|
||||
}
|
||||
|
||||
if (minimumMaxLength !== null) {
|
||||
newPasswordRules.push(new Rule(RuleName.MAX_LENGTH, minimumMaxLength));
|
||||
}
|
||||
|
||||
return newPasswordRules;
|
||||
}
|
@ -45,6 +45,7 @@ EXTRA_JS_MODULES += [
|
||||
"NewPasswordModel.jsm",
|
||||
"OSCrypto.jsm",
|
||||
"PasswordGenerator.jsm",
|
||||
"PasswordRulesParser.jsm",
|
||||
"storage-json.js",
|
||||
]
|
||||
|
||||
|
@ -69,6 +69,7 @@
|
||||
<li><a href="about:license#apache-llvm">Apache License 2.0 with LLVM exception</a></li>
|
||||
<li><a href="about:license#apple">Apple License</a></li>
|
||||
<li><a href="about:license#apple-mozilla">Apple/Mozilla NPRuntime License</a></li>
|
||||
<li><a href="about:license#apple-password-rules-parser">Apple Password Rules Parser License</a></li>
|
||||
<li><a href="about:license#arm">ARM License</a></li>
|
||||
<li><a href="about:license#babel">Babel License</a></li>
|
||||
<li><a href="about:license#babylon">Babylon License</a></li>
|
||||
@ -4900,6 +4901,34 @@ IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
</pre>
|
||||
|
||||
<hr>
|
||||
|
||||
<h1><a id="apple-password-rules-parser"></a>Apple Password Rules Parser License</h1>
|
||||
|
||||
<p>This license applies to the file
|
||||
<code>toolkit/component/passwordmgr/PasswordRulesParser.jsm</code>.</p>
|
||||
|
||||
<pre>
|
||||
Copyright 2020 Apple Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
</pre>
|
||||
|
||||
<hr>
|
||||
|
||||
|
@ -166,6 +166,7 @@ third_party/
|
||||
toolkit/components/certviewer/content/vendor/
|
||||
toolkit/components/jsoncpp/
|
||||
toolkit/components/normandy/vendor/
|
||||
toolkit/components/passwordmgr/PasswordRulesParser.jsm
|
||||
toolkit/components/protobuf/
|
||||
toolkit/components/url-classifier/chromium/
|
||||
toolkit/components/utils/mozjexl.js
|
||||
|
Loading…
Reference in New Issue
Block a user