214 lines
6.6 KiB
JavaScript
214 lines
6.6 KiB
JavaScript
/* 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<string, any>} 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`
|
|
<div id="password-inputs-wrapper" aria-live="polite">
|
|
<form id="password-inputs-form">
|
|
<!--TODO: (bug 1909983) change first input field label for the "change-password" dialog-->
|
|
<label id="new-password-label" for="new-password-input">
|
|
<div id="new-password-label-wrapper-span-input">
|
|
<span
|
|
id="new-password-span"
|
|
data-l10n-id="enable-backup-encryption-create-password-label"
|
|
></span>
|
|
<input
|
|
type="password"
|
|
id="new-password-input"
|
|
minlength="8"
|
|
required
|
|
@input=${this.handleChangeNewPassword}
|
|
@focus=${this.handleFocusNewPassword}
|
|
@blur=${this.handleBlurNewPassword}
|
|
/>
|
|
<!--TODO: (bug 1909984) improve how we read out the first input field for screen readers-->
|
|
</div>
|
|
</label>
|
|
<!--TODO: (bug 1909984) look into how the tooltip vs dialog behaves when pressing the ESC key-->
|
|
<password-rules-tooltip
|
|
id="password-rules"
|
|
class=${!this._showRules && !this._tooltipFocus ? "hidden" : ""}
|
|
.hasCommon=${this._hasCommon}
|
|
.hasEmail=${this._hasEmail}
|
|
.tooShort=${this._tooShort}
|
|
.supportBaseLink=${this.supportBaseLink}
|
|
@focus=${this.handleTooltipFocus}
|
|
@blur=${this.handleTooltipBlur}
|
|
></password-rules-tooltip>
|
|
<label id="repeat-password-label" for="repeat-password-input">
|
|
<span
|
|
id="repeat-password-span"
|
|
data-l10n-id="enable-backup-encryption-repeat-password-label"
|
|
></span>
|
|
<input
|
|
type="password"
|
|
id="repeat-password-input"
|
|
minlength="8"
|
|
required
|
|
@input=${this.handleChangeRepeatPassword}
|
|
/>
|
|
</label>
|
|
</form>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
render() {
|
|
return html`
|
|
<link
|
|
rel="stylesheet"
|
|
href="chrome://browser/content/backup/password-validation-inputs.css"
|
|
/>
|
|
${this.contentTemplate()}
|
|
`;
|
|
}
|
|
}
|
|
|
|
customElements.define("password-validation-inputs", PasswordValidationInputs);
|