Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
name="verificationCode"
formControlName="code"
appInputVerbatim
(paste)="onPaste($event)"
/>
</bit-form-field>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CommonModule, Location } from "@angular/common";
import { Component, OnDestroy, OnInit } from "@angular/core";
import { FormBuilder, ReactiveFormsModule, Validators } from "@angular/forms";
import { Component, OnDestroy, OnInit, viewChild } from "@angular/core";
import { FormBuilder, FormGroupDirective, ReactiveFormsModule, Validators } from "@angular/forms";
import { Router } from "@angular/router";
import { firstValueFrom, Subject, takeUntil } from "rxjs";

Expand Down Expand Up @@ -60,6 +60,8 @@ export class NewDeviceVerificationComponent implements OnInit, OnDestroy {
],
});

private readonly formGroupDirective = viewChild(FormGroupDirective);

protected disableRequestOTP = false;
private destroy$ = new Subject<void>();
protected authenticationSessionTimeoutRoute = "/authentication-timeout";
Expand Down Expand Up @@ -185,6 +187,16 @@ export class NewDeviceVerificationComponent implements OnInit, OnDestroy {
}
};

onPaste(event: ClipboardEvent) {
const pastedText = event.clipboardData?.getData("text")?.trim() ?? "";
if (!pastedText) {
return;
}
event.preventDefault();
this.formGroup.get("code")?.setValue(pastedText);
this.formGroupDirective()?.onSubmit(new Event("submit"));
}
Comment thread
JaredSnider-Bitwarden marked this conversation as resolved.
Comment thread
JaredSnider-Bitwarden marked this conversation as resolved.

protected goBack() {
this.location.back();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
appInputVerbatim
[formControl]="tokenFormControl"
(keyup)="onTokenChange($event)"
(paste)="onPaste($event)"
/>
</bit-form-field>
</ng-container>
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CommonModule } from "@angular/common";
import { Component, Input, Output, EventEmitter } from "@angular/core";
import { Component, Input, Output, EventEmitter, output } from "@angular/core";
import { ReactiveFormsModule, FormsModule, FormControl } from "@angular/forms";

import { JslibModule } from "@bitwarden/angular/jslib.module";
Expand Down Expand Up @@ -40,9 +40,20 @@ export class TwoFactorAuthAuthenticatorComponent {
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref
@Output() tokenChange = new EventEmitter<{ token: string }>();
submitOnPaste = output<void>();

onTokenChange(event: Event) {
const tokenValue = (event.target as HTMLInputElement).value || "";
this.tokenChange.emit({ token: tokenValue });
}

onPaste(event: ClipboardEvent) {
const pastedText = event.clipboardData?.getData("text")?.trim() ?? "";
if (!pastedText) {
return;
}
event.preventDefault();
this.tokenFormControl?.setValue(pastedText);
this.submitOnPaste.emit();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
appInputVerbatim
[formControl]="tokenFormControl"
(keyup)="onTokenChange($event)"
(paste)="onPaste($event)"
/>
</bit-form-field>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CommonModule } from "@angular/common";
import { Component, Input, OnInit, Output, EventEmitter } from "@angular/core";
import { Component, Input, OnInit, Output, EventEmitter, output } from "@angular/core";
import { ReactiveFormsModule, FormsModule, FormControl } from "@angular/forms";

import { JslibModule } from "@bitwarden/angular/jslib.module";
Expand Down Expand Up @@ -56,6 +56,7 @@ export class TwoFactorAuthEmailComponent implements OnInit {
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref
@Output() tokenChange = new EventEmitter<{ token: string }>();
submitOnPaste = output<void>();

twoFactorEmail: string | undefined = undefined;
emailPromise: Promise<any> | undefined;
Expand Down Expand Up @@ -107,6 +108,16 @@ export class TwoFactorAuthEmailComponent implements OnInit {
this.tokenChange.emit({ token: tokenValue });
}

onPaste(event: ClipboardEvent) {
const pastedText = event.clipboardData?.getData("text")?.trim() ?? "";
if (!pastedText) {
return;
}
event.preventDefault();
this.tokenFormControl?.setValue(pastedText);
this.submitOnPaste.emit();
}

async sendEmail(doToast: boolean) {
if (this.emailPromise !== undefined) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@
<app-two-factor-auth-email
[tokenFormControl]="tokenFormControl"
(tokenChange)="saveFormDataWithPartialData($event)"
(submitOnPaste)="continueButton?.nativeElement?.click()"
*ngIf="selectedProviderType === providerType.Email"
/>

<app-two-factor-auth-authenticator
[tokenFormControl]="tokenFormControl"
(tokenChange)="saveFormDataWithPartialData($event)"
(submitOnPaste)="continueButton?.nativeElement?.click()"
*ngIf="selectedProviderType === providerType.Authenticator"
/>
<app-two-factor-auth-yubikey
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
[verificationType]="dialogOptions.verificationType === 'client' ? 'client' : 'server'"
(activeClientVerificationOptionChange)="handleActiveClientVerificationOptionChange($event)"
(biometricsVerificationResultChange)="handleBiometricsVerificationResultChange($event)"
(pasteSubmit)="submitFromPaste()"
></app-user-verification-form-input>
</ng-container>
<ng-container bitDialogFooter>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { CommonModule } from "@angular/common";
import { Component, Inject } from "@angular/core";
import { FormBuilder, ReactiveFormsModule } from "@angular/forms";
import { Component, Inject, ViewChild } from "@angular/core";
import { FormBuilder, FormGroupDirective, ReactiveFormsModule } from "@angular/forms";
import { firstValueFrom } from "rxjs";

import { JslibModule } from "@bitwarden/angular/jslib.module";
Expand Down Expand Up @@ -46,6 +46,10 @@ import { UserVerificationFormInputComponent } from "./user-verification-form-inp
],
})
export class UserVerificationDialogComponent {
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-signals
@ViewChild(FormGroupDirective) private formGroupDirective: FormGroupDirective;

verificationForm = this.formBuilder.group({
secret: this.formBuilder.control<VerificationWithSecret | null>(null),
});
Expand Down Expand Up @@ -289,6 +293,10 @@ export class UserVerificationDialogComponent {
}
};

submitFromPaste(): void {
this.formGroupDirective?.onSubmit(new Event("submit"));
}

cancel() {
this.close({
userAction: "cancel",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@
name="verificationCode"
[formControl]="secret"
appInputVerbatim
(paste)="onPaste($event)"
/>
<bit-hint>{{ "confirmIdentity" | i18n }}</bit-hint>
</bit-form-field>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ export class UserVerificationFormInputComponent implements ControlValueAccessor,
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref
@Output() biometricsVerificationResultChange = new EventEmitter<boolean>();
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
// eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref
@Output() pasteSubmit = new EventEmitter<void>();

readonly Icons = { UserVerificationBiometricsIcon };

Expand Down Expand Up @@ -354,6 +357,21 @@ export class UserVerificationFormInputComponent implements ControlValueAccessor,
}
}

onPaste(event: ClipboardEvent) {
// Only auto-submit in server-side OTP mode (user has no master password)
if (this.verificationType !== "server" || !this.userVerificationOptions.server.otp) {
return;
}
const pastedText = event.clipboardData?.getData("text")?.trim() ?? "";
if (!pastedText) {
return;
}
event.preventDefault();
this.secret.setValue(pastedText); // triggers valueChanges β†’ processSecretChanges β†’ onChange
// β†’ dialog's secret FormControl updates synchronously
this.pasteSubmit.emit(); // dialog submits with the now-correct value
}

ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
Expand Down
Loading