summaryrefslogtreecommitdiffstats
path: root/toolkit/components/passwordmgr/PasswordRulesManager.sys.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/passwordmgr/PasswordRulesManager.sys.mjs')
-rw-r--r--toolkit/components/passwordmgr/PasswordRulesManager.sys.mjs130
1 files changed, 130 insertions, 0 deletions
diff --git a/toolkit/components/passwordmgr/PasswordRulesManager.sys.mjs b/toolkit/components/passwordmgr/PasswordRulesManager.sys.mjs
new file mode 100644
index 0000000000..e80fb51962
--- /dev/null
+++ b/toolkit/components/passwordmgr/PasswordRulesManager.sys.mjs
@@ -0,0 +1,130 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
+
+const lazy = {};
+
+ChromeUtils.defineESModuleGetters(lazy, {
+ LoginHelper: "resource://gre/modules/LoginHelper.sys.mjs",
+ PasswordGenerator: "resource://gre/modules/PasswordGenerator.sys.mjs",
+ PasswordRulesParser: "resource://gre/modules/PasswordRulesParser.sys.mjs",
+ RemoteSettings: "resource://services-settings/remote-settings.sys.mjs",
+});
+
+XPCOMUtils.defineLazyGetter(lazy, "log", () => {
+ let logger = lazy.LoginHelper.createLogger("PasswordRulesManager");
+ return logger.log.bind(logger);
+});
+
+const IMPROVED_PASSWORD_GENERATION_HISTOGRAM =
+ "PWMGR_NUM_IMPROVED_GENERATED_PASSWORDS";
+
+/**
+ * Handles interactions between PasswordRulesParser and the "password-rules" Remote Settings collection
+ *
+ * @class PasswordRulesManagerParent
+ * @extends {JSWindowActorParent}
+ */
+export class PasswordRulesManagerParent extends JSWindowActorParent {
+ /**
+ * @type RemoteSettingsClient
+ *
+ * @memberof PasswordRulesManagerParent
+ */
+ _passwordRulesClient = null;
+
+ async initPasswordRulesCollection() {
+ if (!this._passwordRulesClient) {
+ this._passwordRulesClient = lazy.RemoteSettings(
+ lazy.LoginHelper.improvedPasswordRulesCollection
+ );
+ }
+ }
+ /**
+ * Transforms the parsed rules returned from PasswordRulesParser into a Map for easier access.
+ * The returned Map could have the following keys: "allowed", "required", "maxlength", "minlength", and "max-consecutive"
+ * @example
+ * // Returns a Map with a key-value pair of "allowed": "ascii-printable"
+ * _transformRulesToMap([{ _name: "allowed", value: [{ _name: "ascii-printable" }] }])
+ * @param {Object[]} rules rules from PasswordRulesParser.parsePasswordRules
+ * @return {Map} mapped rules
+ * @memberof PasswordRulesManagerParent
+ */
+ _transformRulesToMap(rules) {
+ let map = new Map();
+ for (let rule of rules) {
+ let { _name, value } = rule;
+ if (
+ _name === "minlength" ||
+ _name === "maxlength" ||
+ _name === "max-consecutive"
+ ) {
+ map.set(_name, value);
+ } else {
+ let _value = [];
+ if (map.get(_name)) {
+ _value = map.get(_name);
+ }
+ for (let _class of value) {
+ let { _name: _className } = _class;
+ if (_className) {
+ _value.push(_className);
+ } else {
+ let { _characters } = _class;
+ _value.push(_characters);
+ }
+ }
+ map.set(_name, _value);
+ }
+ }
+ return map;
+ }
+
+ /**
+ * Generates a password based on rules from the origin parameters.
+ * @param {nsIURI} uri
+ * @return {string} password
+ * @memberof PasswordRulesManagerParent
+ */
+ async generatePassword(uri, { inputMaxLength } = {}) {
+ await this.initPasswordRulesCollection();
+ let originDisplayHost = uri.displayHost;
+ let records = await this._passwordRulesClient.get();
+ let currentRecord;
+ for (let record of records) {
+ if (Services.eTLD.hasRootDomain(originDisplayHost, record.Domain)) {
+ currentRecord = record;
+ break;
+ }
+ }
+ let isCustomRule = false;
+ // If we found a matching result, use that to generate a stronger password.
+ // Otherwise, generate a password using the default rules set.
+ if (currentRecord?.Domain) {
+ isCustomRule = true;
+ lazy.log(
+ `Password rules for ${currentRecord.Domain}: ${currentRecord["password-rules"]}.`
+ );
+ let currentRules = lazy.PasswordRulesParser.parsePasswordRules(
+ currentRecord["password-rules"]
+ );
+ let mapOfRules = this._transformRulesToMap(currentRules);
+ Services.telemetry
+ .getHistogramById(IMPROVED_PASSWORD_GENERATION_HISTOGRAM)
+ .add(isCustomRule);
+ return lazy.PasswordGenerator.generatePassword({
+ rules: mapOfRules,
+ inputMaxLength,
+ });
+ }
+ lazy.log(
+ `No password rules for specified origin, generating standard password.`
+ );
+ Services.telemetry
+ .getHistogramById(IMPROVED_PASSWORD_GENERATION_HISTOGRAM)
+ .add(isCustomRule);
+ return lazy.PasswordGenerator.generatePassword({ inputMaxLength });
+ }
+}