/* 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 { html } from "chrome://global/content/vendor/lit.all.mjs"; import { MozLitElement } from "chrome://global/content/lit-utils.mjs"; // eslint-disable-next-line import/no-unassigned-import import "chrome://browser/content/backup/password-rules-tooltip.mjs"; /** * The widget for enabling password protection if the backup is not yet * encrypted. */ export default class PasswordValidationInputs extends MozLitElement { static properties = { _hasCommon: { type: Boolean, state: true }, _hasEmail: { type: Boolean, state: true }, _passwordsMatch: { type: Boolean, state: true }, _passwordsValid: { type: Boolean, state: true }, _showRules: { type: Boolean, state: true }, _tooShort: { type: Boolean, state: true }, /** * If, by chance, there is focus on a focusable element in the tooltip, * track the focus state so that we can keep the tooltip open. */ _tooltipFocus: { type: Boolean, state: true }, supportBaseLink: { type: String }, }; static get queries() { return { formEl: "#password-inputs-form", inputNewPasswordEl: "#new-password-input", inputRepeatPasswordEl: "#repeat-password-input", passwordRulesEl: "#password-rules", }; } constructor() { super(); this.supportBaseLink = ""; this._tooShort = true; this._hasCommon = false; this._hasEmail = false; this._passwordsMatch = false; this._passwordsValid = false; this._tooltipFocus = false; } reset() { this.formEl.reset(); this._showRules = false; this._hasCommon = false; this._hasEmail = false; this._tooShort = true; this._passwordsMatch = false; this._passwordsValid = false; this._tooltipFocus = false; } handleFocusNewPassword() { this._showRules = true; } handleBlurNewPassword(event) { this._showRules = !event.target.checkValidity(); } handleChangeNewPassword() { this.updatePasswordValidity(); } handleChangeRepeatPassword() { this.updatePasswordValidity(); } updatePasswordValidity() { const emailRegex = /^[\w!#$%&'*+/=?^`{|}~.-]+@[A-Z0-9-]+\.[A-Z0-9.-]+$/i; this._hasEmail = emailRegex.test(this.inputNewPasswordEl.value); if (this._hasEmail) { // TODO: we need a localized string for this error (bug 1909983) this.inputNewPasswordEl.setCustomValidity("TODO: no emails"); } else { this.inputNewPasswordEl.setCustomValidity(""); } const newPassValidity = this.inputNewPasswordEl.validity; this._tooShort = newPassValidity?.valueMissing || newPassValidity?.tooShort; this._passwordsMatch = this.inputNewPasswordEl.value == this.inputRepeatPasswordEl.value; if (!this._passwordsMatch) { // TODO: we need a localized string for this error (bug 1909983) this.inputRepeatPasswordEl.setCustomValidity("TODO: not matching"); } else { this.inputRepeatPasswordEl.setCustomValidity(""); } const repeatPassValidity = this.inputRepeatPasswordEl.validity; this._passwordsValid = newPassValidity?.valid && repeatPassValidity?.valid && this._passwordsMatch; /** * This step may involve async validation with BackupService. For instance, we have to * check against a list of common passwords (bug 1905140) and display an error message if an * issue occurs (bug 1905145). */ } handleTooltipFocus() { this._tooltipFocus = true; } handleTooltipBlur() { this._tooltipFocus = false; } /** * Dispatches a custom event whenever validity changes. * * @param {Map} changedProperties a Map of recently changed properties and their new values */ updated(changedProperties) { if (!changedProperties.has("_passwordsValid")) { return; } if (this._passwordsValid) { this.dispatchEvent( new CustomEvent("ValidPasswordsDetected", { bubbles: true, composed: true, detail: { password: this.inputNewPasswordEl.value, }, }) ); } else { this.dispatchEvent( new CustomEvent("InvalidPasswordsDetected", { bubbles: true, composed: true, }) ); } } contentTemplate() { return html`
`; } render() { return html` ${this.contentTemplate()} `; } } customElements.define("password-validation-inputs", PasswordValidationInputs);