fix: Check password strength on password auto-fill (#2148)

Fixes password strength not being checked when new passwords are
auto-filled, resulting in submit buttons remaining disabled.

---------

Co-authored-by: SuaYoo <SuaYoo@users.noreply.github.com>
Co-authored-by: emma <hi@emma.cafe>
This commit is contained in:
sua yoo 2024-11-19 13:47:24 -08:00 committed by GitHub
parent 2f3dff3de5
commit 333ab6d9e9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 23 additions and 21 deletions

View File

@ -1,7 +1,7 @@
import { localized, msg, str } from "@lit/localize"; import { localized, msg, str } from "@lit/localize";
import type { SlInput } from "@shoelace-style/shoelace"; import type { SlInput } from "@shoelace-style/shoelace";
import type { ZxcvbnResult } from "@zxcvbn-ts/core"; import type { ZxcvbnResult } from "@zxcvbn-ts/core";
import { customElement, property, state } from "lit/decorators.js"; import { customElement, property, query, state } from "lit/decorators.js";
import { when } from "lit/directives/when.js"; import { when } from "lit/directives/when.js";
import debounce from "lodash/fp/debounce"; import debounce from "lodash/fp/debounce";
@ -54,6 +54,9 @@ export class SignUpForm extends LiteElement {
@state() @state()
private showLoginLink = false; private showLoginLink = false;
@query('sl-input[name="password"]')
private readonly password?: SlInput | null;
protected firstUpdated() { protected firstUpdated() {
void PasswordService.setOptions(); void PasswordService.setOptions();
} }
@ -121,7 +124,7 @@ export class SignUpForm extends LiteElement {
passwordToggle passwordToggle
class="hide-required-content" class="hide-required-content"
required required
@input=${this.onPasswordInput as UnderlyingFunction< @sl-input=${this.onPasswordInput as UnderlyingFunction<
typeof this.onPasswordInput typeof this.onPasswordInput
>} >}
> >
@ -174,8 +177,8 @@ export class SignUpForm extends LiteElement {
</div> </div>
`; `;
private readonly onPasswordInput = debounce(150)(async (e: InputEvent) => { private readonly onPasswordInput = debounce(150)(async () => {
const { value } = e.target as SlInput; const value = this.password?.value;
if (!value || value.length < 4) { if (!value || value.length < 4) {
this.pwStrengthResults = null; this.pwStrengthResults = null;
return; return;

View File

@ -3,7 +3,7 @@ import type { SlInput, SlSelectEvent } from "@shoelace-style/shoelace";
import { serialize } from "@shoelace-style/shoelace/dist/utilities/form.js"; import { serialize } from "@shoelace-style/shoelace/dist/utilities/form.js";
import type { ZxcvbnResult } from "@zxcvbn-ts/core"; import type { ZxcvbnResult } from "@zxcvbn-ts/core";
import { nothing, type PropertyValues } from "lit"; import { nothing, type PropertyValues } from "lit";
import { customElement, property, queryAsync, state } from "lit/decorators.js"; import { customElement, property, query, state } from "lit/decorators.js";
import { choose } from "lit/directives/choose.js"; import { choose } from "lit/directives/choose.js";
import { when } from "lit/directives/when.js"; import { when } from "lit/directives/when.js";
import debounce from "lodash/fp/debounce"; import debounce from "lodash/fp/debounce";
@ -112,8 +112,8 @@ export class AccountSettings extends LiteElement {
@state() @state()
private pwStrengthResults: null | ZxcvbnResult = null; private pwStrengthResults: null | ZxcvbnResult = null;
@queryAsync('sl-input[name="password"]') @query('sl-input[name="newPassword"]')
private readonly passwordInput?: Promise<SlInput | null>; private readonly newPassword?: SlInput | null;
private get activeTab() { private get activeTab() {
return this.tab && Object.values(Tab).includes(this.tab as unknown as Tab) return this.tab && Object.values(Tab).includes(this.tab as unknown as Tab)
@ -257,7 +257,7 @@ export class AccountSettings extends LiteElement {
name="password" name="password"
label=${msg("Enter your current password")} label=${msg("Enter your current password")}
type="password" type="password"
autocomplete="off" autocomplete="current-password"
password-toggle password-toggle
required required
></sl-input> ></sl-input>
@ -269,7 +269,7 @@ export class AccountSettings extends LiteElement {
password-toggle password-toggle
minlength="8" minlength="8"
required required
@input=${this.onPasswordInput as UnderlyingFunction< @sl-input=${this.onPasswordInput as UnderlyingFunction<
typeof this.onPasswordInput typeof this.onPasswordInput
>} >}
></sl-input> ></sl-input>
@ -375,8 +375,8 @@ export class AccountSettings extends LiteElement {
</div> </div>
`; `;
private readonly onPasswordInput = debounce(150)(async (e: InputEvent) => { private readonly onPasswordInput = debounce(150)(async () => {
const { value } = e.target as SlInput; const value = this.newPassword?.value;
if (!value || value.length < 4) { if (!value || value.length < 4) {
this.pwStrengthResults = null; this.pwStrengthResults = null;
return; return;

View File

@ -1,7 +1,7 @@
import { localized, msg, str } from "@lit/localize"; import { localized, msg, str } from "@lit/localize";
import type { SlInput } from "@shoelace-style/shoelace"; import type { SlInput } from "@shoelace-style/shoelace";
import type { ZxcvbnResult } from "@zxcvbn-ts/core"; import type { ZxcvbnResult } from "@zxcvbn-ts/core";
import { customElement, property, state } from "lit/decorators.js"; import { customElement, property, query, state } from "lit/decorators.js";
import { when } from "lit/directives/when.js"; import { when } from "lit/directives/when.js";
import debounce from "lodash/fp/debounce"; import debounce from "lodash/fp/debounce";
@ -28,6 +28,9 @@ export class ResetPassword extends LiteElement {
@state() @state()
private isSubmitting = false; private isSubmitting = false;
@query('sl-input[name="newPassword"]')
private readonly newPassword?: SlInput | null;
protected firstUpdated() { protected firstUpdated() {
void PasswordService.setOptions(); void PasswordService.setOptions();
} }
@ -52,16 +55,15 @@ export class ResetPassword extends LiteElement {
<div class="mb-5"> <div class="mb-5">
<sl-input <sl-input
id="password" id="password"
name="password" name="newPassword"
type="password" type="password"
label="${msg("Enter new password")}" label="${msg("Enter new password")}"
help-text=${msg("Must be between 8-64 characters")}
minlength="8" minlength="8"
autocomplete="new-password" autocomplete="new-password"
passwordToggle passwordToggle
class="hide-required-content" class="hide-required-content"
required required
@input=${this.onPasswordInput as UnderlyingFunction< @sl-input=${this.onPasswordInput as UnderlyingFunction<
typeof this.onPasswordInput typeof this.onPasswordInput
>} >}
> >
@ -110,8 +112,8 @@ export class ResetPassword extends LiteElement {
</div> </div>
`; `;
private readonly onPasswordInput = debounce(150)(async (e: InputEvent) => { private readonly onPasswordInput = debounce(150)(async () => {
const { value } = e.target as SlInput; const value = this.newPassword?.value;
if (!value || value.length < 4) { if (!value || value.length < 4) {
this.pwStrengthResults = null; this.pwStrengthResults = null;
return; return;
@ -124,7 +126,7 @@ export class ResetPassword extends LiteElement {
this.isSubmitting = true; this.isSubmitting = true;
const formData = new FormData(event.target as HTMLFormElement); const formData = new FormData(event.target as HTMLFormElement);
const password = formData.get("password") as string; const password = formData.get("newPassword") as string;
const resp = await fetch("/api/auth/reset-password", { const resp = await fetch("/api/auth/reset-password", {
method: "POST", method: "POST",

View File

@ -3235,9 +3235,6 @@
<trans-unit id="sf151c44c3a52a448"> <trans-unit id="sf151c44c3a52a448">
<source>Enter new password</source> <source>Enter new password</source>
</trans-unit> </trans-unit>
<trans-unit id="sf6c0a694575fb0a6">
<source>Must be between 8-64 characters</source>
</trans-unit>
<trans-unit id="s8daf047a917f4cc4"> <trans-unit id="s8daf047a917f4cc4">
<source>Choose a strong password between <x equiv-text="${PASSWORD_MINLENGTH}" id="0"/>-<x equiv-text="${PASSWORD_MAXLENGTH}" id="1"/> characters.</source> <source>Choose a strong password between <x equiv-text="${PASSWORD_MINLENGTH}" id="0"/>-<x equiv-text="${PASSWORD_MAXLENGTH}" id="1"/> characters.</source>
</trans-unit> </trans-unit>