/* 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, ifDefined } from "chrome://global/content/vendor/lit.all.mjs"; import { MozLitElement } from "chrome://global/content/lit-utils.mjs"; /** * Valid attributes for the enable-backup-encryption dialog type. * * @see EnableBackupEncryption.type */ const VALID_TYPES = Object.freeze({ SET_PASSWORD: "set-password", CHANGE_PASSWORD: "change-password", }); const VALID_L10N_IDS = new Map([ [VALID_TYPES.SET_PASSWORD, "enable-backup-encryption-header"], [VALID_TYPES.CHANGE_PASSWORD, "change-backup-encryption-header"], ]); /** * The widget for enabling password protection if the backup is not yet * encrypted. */ export default class EnableBackupEncryption extends MozLitElement { static properties = { passwordsMatch: { type: Boolean, reflect: true }, passwordsRequired: { type: Boolean, reflect: true }, /** * The "type" attribute changes the layout. * * @see VALID_TYPES */ type: { type: String, reflect: true }, }; static get queries() { return { cancelButtonEl: "#backup-enable-encryption-cancel-button", confirmButtonEl: "#backup-enable-encryption-confirm-button", inputNewPasswordEl: "#new-password-input", inputRepeatPasswordEl: "#repeat-password-input", textDescriptionEl: "#backup-enable-encryption-description", }; } constructor() { super(); this.passwordsMatch = false; this.passwordsRequired = true; this.type = VALID_TYPES.SET_PASSWORD; } /** * Dispatches the BackupUI:InitWidget custom event upon being attached to the * DOM, which registers with BackupUIChild for BackupService state updates. */ connectedCallback() { super.connectedCallback(); this.dispatchEvent( new CustomEvent("BackupUI:InitWidget", { bubbles: true }) ); } handleCancel() { this.dispatchEvent( new CustomEvent("dialogCancel", { bubbles: true, composed: true, }) ); this.resetChanges(); } handleConfirm() { switch (this.type) { case VALID_TYPES.SET_PASSWORD: this.dispatchEvent( new CustomEvent("enableEncryption", { bubbles: true, composed: true, detail: { password: this.inputNewPasswordEl.value, }, }) ); break; case VALID_TYPES.CHANGE_PASSWORD: this.dispatchEvent( new CustomEvent("rerunEncryption", { bubbles: true, composed: true, detail: { password: this.inputNewPasswordEl.value, }, }) ); break; } this.resetChanges(); } handleChangeNewPassword() { this.updatePasswordValidity(); } handleChangeRepeatPassword() { this.updatePasswordValidity(); } updatePasswordValidity() { // If the "required" attribute was previously removed, add it back // to make password validation work as expected. if (!this.passwordsRequired) { this.passwordsRequired = true; } let isNewPasswordInputValid = this.inputNewPasswordEl?.checkValidity(); let isRepeatPasswordInputValid = this.inputRepeatPasswordEl?.checkValidity(); /** * TODO: Before confirmation, verify FxA format rules (bug 1896772). * This step may involve async validation with BackupService. For instance, we have to * check against a list of common passwords (bug 1905140) and display a message if an * issue occurs (bug 1905145). */ this.passwordsMatch = isNewPasswordInputValid && isRepeatPasswordInputValid && this.inputNewPasswordEl.value == this.inputRepeatPasswordEl.value; } resetChanges() { this.passwordsMatch = false; this.inputNewPasswordEl.value = ""; this.inputRepeatPasswordEl.value = ""; // Temporarily remove "required" attribute to remove styles for invalid inputs. // The attribute will be added again when we run validation. this.passwordsRequired = false; } contentTemplate() { return html`

${this.type === VALID_TYPES.SET_PASSWORD ? html`
` : null}
`; } render() { return html` ${this.contentTemplate()} `; } } customElements.define("enable-backup-encryption", EnableBackupEncryption);