diff --git a/apps/web/src/app/auth/core/services/login/web-login-component.service.ts b/apps/web/src/app/auth/core/services/login/web-login-component.service.ts index c644f26dd90..36e7143ccd0 100644 --- a/apps/web/src/app/auth/core/services/login/web-login-component.service.ts +++ b/apps/web/src/app/auth/core/services/login/web-login-component.service.ts @@ -98,7 +98,7 @@ export class WebLoginComponentService const enforcedPasswordPolicyOptions = await firstValueFrom( this.accountService.activeAccount$.pipe( getUserId, - switchMap((userId) => this.policyService.masterPasswordPolicyOptions$(userId)), + switchMap((userId) => this.policyService.masterPasswordPolicyOptions$(userId, policies)), ), ); diff --git a/apps/web/src/app/auth/settings/security/password-settings/password-settings.component.html b/apps/web/src/app/auth/settings/security/password-settings/password-settings.component.html index 94cf08b5871..e5fb7142a1a 100644 --- a/apps/web/src/app/auth/settings/security/password-settings/password-settings.component.html +++ b/apps/web/src/app/auth/settings/security/password-settings/password-settings.component.html @@ -3,7 +3,6 @@
- {{ "loggedOutWarning" | i18n }}
diff --git a/apps/web/src/app/oss-routing.module.ts b/apps/web/src/app/oss-routing.module.ts index 2c3664284d2..c1592efea4a 100644 --- a/apps/web/src/app/oss-routing.module.ts +++ b/apps/web/src/app/oss-routing.module.ts @@ -155,8 +155,10 @@ const routes: Routes = [ }, ], data: { - pageIcon: undefined, + pageIcon: LockIcon, + pageTitle: { key: "updateMasterPassword" }, hideFooter: true, + maxWidth: "lg", } satisfies AnonLayoutWrapperData, }, ], @@ -168,7 +170,7 @@ const routes: Routes = [ canActivate: [ canAccessFeature( FeatureFlag.PM16117_ChangeExistingPasswordRefactor, - false, + true, "/change-password", false, ), @@ -182,7 +184,7 @@ const routes: Routes = [ canActivate: [ canAccessFeature( FeatureFlag.PM16117_ChangeExistingPasswordRefactor, - false, + true, "/change-password", false, ), diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 3bf3ab91c78..034a08bdf52 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -1788,6 +1788,9 @@ "loggedOutWarning": { "message": "Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour." }, + "changePasswordWarning": { + "message": "After changing your password, you will need to log in with your new password. Active sessions on other devices will be logged out within one hour." + }, "emailChanged": { "message": "Email saved" }, diff --git a/libs/auth/src/angular/anon-layout/anon-layout-wrapper.component.ts b/libs/auth/src/angular/anon-layout/anon-layout-wrapper.component.ts index c0b072fd8f1..5ae2fdbf347 100644 --- a/libs/auth/src/angular/anon-layout/anon-layout-wrapper.component.ts +++ b/libs/auth/src/angular/anon-layout/anon-layout-wrapper.component.ts @@ -34,7 +34,7 @@ export interface AnonLayoutWrapperData { /** * Optional flag to set the max-width of the page. Defaults to 'md' if not provided. */ - maxWidth?: "md" | "3xl"; + maxWidth?: "sm" | "md" | "lg" | "xl" | "2xl" | "3xl"; /** * Optional flag to set the max-width of the title area. Defaults to null if not provided. */ diff --git a/libs/auth/src/angular/anon-layout/anon-layout.component.html b/libs/auth/src/angular/anon-layout/anon-layout.component.html index 1e16dba82cc..439087f902a 100644 --- a/libs/auth/src/angular/anon-layout/anon-layout.component.html +++ b/libs/auth/src/angular/anon-layout/anon-layout.component.html @@ -37,7 +37,14 @@
} diff --git a/libs/auth/src/angular/change-password/change-password.component.ts b/libs/auth/src/angular/change-password/change-password.component.ts index 9cfb78d994b..85d421072b1 100644 --- a/libs/auth/src/angular/change-password/change-password.component.ts +++ b/libs/auth/src/angular/change-password/change-password.component.ts @@ -5,25 +5,15 @@ import { firstValueFrom } from "rxjs"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options"; import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; -import { PasswordRequest } from "@bitwarden/common/auth/models/request/password.request"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; -import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { SyncService } from "@bitwarden/common/platform/sync"; import { UserId } from "@bitwarden/common/types/guid"; -import { UserKey } from "@bitwarden/common/types/key"; import { DialogService, ToastService, Translation } from "@bitwarden/components"; -import { KeyService } from "@bitwarden/key-management"; import { I18nPipe } from "@bitwarden/ui-common"; -// import { -// AcceptOrganizationInviteService -// } from "@bitwarden/web-vault/src/app/auth/organization-invite/accept-organization.service"; -// import { RouterService } from "@bitwarden/web-vault/src/app/core"; import { InputPasswordComponent, @@ -48,18 +38,15 @@ export class ChangePasswordComponent implements OnInit { masterPasswordPolicyOptions?: MasterPasswordPolicyOptions; initializing = true; submitting = false; - userkeyRotationV2 = false; formPromise?: Promise; - secondaryButtonText?: Translation = undefined; forceSetPasswordReason: ForceSetPasswordReason = ForceSetPasswordReason.None; + warningText?: Translation; constructor( private accountService: AccountService, private changePasswordService: ChangePasswordService, private configService: ConfigService, private i18nService: I18nService, - private keyService: KeyService, - private masterPasswordApiService: MasterPasswordApiService, private masterPasswordService: InternalMasterPasswordServiceAbstraction, private messagingService: MessagingService, private policyService: PolicyService, @@ -72,8 +59,6 @@ export class ChangePasswordComponent implements OnInit { ) {} async ngOnInit() { - this.userkeyRotationV2 = await this.configService.getFeatureFlag(FeatureFlag.UserKeyRotationV2); - this.activeAccount = await firstValueFrom(this.accountService.activeAccount$); this.activeUserId = this.activeAccount?.id; this.email = this.activeAccount?.email; @@ -90,26 +75,10 @@ export class ChangePasswordComponent implements OnInit { this.masterPasswordService.forceSetPasswordReason$(this.activeUserId), ); - if ( - this.forceSetPasswordReason === ForceSetPasswordReason.AdminForcePasswordReset || - this.forceSetPasswordReason === ForceSetPasswordReason.WeakMasterPassword - ) { - this.secondaryButtonText = { key: "cancel" }; - } else { - this.secondaryButtonText = undefined; - } - this.initializing = false; - } - async performSecondaryAction() { - if ( - this.forceSetPasswordReason === ForceSetPasswordReason.AdminForcePasswordReset || - this.forceSetPasswordReason === ForceSetPasswordReason.WeakMasterPassword - ) { - await this.logOut(); - } else { - await this.cancel(); + if (this.masterPasswordPolicyOptions?.enforceOnLogin) { + this.warningText = { key: "masterPasswordInvalidWarning" }; } } @@ -126,24 +95,9 @@ export class ChangePasswordComponent implements OnInit { } } - async cancel() { - // clearing the login redirect url so that the user - // does not join the organization if they cancel - // await this.routerService.getAndClearLoginRedirectUrl(); - // await this.acceptOrganizationInviteService.clearOrganizationInvitation(); - // await this.router.navigate(["/vault"]); - } - async handlePasswordFormSubmit(passwordInputResult: PasswordInputResult) { this.submitting = true; - if (this.userkeyRotationV2) { - await this.submitNew(passwordInputResult); - } else { - await this.submitOld(passwordInputResult); - } - } - private async submitNew(passwordInputResult: PasswordInputResult) { try { if (passwordInputResult.rotateUserKey) { if (this.activeAccount == null) { @@ -187,83 +141,4 @@ export class ChangePasswordComponent implements OnInit { this.submitting = false; } } - - private async submitOld(passwordInputResult: PasswordInputResult) { - if (!this.activeUserId) { - throw new Error("userId not found"); - } - - if (passwordInputResult.currentServerMasterKeyHash == null) { - throw new Error("currentServerMasterKeyHash not found"); - } - - if (passwordInputResult.rotateUserKey) { - await this.syncService.fullSync(true); - } - - let newMasterKeyEncryptedUserKey: [UserKey, EncString] | null = null; - - const userKey = await this.keyService.getUserKey(); - if (userKey == null) { - newMasterKeyEncryptedUserKey = await this.keyService.makeUserKey( - passwordInputResult.newMasterKey, - ); - } else { - newMasterKeyEncryptedUserKey = await this.keyService.encryptUserKeyWithMasterKey( - passwordInputResult.newMasterKey, - ); - } - - const request = new PasswordRequest(); - request.masterPasswordHash = passwordInputResult.currentServerMasterKeyHash; - request.newMasterPasswordHash = passwordInputResult.newServerMasterKeyHash; - request.masterPasswordHint = passwordInputResult.newPasswordHint; - request.key = newMasterKeyEncryptedUserKey[1].encryptedString as string; - - try { - if (passwordInputResult.rotateUserKey) { - this.formPromise = this.masterPasswordApiService.postPassword(request).then(async () => { - // we need to save this for local masterkey verification during rotation - await this.masterPasswordService.setMasterKeyHash( - passwordInputResult.newLocalMasterKeyHash, - this.activeUserId as UserId, - ); - await this.masterPasswordService.setMasterKey( - passwordInputResult.newMasterKey, - this.activeUserId as UserId, - ); - return this.updateKey(passwordInputResult.newPassword); - }); - } else { - this.formPromise = this.masterPasswordApiService.postPassword(request); - } - - await this.formPromise; - - this.toastService.showToast({ - variant: "success", - title: this.i18nService.t("masterPasswordChanged"), - message: this.i18nService.t("logBackIn"), - }); - - this.messagingService.send("logout"); - } catch { - this.toastService.showToast({ - variant: "error", - title: "", - message: this.i18nService.t("errorOccurred"), - }); - } - } - - private async updateKey(newPassword: string) { - if (this.activeAccount == null) { - throw new Error("activeAccount not found"); - } - - await this.changePasswordService.rotateUserKeyAndEncryptedDataLegacy( - newPassword, - this.activeAccount, - ); - } } diff --git a/libs/auth/src/angular/input-password/input-password.component.html b/libs/auth/src/angular/input-password/input-password.component.html index 8955a7b40b1..d7742a97876 100644 --- a/libs/auth/src/angular/input-password/input-password.component.html +++ b/libs/auth/src/angular/input-password/input-password.component.html @@ -1,4 +1,6 @@
+ {{ "changePasswordWarning" | i18n }} +