mirror of
https://github.com/bitwarden/browser
synced 2025-12-17 08:43:33 +00:00
merge main
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
class="tw-flex tw-min-h-screen tw-w-full tw-mx-auto tw-flex-col tw-gap-7 tw-bg-background-alt tw-px-8 tw-pb-4 tw-text-main"
|
||||
[ngClass]="{ 'tw-pt-0': decreaseTopPadding, 'tw-pt-8': !decreaseTopPadding }"
|
||||
>
|
||||
<bit-icon *ngIf="!hideLogo" [icon]="logo" class="tw-max-w-36"></bit-icon>
|
||||
<bit-icon *ngIf="!hideLogo" [icon]="logo" class="tw-w-[128px] [&>*]:tw-align-top"></bit-icon>
|
||||
|
||||
<div class="tw-text-center">
|
||||
<div class="tw-mx-auto tw-max-w-28 sm:tw-max-w-32">
|
||||
|
||||
@@ -10,9 +10,11 @@ import { RegisterVerificationEmailClickedRequest } from "@bitwarden/common/auth/
|
||||
import { HttpStatusCode } from "@bitwarden/common/enums";
|
||||
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
||||
import { ToastService } from "@bitwarden/components";
|
||||
|
||||
import { LoginStrategyServiceAbstraction, PasswordLoginCredentials } from "../../../common";
|
||||
import { InputPasswordComponent } from "../../input-password/input-password.component";
|
||||
import { PasswordInputResult } from "../../input-password/password-input-result";
|
||||
|
||||
@@ -46,6 +48,8 @@ export class RegistrationFinishComponent implements OnInit, OnDestroy {
|
||||
private registrationFinishService: RegistrationFinishService,
|
||||
private validationService: ValidationService,
|
||||
private accountApiService: AccountApiService,
|
||||
private loginStrategyService: LoginStrategyServiceAbstraction,
|
||||
private logService: LogService,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
@@ -90,8 +94,9 @@ export class RegistrationFinishComponent implements OnInit, OnDestroy {
|
||||
|
||||
async handlePasswordFormSubmit(passwordInputResult: PasswordInputResult) {
|
||||
this.submitting = true;
|
||||
let captchaBypassToken: string = null;
|
||||
try {
|
||||
await this.registrationFinishService.finishRegistration(
|
||||
captchaBypassToken = await this.registrationFinishService.finishRegistration(
|
||||
this.email,
|
||||
passwordInputResult,
|
||||
this.emailVerificationToken,
|
||||
@@ -102,14 +107,37 @@ export class RegistrationFinishComponent implements OnInit, OnDestroy {
|
||||
return;
|
||||
}
|
||||
|
||||
// Show acct created toast
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t("newAccountCreated"),
|
||||
message: this.i18nService.t("newAccountCreated2"),
|
||||
});
|
||||
|
||||
// login with the new account
|
||||
try {
|
||||
const credentials = new PasswordLoginCredentials(
|
||||
this.email,
|
||||
passwordInputResult.password,
|
||||
captchaBypassToken,
|
||||
null,
|
||||
);
|
||||
|
||||
await this.loginStrategyService.logIn(credentials);
|
||||
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t("youHaveBeenLoggedIn"),
|
||||
});
|
||||
|
||||
await this.router.navigate(["/vault"]);
|
||||
} catch (e) {
|
||||
// If login errors, redirect to login page per product. Don't show error
|
||||
this.logService.error("Error logging in after registration: ", e.message);
|
||||
await this.router.navigate(["/login"], { queryParams: { email: this.email } });
|
||||
}
|
||||
this.submitting = false;
|
||||
await this.router.navigate(["/login"], { queryParams: { email: this.email } });
|
||||
}
|
||||
|
||||
private async registerVerificationEmailClicked(email: string, emailVerificationToken: string) {
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
CalloutModule,
|
||||
DialogModule,
|
||||
DialogService,
|
||||
ToastService,
|
||||
} from "@bitwarden/components";
|
||||
|
||||
import { ActiveClientVerificationOption } from "./active-client-verification-option.enum";
|
||||
@@ -58,6 +59,7 @@ export class UserVerificationDialogComponent {
|
||||
private userVerificationService: UserVerificationService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private i18nService: I18nService,
|
||||
private toastService: ToastService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -256,19 +258,27 @@ export class UserVerificationDialogComponent {
|
||||
|
||||
// Only pin should ever get here, but added this check to be safe.
|
||||
if (this.activeClientVerificationOption === ActiveClientVerificationOption.Pin) {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("error"),
|
||||
this.i18nService.t("invalidPin"),
|
||||
);
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: this.i18nService.t("error"),
|
||||
message: this.i18nService.t("invalidPin"),
|
||||
});
|
||||
} else {
|
||||
this.platformUtilsService.showToast("error", null, this.i18nService.t("unexpectedError"));
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: null,
|
||||
message: this.i18nService.t("unexpectedError"),
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Catch handles OTP and MP verification scenarios as those throw errors on verification failure instead of returning false like PIN and biometrics.
|
||||
this.invalidSecret = true;
|
||||
this.platformUtilsService.showToast("error", this.i18nService.t("error"), e.message);
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: this.i18nService.t("error"),
|
||||
message: e.message,
|
||||
});
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -158,7 +158,10 @@ describe("AuthRequestLoginStrategy", () => {
|
||||
decMasterKeyHash,
|
||||
mockUserId,
|
||||
);
|
||||
expect(cryptoService.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith(tokenResponse.key);
|
||||
expect(cryptoService.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith(
|
||||
tokenResponse.key,
|
||||
mockUserId,
|
||||
);
|
||||
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userKey, mockUserId);
|
||||
expect(deviceTrustService.trustDeviceIfRequired).toHaveBeenCalled();
|
||||
expect(cryptoService.setPrivateKey).toHaveBeenCalledWith(tokenResponse.privateKey, mockUserId);
|
||||
@@ -183,7 +186,10 @@ describe("AuthRequestLoginStrategy", () => {
|
||||
expect(masterPasswordService.mock.setMasterKeyHash).not.toHaveBeenCalled();
|
||||
|
||||
// setMasterKeyEncryptedUserKey, setUserKey, and setPrivateKey should still be called
|
||||
expect(cryptoService.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith(tokenResponse.key);
|
||||
expect(cryptoService.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith(
|
||||
tokenResponse.key,
|
||||
mockUserId,
|
||||
);
|
||||
expect(cryptoService.setUserKey).toHaveBeenCalledWith(decUserKey, mockUserId);
|
||||
expect(cryptoService.setPrivateKey).toHaveBeenCalledWith(tokenResponse.privateKey, mockUserId);
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ export class AuthRequestLoginStrategy extends LoginStrategy {
|
||||
const authRequestCredentials = this.cache.value.authRequestCredentials;
|
||||
// User now may or may not have a master password
|
||||
// but set the master key encrypted user key if it exists regardless
|
||||
await this.cryptoService.setMasterKeyEncryptedUserKey(response.key);
|
||||
await this.cryptoService.setMasterKeyEncryptedUserKey(response.key, userId);
|
||||
|
||||
if (authRequestCredentials.decryptedUserKey) {
|
||||
await this.cryptoService.setUserKey(authRequestCredentials.decryptedUserKey, userId);
|
||||
|
||||
@@ -222,7 +222,11 @@ export abstract class LoginStrategy {
|
||||
),
|
||||
);
|
||||
|
||||
await this.billingAccountProfileStateService.setHasPremium(accountInformation.premium, false);
|
||||
await this.billingAccountProfileStateService.setHasPremium(
|
||||
accountInformation.premium,
|
||||
false,
|
||||
userId,
|
||||
);
|
||||
return userId;
|
||||
}
|
||||
|
||||
|
||||
@@ -172,7 +172,10 @@ describe("UserApiLoginStrategy", () => {
|
||||
|
||||
await apiLogInStrategy.logIn(credentials);
|
||||
|
||||
expect(cryptoService.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith(tokenResponse.key);
|
||||
expect(cryptoService.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith(
|
||||
tokenResponse.key,
|
||||
userId,
|
||||
);
|
||||
expect(cryptoService.setPrivateKey).toHaveBeenCalledWith(tokenResponse.privateKey, userId);
|
||||
});
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ export class UserApiLoginStrategy extends LoginStrategy {
|
||||
response: IdentityTokenResponse,
|
||||
userId: UserId,
|
||||
): Promise<void> {
|
||||
await this.cryptoService.setMasterKeyEncryptedUserKey(response.key);
|
||||
await this.cryptoService.setMasterKeyEncryptedUserKey(response.key, userId);
|
||||
|
||||
if (response.apiUseKeyConnector) {
|
||||
const masterKey = await firstValueFrom(this.masterPasswordService.masterKey$(userId));
|
||||
|
||||
Reference in New Issue
Block a user