mirror of
https://github.com/bitwarden/browser
synced 2025-12-25 20:53:22 +00:00
feat(change-password): [PM-18720] (#5319) Change Password Implementation for Non Dialog Cases (#15319)
* feat(change-password-component): Change Password Update [18720] - Very close to complete. * fix(policy-enforcement): [PM-21085] Fix Bug with Policy Enforcement - Removed temp code to force the state I need to verify correctness. * fix(policy-enforcement): [PM-21085] Fix Bug with Policy Enforcement - Recover account working with change password component. * fix(policy-enforcement): [PM-21085] Fix Bug with Policy Enforcement - Made code more dry. * fix(change-password-component): Change Password Update [18720] - Updates to routing and the extension. Extension is still a wip. * fix(change-password-component): Change Password Update [18720] - Extension routing changes. * feat(change-password-component): Change Password Update [18720] - More extension work * feat(change-password-component): Change Password Update [18720] - Pausing work for now while we wait for product to hear back. * feat(change-password-component): Change Password Update [18720] - Removed duplicated anon layouts. * feat(change-password-component): Change Password Update [18720] - Tidied up code. * feat(change-password-component): Change Password Update [18720] - Small fixes to the styling * feat(change-password-component): Change Password Update [18720] - Adding more content for the routing. * feat(change-password-component): Change Password Update [18720] - Removed circular loop for now. * feat(change-password-component): Change Password Update [18720] - Made comments regarding the change password routing complexities with change-password and auth guard. * feat(change-password-component): Change Password Update [18720] - Undid some changes because they will be conflicts later on. * feat(change-password-component): Change Password Update [18720] - Small directive change. * feat(change-password-component): Change Password Update [18720] - Small changes and added some clarification on where I'm blocked * feat(change-password-component): Change Password Update [18720] - Org invite is seemingly working, found one bug to iron out. * refactor(change-password-component): Change Password Update [18720] - Fixed up policy service to be made more clear. * docs(change-password-component): Change Password Update [18720] - Updated documentation. * refactor(change-password-component): Change Password Update [18720] - Routing changes and policy service changes. * fix(change-password-component): Change Password Update [18720] - Wrapping up changes. * feat(change-password-component): Change Password Update [18720] - Should be working fully * feat(change-password-component): Change Password Update [18720] - Found a bug, working on password policy being present on login. * feat(change-password-component): Change Password Update [18720] - Turned on auth guard on other clients for change-password route. * feat(change-password-component): Change Password Update [18720] - Committing intermediate changes. * feat(change-password-component): Change Password Update [18720] - The master password policy endpoint has been added! Should be working. Testing now. * feat(change-password-component): Change Password Update [18720] - Minor fixes. * feat(change-password-component): Change Password Update [18720] - Undid naming change. * feat(change-password-component): Change Password Update [18720] - Removed comment. * feat(change-password-component): Change Password Update [18720] - Removed unneeded code. * fix(change-password-component): Change Password Update [18720] - Took org invite state out of service and made it accessible. * fix(change-password-component): Change Password Update [18720] - Small changes. * fix(change-password-component): Change Password Update [18720] - Split up org invite service into client specific implementations and have them injected into clients properly * feat(change-password-component): Change Password Update [18720] - Stopping work and going to switch to a new branch to pare down some of the solutions that were made to get this over the finish line * feat(change-password-component): Change Password Update [18720] - Started to remove functionality in the login.component and the password login strategy. * feat(change-password-component): Change Password Update [18720] - Removed more unneded changes. * feat(change-password-component): Change Password Update [18720] - Change password clearing state working properly. * fix(change-password-component): Change Password Update [18720] - Added docs and moved web implementation. * comments(change-password-component): Change Password Update [18720] - Added more notes. * test(change-password-component): Change Password Update [18720] - Added in tests for policy service. * comment(change-password-component): Change Password Update [18720] - Updated doc with correct ticket number. * comment(change-password-component): Change Password Update [18720] - Fixed doc. * test(change-password-component): Change Password Update [18720] - Fixed tests. * test(change-password-component): Change Password Update [18720] - Fixed linting errors. Have more tests to fix. * test(change-password-component): Change Password Update [18720] - Added back in ignore for typesafety. * fix(change-password-component): Change Password Update [18720] - Fixed other type issues. * test(change-password-component): Change Password Update [18720] - Fixed tests. * test(change-password-component): Change Password Update [18720] - Fixed more tests. * test(change-password-component): Change Password Update [18720] - Fixed tiny duplicate code. * fix(change-password-component): Change Password Update [18720] - Fixed desktop component. * fix(change-password-component): Change Password Update [18720] - Removed unused code * fix(change-password-component): Change Password Update [18720] - Fixed locales. * fix(change-password-component): Change Password Update [18720] - Removed tracing. * fix(change-password-component): Change Password Update [18720] - Removed duplicative services module entry. * fix(change-password-component): Change Password Update [18720] - Added comment. * fix(change-password-component): Change Password Update [18720] - Fixed unneeded call in two factor to get user id. * fix(change-password-component): Change Password Update [18720] - Fixed a couple of tiny things. * fix(change-password-component): Change Password Update [18720] - Added comment for later fix. * fix(change-password-component): Change Password Update [18720] - Fixed linting error. * PM-18720 - AuthGuard - move call to get isChangePasswordFlagOn down after other conditions for efficiency. * PM-18720 - PasswordLoginStrategy tests - test new feature flagged combine org invite policies logic for weak password evaluation. * PM-18720 - CLI - fix dep issue * PM-18720 - ChangePasswordComp - extract change password warning up out of input password component * PM-18720 - InputPassword - remove unused dependency. * PM-18720 - ChangePasswordComp - add callout dep * PM-18720 - Revert all anon-layout changes * PM-18720 - Anon Layout - finish reverting changes. * PM-18720 - WIP move of change password out of libs/auth * PM-18720 - Clean up remaining imports from moving change password out of libs/auth * PM-18720 - Add change-password barrel file for better import grouping * PM-18720 - Change Password comp - restore maxWidth * PM-18720 - After merge, fix errors * PM-18720 - Desktop - fix api service import * PM-18720 - NDV - fix routing. * PM-18720 - Change Password Comp - add logout service todo * PM-18720 - PasswordSettings - per feedback, component is already feature flagged behind PM16117_ChangeExistingPasswordRefactor so we can just delete the replaced callout (new text is in change-password comp) * PM-18720 - Routing Modules - properly flag new component behind feature flag. * PM-18720 - SSO Login Strategy - fix config service import since it is now in shared deps from main merge. * PM-18720 - Fix SSO login strategy tests * PM-18720 - Default Policy Service - address AC PR feedback --------- Co-authored-by: Jared Snider <jsnider@bitwarden.com> Co-authored-by: Jared Snider <116684653+JaredSnider-Bitwarden@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
ec015bd253
commit
1f60bcdcc0
@@ -1,8 +1,12 @@
|
||||
import { ChangePasswordService, DefaultChangePasswordService } from "@bitwarden/auth/angular";
|
||||
import {
|
||||
ChangePasswordService,
|
||||
DefaultChangePasswordService,
|
||||
} from "@bitwarden/angular/auth/password-management/change-password";
|
||||
import { Account } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
|
||||
import { KeyService } from "@bitwarden/key-management";
|
||||
import { RouterService } from "@bitwarden/web-vault/app/core";
|
||||
import { UserKeyRotationService } from "@bitwarden/web-vault/app/key-management/key-rotation/user-key-rotation.service";
|
||||
|
||||
export class WebChangePasswordService
|
||||
@@ -14,6 +18,7 @@ export class WebChangePasswordService
|
||||
protected masterPasswordApiService: MasterPasswordApiService,
|
||||
protected masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
||||
private userKeyRotationService: UserKeyRotationService,
|
||||
private routerService: RouterService,
|
||||
) {
|
||||
super(keyService, masterPasswordApiService, masterPasswordService);
|
||||
}
|
||||
@@ -31,4 +36,8 @@ export class WebChangePasswordService
|
||||
newPasswordHint,
|
||||
);
|
||||
}
|
||||
|
||||
async clearDeeplinkState() {
|
||||
await this.routerService.getAndClearLoginRedirectUrl();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@ import {
|
||||
LoginDecryptionOptionsService,
|
||||
DefaultLoginDecryptionOptionsService,
|
||||
} from "@bitwarden/auth/angular";
|
||||
import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
|
||||
import { RouterService } from "../../../../core/router.service";
|
||||
import { AcceptOrganizationInviteService } from "../../../organization-invite/accept-organization.service";
|
||||
|
||||
export class WebLoginDecryptionOptionsService
|
||||
extends DefaultLoginDecryptionOptionsService
|
||||
@@ -16,7 +16,7 @@ export class WebLoginDecryptionOptionsService
|
||||
constructor(
|
||||
protected messagingService: MessagingService,
|
||||
private routerService: RouterService,
|
||||
private acceptOrganizationInviteService: AcceptOrganizationInviteService,
|
||||
private organizationInviteService: OrganizationInviteService,
|
||||
) {
|
||||
super(messagingService);
|
||||
}
|
||||
@@ -27,7 +27,7 @@ export class WebLoginDecryptionOptionsService
|
||||
// accepted while being enrolled in admin recovery. So we need to clear
|
||||
// the redirect and stored org invite.
|
||||
await this.routerService.getAndClearLoginRedirectUrl();
|
||||
await this.acceptOrganizationInviteService.clearOrganizationInvitation();
|
||||
await this.organizationInviteService.clearOrganizationInvitation();
|
||||
} catch (error) {
|
||||
throw new Error(error);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,9 @@ import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
||||
import { ResetPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/reset-password-policy-options";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||
import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service";
|
||||
import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
@@ -22,7 +24,6 @@ import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legac
|
||||
// FIXME: remove `src` and fix import
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { RouterService } from "../../../../../../../../apps/web/src/app/core";
|
||||
import { AcceptOrganizationInviteService } from "../../../organization-invite/accept-organization.service";
|
||||
|
||||
import { WebLoginComponentService } from "./web-login-component.service";
|
||||
|
||||
@@ -32,7 +33,7 @@ jest.mock("../../../../../utils/flags", () => ({
|
||||
|
||||
describe("WebLoginComponentService", () => {
|
||||
let service: WebLoginComponentService;
|
||||
let acceptOrganizationInviteService: MockProxy<AcceptOrganizationInviteService>;
|
||||
let organizationInviteService: MockProxy<OrganizationInviteService>;
|
||||
let logService: MockProxy<LogService>;
|
||||
let policyApiService: MockProxy<PolicyApiServiceAbstraction>;
|
||||
let internalPolicyService: MockProxy<InternalPolicyService>;
|
||||
@@ -44,9 +45,10 @@ describe("WebLoginComponentService", () => {
|
||||
let ssoLoginService: MockProxy<SsoLoginServiceAbstraction>;
|
||||
const mockUserId = Utils.newGuid() as UserId;
|
||||
let accountService: FakeAccountService;
|
||||
let configService: MockProxy<ConfigService>;
|
||||
|
||||
beforeEach(() => {
|
||||
acceptOrganizationInviteService = mock<AcceptOrganizationInviteService>();
|
||||
organizationInviteService = mock<OrganizationInviteService>();
|
||||
logService = mock<LogService>();
|
||||
policyApiService = mock<PolicyApiServiceAbstraction>();
|
||||
internalPolicyService = mock<InternalPolicyService>();
|
||||
@@ -57,12 +59,13 @@ describe("WebLoginComponentService", () => {
|
||||
platformUtilsService = mock<PlatformUtilsService>();
|
||||
ssoLoginService = mock<SsoLoginServiceAbstraction>();
|
||||
accountService = mockAccountServiceWith(mockUserId);
|
||||
configService = mock<ConfigService>();
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
WebLoginComponentService,
|
||||
{ provide: DefaultLoginComponentService, useClass: WebLoginComponentService },
|
||||
{ provide: AcceptOrganizationInviteService, useValue: acceptOrganizationInviteService },
|
||||
{ provide: OrganizationInviteService, useValue: organizationInviteService },
|
||||
{ provide: LogService, useValue: logService },
|
||||
{ provide: PolicyApiServiceAbstraction, useValue: policyApiService },
|
||||
{ provide: InternalPolicyService, useValue: internalPolicyService },
|
||||
@@ -73,6 +76,7 @@ describe("WebLoginComponentService", () => {
|
||||
{ provide: PlatformUtilsService, useValue: platformUtilsService },
|
||||
{ provide: SsoLoginServiceAbstraction, useValue: ssoLoginService },
|
||||
{ provide: AccountService, useValue: accountService },
|
||||
{ provide: ConfigService, useValue: configService },
|
||||
],
|
||||
});
|
||||
service = TestBed.inject(WebLoginComponentService);
|
||||
@@ -84,14 +88,14 @@ describe("WebLoginComponentService", () => {
|
||||
|
||||
describe("getOrgPoliciesFromOrgInvite", () => {
|
||||
it("returns undefined if organization invite is null", async () => {
|
||||
acceptOrganizationInviteService.getOrganizationInvite.mockResolvedValue(null);
|
||||
organizationInviteService.getOrganizationInvite.mockResolvedValue(null);
|
||||
const result = await service.getOrgPoliciesFromOrgInvite();
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it("logs an error if getPoliciesByToken throws an error", async () => {
|
||||
const error = new Error("Test error");
|
||||
acceptOrganizationInviteService.getOrganizationInvite.mockResolvedValue({
|
||||
organizationInviteService.getOrganizationInvite.mockResolvedValue({
|
||||
organizationId: "org-id",
|
||||
token: "token",
|
||||
email: "email",
|
||||
@@ -117,7 +121,7 @@ describe("WebLoginComponentService", () => {
|
||||
const resetPasswordPolicyOptions = new ResetPasswordPolicyOptions();
|
||||
resetPasswordPolicyOptions.autoEnrollEnabled = autoEnrollEnabled;
|
||||
|
||||
acceptOrganizationInviteService.getOrganizationInvite.mockResolvedValue({
|
||||
organizationInviteService.getOrganizationInvite.mockResolvedValue({
|
||||
organizationId: "org-id",
|
||||
token: "token",
|
||||
email: "email",
|
||||
|
||||
@@ -11,18 +11,21 @@ import {
|
||||
} from "@bitwarden/auth/angular";
|
||||
import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction";
|
||||
import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
|
||||
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy";
|
||||
|
||||
import { RouterService } from "../../../../core/router.service";
|
||||
import { AcceptOrganizationInviteService } from "../../../organization-invite/accept-organization.service";
|
||||
|
||||
@Injectable()
|
||||
export class WebLoginComponentService
|
||||
@@ -30,7 +33,7 @@ export class WebLoginComponentService
|
||||
implements LoginComponentService
|
||||
{
|
||||
constructor(
|
||||
protected acceptOrganizationInviteService: AcceptOrganizationInviteService,
|
||||
protected organizationInviteService: OrganizationInviteService,
|
||||
protected logService: LogService,
|
||||
protected policyApiService: PolicyApiServiceAbstraction,
|
||||
protected policyService: InternalPolicyService,
|
||||
@@ -42,6 +45,7 @@ export class WebLoginComponentService
|
||||
ssoLoginService: SsoLoginServiceAbstraction,
|
||||
private router: Router,
|
||||
private accountService: AccountService,
|
||||
private configService: ConfigService,
|
||||
) {
|
||||
super(
|
||||
cryptoFunctionService,
|
||||
@@ -66,8 +70,8 @@ export class WebLoginComponentService
|
||||
return;
|
||||
}
|
||||
|
||||
async getOrgPoliciesFromOrgInvite(): Promise<PasswordPolicies | null> {
|
||||
const orgInvite = await this.acceptOrganizationInviteService.getOrganizationInvite();
|
||||
async getOrgPoliciesFromOrgInvite(): Promise<PasswordPolicies | undefined> {
|
||||
const orgInvite = await this.organizationInviteService.getOrganizationInvite();
|
||||
|
||||
if (orgInvite != null) {
|
||||
let policies: Policy[];
|
||||
@@ -84,7 +88,7 @@ export class WebLoginComponentService
|
||||
}
|
||||
|
||||
if (policies == null) {
|
||||
return;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const resetPasswordPolicy = this.policyService.getResetPasswordPolicyOptions(
|
||||
@@ -95,12 +99,23 @@ export class WebLoginComponentService
|
||||
const isPolicyAndAutoEnrollEnabled =
|
||||
resetPasswordPolicy[1] && resetPasswordPolicy[0].autoEnrollEnabled;
|
||||
|
||||
const enforcedPasswordPolicyOptions = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(
|
||||
getUserId,
|
||||
switchMap((userId) => this.policyService.masterPasswordPolicyOptions$(userId, policies)),
|
||||
),
|
||||
);
|
||||
let enforcedPasswordPolicyOptions: MasterPasswordPolicyOptions;
|
||||
|
||||
if (
|
||||
await this.configService.getFeatureFlag(FeatureFlag.PM16117_ChangeExistingPasswordRefactor)
|
||||
) {
|
||||
enforcedPasswordPolicyOptions =
|
||||
this.policyService.combinePoliciesIntoMasterPasswordPolicyOptions(policies);
|
||||
} else {
|
||||
enforcedPasswordPolicyOptions = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(
|
||||
getUserId,
|
||||
switchMap((userId) =>
|
||||
this.policyService.masterPasswordPolicyOptions$(userId, policies),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
policies,
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { OrganizationInvite } from "@bitwarden/common/auth/services/organization-invite/organization-invite";
|
||||
import { ORGANIZATION_INVITE } from "@bitwarden/common/auth/services/organization-invite/organization-invite-state";
|
||||
import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service";
|
||||
import { GlobalState, GlobalStateProvider } from "@bitwarden/common/platform/state";
|
||||
|
||||
export class WebOrganizationInviteService implements OrganizationInviteService {
|
||||
private organizationInvitationState: GlobalState<OrganizationInvite | null>;
|
||||
|
||||
constructor(private readonly globalStateProvider: GlobalStateProvider) {
|
||||
this.organizationInvitationState = this.globalStateProvider.get(ORGANIZATION_INVITE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently stored organization invite
|
||||
*/
|
||||
async getOrganizationInvite(): Promise<OrganizationInvite | null> {
|
||||
return await firstValueFrom(this.organizationInvitationState.state$);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a new organization invite
|
||||
* @param invite an organization invite
|
||||
* @throws if the invite is nullish
|
||||
*/
|
||||
async setOrganizationInvitation(invite: OrganizationInvite): Promise<void> {
|
||||
if (invite == null) {
|
||||
throw new Error("Invite cannot be null. Use clearOrganizationInvitation instead.");
|
||||
}
|
||||
await this.organizationInvitationState.update(() => invite);
|
||||
}
|
||||
|
||||
/** Clears the currently stored organization invite */
|
||||
async clearOrganizationInvitation(): Promise<void> {
|
||||
await this.organizationInvitationState.update(() => null);
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction";
|
||||
import { SetPasswordRequest } from "@bitwarden/common/auth/models/request/set-password.request";
|
||||
import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service";
|
||||
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
|
||||
import { KeysRequest } from "@bitwarden/common/models/request/keys.request";
|
||||
@@ -25,7 +26,6 @@ import { CsprngArray } from "@bitwarden/common/types/csprng";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { MasterKey, UserKey } from "@bitwarden/common/types/key";
|
||||
import { DEFAULT_KDF_CONFIG, KdfConfigService, KeyService } from "@bitwarden/key-management";
|
||||
import { AcceptOrganizationInviteService } from "@bitwarden/web-vault/app/auth/organization-invite/accept-organization.service";
|
||||
import { RouterService } from "@bitwarden/web-vault/app/core";
|
||||
|
||||
import { WebSetInitialPasswordService } from "./web-set-initial-password.service";
|
||||
@@ -43,7 +43,7 @@ describe("WebSetInitialPasswordService", () => {
|
||||
let organizationApiService: MockProxy<OrganizationApiServiceAbstraction>;
|
||||
let organizationUserApiService: MockProxy<OrganizationUserApiService>;
|
||||
let userDecryptionOptionsService: MockProxy<InternalUserDecryptionOptionsServiceAbstraction>;
|
||||
let acceptOrganizationInviteService: MockProxy<AcceptOrganizationInviteService>;
|
||||
let organizationInviteService: MockProxy<OrganizationInviteService>;
|
||||
let routerService: MockProxy<RouterService>;
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -57,7 +57,7 @@ describe("WebSetInitialPasswordService", () => {
|
||||
organizationApiService = mock<OrganizationApiServiceAbstraction>();
|
||||
organizationUserApiService = mock<OrganizationUserApiService>();
|
||||
userDecryptionOptionsService = mock<InternalUserDecryptionOptionsServiceAbstraction>();
|
||||
acceptOrganizationInviteService = mock<AcceptOrganizationInviteService>();
|
||||
organizationInviteService = mock<OrganizationInviteService>();
|
||||
routerService = mock<RouterService>();
|
||||
|
||||
sut = new WebSetInitialPasswordService(
|
||||
@@ -71,7 +71,7 @@ describe("WebSetInitialPasswordService", () => {
|
||||
organizationApiService,
|
||||
organizationUserApiService,
|
||||
userDecryptionOptionsService,
|
||||
acceptOrganizationInviteService,
|
||||
organizationInviteService,
|
||||
routerService,
|
||||
);
|
||||
});
|
||||
@@ -169,9 +169,7 @@ describe("WebSetInitialPasswordService", () => {
|
||||
|
||||
// Assert
|
||||
expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest);
|
||||
expect(acceptOrganizationInviteService.clearOrganizationInvitation).toHaveBeenCalledTimes(
|
||||
1,
|
||||
);
|
||||
expect(organizationInviteService.clearOrganizationInvitation).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -201,7 +199,7 @@ describe("WebSetInitialPasswordService", () => {
|
||||
// Assert
|
||||
await expect(promise).rejects.toThrow();
|
||||
expect(masterPasswordApiService.setPassword).not.toHaveBeenCalled();
|
||||
expect(acceptOrganizationInviteService.clearOrganizationInvitation).not.toHaveBeenCalled();
|
||||
expect(organizationInviteService.clearOrganizationInvitation).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,12 +9,12 @@ import { InternalUserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction";
|
||||
import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service";
|
||||
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { KdfConfigService, KeyService } from "@bitwarden/key-management";
|
||||
import { AcceptOrganizationInviteService } from "@bitwarden/web-vault/app/auth/organization-invite/accept-organization.service";
|
||||
import { RouterService } from "@bitwarden/web-vault/app/core";
|
||||
|
||||
export class WebSetInitialPasswordService
|
||||
@@ -32,7 +32,7 @@ export class WebSetInitialPasswordService
|
||||
protected organizationApiService: OrganizationApiServiceAbstraction,
|
||||
protected organizationUserApiService: OrganizationUserApiService,
|
||||
protected userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction,
|
||||
private acceptOrganizationInviteService: AcceptOrganizationInviteService,
|
||||
private organizationInviteService: OrganizationInviteService,
|
||||
private routerService: RouterService,
|
||||
) {
|
||||
super(
|
||||
@@ -78,6 +78,6 @@ export class WebSetInitialPasswordService
|
||||
* as clear the org invite itself that was originally set in state by the AcceptOrganizationComponent.
|
||||
*/
|
||||
await this.routerService.getAndClearLoginRedirectUrl();
|
||||
await this.acceptOrganizationInviteService.clearOrganizationInvitation();
|
||||
await this.organizationInviteService.clearOrganizationInvitation();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,20 +9,16 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli
|
||||
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
|
||||
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
||||
import { AccountApiService } from "@bitwarden/common/auth/abstractions/account-api.service";
|
||||
import { OrganizationInvite } from "@bitwarden/common/auth/services/organization-invite/organization-invite";
|
||||
import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
||||
import { CsprngArray } from "@bitwarden/common/types/csprng";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { MasterKey, UserKey } from "@bitwarden/common/types/key";
|
||||
import { DEFAULT_KDF_CONFIG, KeyService } from "@bitwarden/key-management";
|
||||
|
||||
import { AcceptOrganizationInviteService } from "../../../organization-invite/accept-organization.service";
|
||||
import { OrganizationInvite } from "../../../organization-invite/organization-invite";
|
||||
|
||||
import { WebRegistrationFinishService } from "./web-registration-finish.service";
|
||||
|
||||
describe("WebRegistrationFinishService", () => {
|
||||
@@ -30,32 +26,28 @@ describe("WebRegistrationFinishService", () => {
|
||||
|
||||
let keyService: MockProxy<KeyService>;
|
||||
let accountApiService: MockProxy<AccountApiService>;
|
||||
let acceptOrgInviteService: MockProxy<AcceptOrganizationInviteService>;
|
||||
let organizationInviteService: MockProxy<OrganizationInviteService>;
|
||||
let policyApiService: MockProxy<PolicyApiServiceAbstraction>;
|
||||
let logService: MockProxy<LogService>;
|
||||
let policyService: MockProxy<PolicyService>;
|
||||
let configService: MockProxy<ConfigService>;
|
||||
const mockUserId = Utils.newGuid() as UserId;
|
||||
let accountService: FakeAccountService;
|
||||
|
||||
beforeEach(() => {
|
||||
keyService = mock<KeyService>();
|
||||
accountApiService = mock<AccountApiService>();
|
||||
acceptOrgInviteService = mock<AcceptOrganizationInviteService>();
|
||||
organizationInviteService = mock<OrganizationInviteService>();
|
||||
policyApiService = mock<PolicyApiServiceAbstraction>();
|
||||
logService = mock<LogService>();
|
||||
policyService = mock<PolicyService>();
|
||||
accountService = mockAccountServiceWith(mockUserId);
|
||||
configService = mock<ConfigService>();
|
||||
|
||||
service = new WebRegistrationFinishService(
|
||||
keyService,
|
||||
accountApiService,
|
||||
acceptOrgInviteService,
|
||||
organizationInviteService,
|
||||
policyApiService,
|
||||
logService,
|
||||
policyService,
|
||||
accountService,
|
||||
configService,
|
||||
);
|
||||
});
|
||||
@@ -76,21 +68,21 @@ describe("WebRegistrationFinishService", () => {
|
||||
});
|
||||
|
||||
it("returns null when the org invite is null", async () => {
|
||||
acceptOrgInviteService.getOrganizationInvite.mockResolvedValue(null);
|
||||
organizationInviteService.getOrganizationInvite.mockResolvedValue(null);
|
||||
|
||||
const result = await service.getOrgNameFromOrgInvite();
|
||||
|
||||
expect(result).toBeNull();
|
||||
expect(acceptOrgInviteService.getOrganizationInvite).toHaveBeenCalled();
|
||||
expect(organizationInviteService.getOrganizationInvite).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("returns the organization name from the organization invite when it exists", async () => {
|
||||
acceptOrgInviteService.getOrganizationInvite.mockResolvedValue(orgInvite);
|
||||
organizationInviteService.getOrganizationInvite.mockResolvedValue(orgInvite);
|
||||
|
||||
const result = await service.getOrgNameFromOrgInvite();
|
||||
|
||||
expect(result).toEqual(orgInvite.organizationName);
|
||||
expect(acceptOrgInviteService.getOrganizationInvite).toHaveBeenCalled();
|
||||
expect(organizationInviteService.getOrganizationInvite).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -106,22 +98,22 @@ describe("WebRegistrationFinishService", () => {
|
||||
});
|
||||
|
||||
it("returns null when the org invite is null", async () => {
|
||||
acceptOrgInviteService.getOrganizationInvite.mockResolvedValue(null);
|
||||
organizationInviteService.getOrganizationInvite.mockResolvedValue(null);
|
||||
|
||||
const result = await service.getMasterPasswordPolicyOptsFromOrgInvite();
|
||||
|
||||
expect(result).toBeNull();
|
||||
expect(acceptOrgInviteService.getOrganizationInvite).toHaveBeenCalled();
|
||||
expect(organizationInviteService.getOrganizationInvite).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("returns null when the policies are null", async () => {
|
||||
acceptOrgInviteService.getOrganizationInvite.mockResolvedValue(orgInvite);
|
||||
organizationInviteService.getOrganizationInvite.mockResolvedValue(orgInvite);
|
||||
policyApiService.getPoliciesByToken.mockResolvedValue(null);
|
||||
|
||||
const result = await service.getMasterPasswordPolicyOptsFromOrgInvite();
|
||||
|
||||
expect(result).toBeNull();
|
||||
expect(acceptOrgInviteService.getOrganizationInvite).toHaveBeenCalled();
|
||||
expect(organizationInviteService.getOrganizationInvite).toHaveBeenCalled();
|
||||
expect(policyApiService.getPoliciesByToken).toHaveBeenCalledWith(
|
||||
orgInvite.organizationId,
|
||||
orgInvite.token,
|
||||
@@ -131,13 +123,13 @@ describe("WebRegistrationFinishService", () => {
|
||||
});
|
||||
|
||||
it("logs an error and returns null when policies cannot be fetched", async () => {
|
||||
acceptOrgInviteService.getOrganizationInvite.mockResolvedValue(orgInvite);
|
||||
organizationInviteService.getOrganizationInvite.mockResolvedValue(orgInvite);
|
||||
policyApiService.getPoliciesByToken.mockRejectedValue(new Error("error"));
|
||||
|
||||
const result = await service.getMasterPasswordPolicyOptsFromOrgInvite();
|
||||
|
||||
expect(result).toBeNull();
|
||||
expect(acceptOrgInviteService.getOrganizationInvite).toHaveBeenCalled();
|
||||
expect(organizationInviteService.getOrganizationInvite).toHaveBeenCalled();
|
||||
expect(policyApiService.getPoliciesByToken).toHaveBeenCalledWith(
|
||||
orgInvite.organizationId,
|
||||
orgInvite.token,
|
||||
@@ -151,14 +143,14 @@ describe("WebRegistrationFinishService", () => {
|
||||
const masterPasswordPolicies = [new Policy()];
|
||||
const masterPasswordPolicyOptions = new MasterPasswordPolicyOptions();
|
||||
|
||||
acceptOrgInviteService.getOrganizationInvite.mockResolvedValue(orgInvite);
|
||||
organizationInviteService.getOrganizationInvite.mockResolvedValue(orgInvite);
|
||||
policyApiService.getPoliciesByToken.mockResolvedValue(masterPasswordPolicies);
|
||||
policyService.masterPasswordPolicyOptions$.mockReturnValue(of(masterPasswordPolicyOptions));
|
||||
|
||||
const result = await service.getMasterPasswordPolicyOptsFromOrgInvite();
|
||||
|
||||
expect(result).toEqual(masterPasswordPolicyOptions);
|
||||
expect(acceptOrgInviteService.getOrganizationInvite).toHaveBeenCalled();
|
||||
expect(organizationInviteService.getOrganizationInvite).toHaveBeenCalled();
|
||||
expect(policyApiService.getPoliciesByToken).toHaveBeenCalledWith(
|
||||
orgInvite.organizationId,
|
||||
orgInvite.token,
|
||||
@@ -225,7 +217,7 @@ describe("WebRegistrationFinishService", () => {
|
||||
keyService.makeUserKey.mockResolvedValue([userKey, userKeyEncString]);
|
||||
keyService.makeKeyPair.mockResolvedValue(userKeyPair);
|
||||
accountApiService.registerFinish.mockResolvedValue();
|
||||
acceptOrgInviteService.getOrganizationInvite.mockResolvedValue(null);
|
||||
organizationInviteService.getOrganizationInvite.mockResolvedValue(null);
|
||||
|
||||
await service.finishRegistration(email, passwordInputResult, emailVerificationToken);
|
||||
|
||||
@@ -261,7 +253,7 @@ describe("WebRegistrationFinishService", () => {
|
||||
keyService.makeUserKey.mockResolvedValue([userKey, userKeyEncString]);
|
||||
keyService.makeKeyPair.mockResolvedValue(userKeyPair);
|
||||
accountApiService.registerFinish.mockResolvedValue();
|
||||
acceptOrgInviteService.getOrganizationInvite.mockResolvedValue(orgInvite);
|
||||
organizationInviteService.getOrganizationInvite.mockResolvedValue(orgInvite);
|
||||
|
||||
await service.finishRegistration(email, passwordInputResult);
|
||||
|
||||
@@ -297,7 +289,7 @@ describe("WebRegistrationFinishService", () => {
|
||||
keyService.makeUserKey.mockResolvedValue([userKey, userKeyEncString]);
|
||||
keyService.makeKeyPair.mockResolvedValue(userKeyPair);
|
||||
accountApiService.registerFinish.mockResolvedValue();
|
||||
acceptOrgInviteService.getOrganizationInvite.mockResolvedValue(null);
|
||||
organizationInviteService.getOrganizationInvite.mockResolvedValue(null);
|
||||
|
||||
await service.finishRegistration(
|
||||
email,
|
||||
@@ -338,7 +330,7 @@ describe("WebRegistrationFinishService", () => {
|
||||
keyService.makeUserKey.mockResolvedValue([userKey, userKeyEncString]);
|
||||
keyService.makeKeyPair.mockResolvedValue(userKeyPair);
|
||||
accountApiService.registerFinish.mockResolvedValue();
|
||||
acceptOrgInviteService.getOrganizationInvite.mockResolvedValue(null);
|
||||
organizationInviteService.getOrganizationInvite.mockResolvedValue(null);
|
||||
|
||||
await service.finishRegistration(
|
||||
email,
|
||||
@@ -381,7 +373,7 @@ describe("WebRegistrationFinishService", () => {
|
||||
keyService.makeUserKey.mockResolvedValue([userKey, userKeyEncString]);
|
||||
keyService.makeKeyPair.mockResolvedValue(userKeyPair);
|
||||
accountApiService.registerFinish.mockResolvedValue();
|
||||
acceptOrgInviteService.getOrganizationInvite.mockResolvedValue(null);
|
||||
organizationInviteService.getOrganizationInvite.mockResolvedValue(null);
|
||||
|
||||
await service.finishRegistration(
|
||||
email,
|
||||
|
||||
@@ -12,16 +12,14 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli
|
||||
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
|
||||
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
||||
import { AccountApiService } from "@bitwarden/common/auth/abstractions/account-api.service";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { RegisterFinishRequest } from "@bitwarden/common/auth/models/request/registration/register-finish.request";
|
||||
import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { EncryptedString, EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||
import { KeyService } from "@bitwarden/key-management";
|
||||
|
||||
import { AcceptOrganizationInviteService } from "../../../organization-invite/accept-organization.service";
|
||||
|
||||
export class WebRegistrationFinishService
|
||||
extends DefaultRegistrationFinishService
|
||||
implements RegistrationFinishService
|
||||
@@ -29,18 +27,17 @@ export class WebRegistrationFinishService
|
||||
constructor(
|
||||
protected keyService: KeyService,
|
||||
protected accountApiService: AccountApiService,
|
||||
private acceptOrgInviteService: AcceptOrganizationInviteService,
|
||||
private organizationInviteService: OrganizationInviteService,
|
||||
private policyApiService: PolicyApiServiceAbstraction,
|
||||
private logService: LogService,
|
||||
private policyService: PolicyService,
|
||||
private accountService: AccountService,
|
||||
private configService: ConfigService,
|
||||
) {
|
||||
super(keyService, accountApiService);
|
||||
}
|
||||
|
||||
override async getOrgNameFromOrgInvite(): Promise<string | null> {
|
||||
const orgInvite = await this.acceptOrgInviteService.getOrganizationInvite();
|
||||
const orgInvite = await this.organizationInviteService.getOrganizationInvite();
|
||||
if (orgInvite == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -50,7 +47,7 @@ export class WebRegistrationFinishService
|
||||
|
||||
override async getMasterPasswordPolicyOptsFromOrgInvite(): Promise<MasterPasswordPolicyOptions | null> {
|
||||
// If there's a deep linked org invite, use it to get the password policies
|
||||
const orgInvite = await this.acceptOrgInviteService.getOrganizationInvite();
|
||||
const orgInvite = await this.organizationInviteService.getOrganizationInvite();
|
||||
|
||||
if (orgInvite == null) {
|
||||
return null;
|
||||
@@ -115,7 +112,7 @@ export class WebRegistrationFinishService
|
||||
// web specific logic
|
||||
// Org invites are deep linked. Non-existent accounts are redirected to the register page.
|
||||
// Org user id and token are included here only for validation and two factor purposes.
|
||||
const orgInvite = await this.acceptOrgInviteService.getOrganizationInvite();
|
||||
const orgInvite = await this.organizationInviteService.getOrganizationInvite();
|
||||
if (orgInvite != null) {
|
||||
registerRequest.organizationUserId = orgInvite.organizationUserId;
|
||||
registerRequest.orgInviteToken = orgInvite.token;
|
||||
|
||||
@@ -5,16 +5,16 @@ import {
|
||||
SetPasswordCredentials,
|
||||
SetPasswordJitService,
|
||||
} from "@bitwarden/auth/angular";
|
||||
import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service";
|
||||
|
||||
import { RouterService } from "../../../../core/router.service";
|
||||
import { AcceptOrganizationInviteService } from "../../../organization-invite/accept-organization.service";
|
||||
|
||||
export class WebSetPasswordJitService
|
||||
extends DefaultSetPasswordJitService
|
||||
implements SetPasswordJitService
|
||||
{
|
||||
routerService = inject(RouterService);
|
||||
acceptOrganizationInviteService = inject(AcceptOrganizationInviteService);
|
||||
organizationInviteService = inject(OrganizationInviteService);
|
||||
|
||||
override async setPassword(credentials: SetPasswordCredentials) {
|
||||
await super.setPassword(credentials);
|
||||
@@ -22,6 +22,6 @@ export class WebSetPasswordJitService
|
||||
// SSO JIT accepts org invites when setting their MP, meaning
|
||||
// we can clear the deep linked url for accepting it.
|
||||
await this.routerService.getAndClearLoginRedirectUrl();
|
||||
await this.acceptOrganizationInviteService.clearOrganizationInvitation();
|
||||
await this.organizationInviteService.clearOrganizationInvitation();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,14 @@ import { Component } from "@angular/core";
|
||||
import { ActivatedRoute, Params, Router } from "@angular/router";
|
||||
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { OrganizationInvite } from "@bitwarden/common/auth/services/organization-invite/organization-invite";
|
||||
import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
|
||||
import { BaseAcceptComponent } from "../../common/base.accept.component";
|
||||
|
||||
import { AcceptOrganizationInviteService } from "./accept-organization.service";
|
||||
import { OrganizationInvite } from "./organization-invite";
|
||||
|
||||
@Component({
|
||||
templateUrl: "accept-organization.component.html",
|
||||
@@ -21,18 +22,19 @@ export class AcceptOrganizationComponent extends BaseAcceptComponent {
|
||||
protected requiredParameters: string[] = ["organizationId", "organizationUserId", "token"];
|
||||
|
||||
constructor(
|
||||
router: Router,
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
i18nService: I18nService,
|
||||
route: ActivatedRoute,
|
||||
authService: AuthService,
|
||||
protected router: Router,
|
||||
protected platformUtilsService: PlatformUtilsService,
|
||||
protected i18nService: I18nService,
|
||||
protected route: ActivatedRoute,
|
||||
protected authService: AuthService,
|
||||
private acceptOrganizationInviteService: AcceptOrganizationInviteService,
|
||||
private organizationInviteService: OrganizationInviteService,
|
||||
) {
|
||||
super(router, platformUtilsService, i18nService, route, authService);
|
||||
}
|
||||
|
||||
async authedHandler(qParams: Params): Promise<void> {
|
||||
const invite = OrganizationInvite.fromParams(qParams);
|
||||
const invite = this.fromParams(qParams);
|
||||
const success = await this.acceptOrganizationInviteService.validateAndAcceptInvite(invite);
|
||||
|
||||
if (!success) {
|
||||
@@ -52,9 +54,9 @@ export class AcceptOrganizationComponent extends BaseAcceptComponent {
|
||||
}
|
||||
|
||||
async unauthedHandler(qParams: Params): Promise<void> {
|
||||
const invite = OrganizationInvite.fromParams(qParams);
|
||||
const invite = this.fromParams(qParams);
|
||||
|
||||
await this.acceptOrganizationInviteService.setOrganizationInvitation(invite);
|
||||
await this.organizationInviteService.setOrganizationInvitation(invite);
|
||||
await this.navigateInviteAcceptance(invite);
|
||||
}
|
||||
|
||||
@@ -94,4 +96,21 @@ export class AcceptOrganizationComponent extends BaseAcceptComponent {
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
private fromParams(params: Params): OrganizationInvite | null {
|
||||
if (params == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Object.assign(new OrganizationInvite(), {
|
||||
email: params.email,
|
||||
initOrganization: params.initOrganization?.toLocaleLowerCase() === "true",
|
||||
orgSsoIdentifier: params.orgSsoIdentifier,
|
||||
orgUserHasExistingUser: params.orgUserHasExistingUser?.toLocaleLowerCase() === "true",
|
||||
organizationId: params.organizationId,
|
||||
organizationName: params.organizationName,
|
||||
organizationUserId: params.organizationUserId,
|
||||
token: params.token,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { FakeGlobalStateProvider } from "@bitwarden/common/../spec/fake-state-provider";
|
||||
import { MockProxy, mock } from "jest-mock-extended";
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
|
||||
@@ -15,22 +14,18 @@ import { ResetPasswordPolicyOptions } from "@bitwarden/common/admin-console/mode
|
||||
import { OrganizationKeysResponse } from "@bitwarden/common/admin-console/models/response/organization-keys.response";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { OrganizationInvite } from "@bitwarden/common/auth/services/organization-invite/organization-invite";
|
||||
import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service";
|
||||
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||
import { FakeGlobalState } from "@bitwarden/common/spec/fake-state";
|
||||
import { OrgKey } from "@bitwarden/common/types/key";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
import { KeyService } from "@bitwarden/key-management";
|
||||
|
||||
import { I18nService } from "../../core/i18n.service";
|
||||
|
||||
import {
|
||||
AcceptOrganizationInviteService,
|
||||
ORGANIZATION_INVITE,
|
||||
} from "./accept-organization.service";
|
||||
import { OrganizationInvite } from "./organization-invite";
|
||||
import { AcceptOrganizationInviteService } from "./accept-organization.service";
|
||||
|
||||
describe("AcceptOrganizationInviteService", () => {
|
||||
let sut: AcceptOrganizationInviteService;
|
||||
@@ -43,10 +38,8 @@ describe("AcceptOrganizationInviteService", () => {
|
||||
let logService: MockProxy<LogService>;
|
||||
let organizationApiService: MockProxy<OrganizationApiServiceAbstraction>;
|
||||
let organizationUserApiService: MockProxy<OrganizationUserApiService>;
|
||||
let organizationInviteService: MockProxy<OrganizationInviteService>;
|
||||
let i18nService: MockProxy<I18nService>;
|
||||
let globalStateProvider: FakeGlobalStateProvider;
|
||||
let globalState: FakeGlobalState<OrganizationInvite>;
|
||||
let dialogService: MockProxy<DialogService>;
|
||||
let accountService: MockProxy<AccountService>;
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -59,10 +52,8 @@ describe("AcceptOrganizationInviteService", () => {
|
||||
logService = mock();
|
||||
organizationApiService = mock();
|
||||
organizationUserApiService = mock();
|
||||
organizationInviteService = mock();
|
||||
i18nService = mock();
|
||||
globalStateProvider = new FakeGlobalStateProvider();
|
||||
globalState = globalStateProvider.getFake(ORGANIZATION_INVITE);
|
||||
dialogService = mock();
|
||||
accountService = mock();
|
||||
|
||||
sut = new AcceptOrganizationInviteService(
|
||||
@@ -76,8 +67,7 @@ describe("AcceptOrganizationInviteService", () => {
|
||||
organizationApiService,
|
||||
organizationUserApiService,
|
||||
i18nService,
|
||||
globalStateProvider,
|
||||
dialogService,
|
||||
organizationInviteService,
|
||||
accountService,
|
||||
);
|
||||
});
|
||||
@@ -103,8 +93,10 @@ describe("AcceptOrganizationInviteService", () => {
|
||||
expect(result).toBe(true);
|
||||
expect(organizationUserApiService.postOrganizationUserAcceptInit).toHaveBeenCalled();
|
||||
expect(apiService.refreshIdentityToken).toHaveBeenCalled();
|
||||
expect(globalState.nextMock).toHaveBeenCalledWith(null);
|
||||
expect(organizationUserApiService.postOrganizationUserAccept).not.toHaveBeenCalled();
|
||||
expect(organizationInviteService.getOrganizationInvite).not.toHaveBeenCalled();
|
||||
expect(organizationInviteService.setOrganizationInvitation).not.toHaveBeenCalled();
|
||||
expect(organizationInviteService.clearOrganizationInvitation).toHaveBeenCalled();
|
||||
expect(authService.logOut).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -121,13 +113,16 @@ describe("AcceptOrganizationInviteService", () => {
|
||||
|
||||
expect(result).toBe(false);
|
||||
expect(authService.logOut).toHaveBeenCalled();
|
||||
expect(globalState.nextMock).toHaveBeenCalledWith(invite);
|
||||
expect(organizationInviteService.setOrganizationInvitation).toHaveBeenCalledWith(invite);
|
||||
expect(organizationInviteService.clearOrganizationInvitation).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("clears the stored invite when a master password policy check is required but the stored invite doesn't match the provided one", async () => {
|
||||
const storedInvite = createOrgInvite({ email: "wrongemail@example.com" });
|
||||
const providedInvite = createOrgInvite();
|
||||
await globalState.update(() => storedInvite);
|
||||
organizationInviteService.getOrganizationInvite.mockReturnValueOnce(
|
||||
Promise.resolve(storedInvite),
|
||||
);
|
||||
policyApiService.getPoliciesByToken.mockResolvedValue([
|
||||
{
|
||||
type: PolicyType.MasterPassword,
|
||||
@@ -139,7 +134,11 @@ describe("AcceptOrganizationInviteService", () => {
|
||||
|
||||
expect(result).toBe(false);
|
||||
expect(authService.logOut).toHaveBeenCalled();
|
||||
expect(globalState.nextMock).toHaveBeenCalledWith(providedInvite);
|
||||
expect(organizationInviteService.setOrganizationInvitation).toHaveBeenCalledWith(
|
||||
providedInvite,
|
||||
);
|
||||
expect(organizationInviteService.getOrganizationInvite).toHaveBeenCalledWith();
|
||||
expect(organizationInviteService.clearOrganizationInvitation).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("accepts the invitation request when the organization doesn't have a master password policy", async () => {
|
||||
@@ -151,8 +150,10 @@ describe("AcceptOrganizationInviteService", () => {
|
||||
expect(result).toBe(true);
|
||||
expect(organizationUserApiService.postOrganizationUserAccept).toHaveBeenCalled();
|
||||
expect(apiService.refreshIdentityToken).toHaveBeenCalled();
|
||||
expect(globalState.nextMock).toHaveBeenCalledWith(null);
|
||||
expect(organizationUserApiService.postOrganizationUserAcceptInit).not.toHaveBeenCalled();
|
||||
expect(organizationInviteService.setOrganizationInvitation).not.toHaveBeenCalled();
|
||||
expect(organizationInviteService.getOrganizationInvite).not.toHaveBeenCalled();
|
||||
expect(organizationInviteService.clearOrganizationInvitation).toHaveBeenCalled();
|
||||
expect(authService.logOut).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -165,7 +166,7 @@ describe("AcceptOrganizationInviteService", () => {
|
||||
} as Policy,
|
||||
]);
|
||||
// an existing invite means the user has already passed the master password policy
|
||||
await globalState.update(() => invite);
|
||||
organizationInviteService.getOrganizationInvite.mockReturnValueOnce(Promise.resolve(invite));
|
||||
|
||||
policyService.getResetPasswordPolicyOptions.mockReturnValue([
|
||||
{
|
||||
@@ -179,6 +180,8 @@ describe("AcceptOrganizationInviteService", () => {
|
||||
expect(result).toBe(true);
|
||||
expect(organizationUserApiService.postOrganizationUserAccept).toHaveBeenCalled();
|
||||
expect(organizationUserApiService.postOrganizationUserAcceptInit).not.toHaveBeenCalled();
|
||||
expect(organizationInviteService.getOrganizationInvite).toHaveBeenCalledWith();
|
||||
expect(organizationInviteService.clearOrganizationInvitation).toHaveBeenCalled();
|
||||
expect(authService.logOut).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -202,7 +205,7 @@ describe("AcceptOrganizationInviteService", () => {
|
||||
encryptedString: "encryptedString",
|
||||
} as EncString);
|
||||
|
||||
await globalState.update(() => invite);
|
||||
organizationInviteService.getOrganizationInvite.mockReturnValueOnce(Promise.resolve(invite));
|
||||
|
||||
policyService.getResetPasswordPolicyOptions.mockReturnValue([
|
||||
{
|
||||
@@ -220,6 +223,9 @@ describe("AcceptOrganizationInviteService", () => {
|
||||
);
|
||||
expect(organizationUserApiService.postOrganizationUserAccept).toHaveBeenCalled();
|
||||
expect(organizationUserApiService.postOrganizationUserAcceptInit).not.toHaveBeenCalled();
|
||||
expect(organizationInviteService.getOrganizationInvite).toHaveBeenCalledTimes(1);
|
||||
expect(organizationInviteService.getOrganizationInvite).toHaveBeenCalledWith();
|
||||
expect(organizationInviteService.clearOrganizationInvitation).toHaveBeenCalled();
|
||||
expect(authService.logOut).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17,36 +17,17 @@ import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
||||
import { OrganizationKeysRequest } from "@bitwarden/common/admin-console/models/request/organization-keys.request";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { OrganizationInvite } from "@bitwarden/common/auth/services/organization-invite/organization-invite";
|
||||
import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service";
|
||||
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import {
|
||||
GlobalState,
|
||||
GlobalStateProvider,
|
||||
KeyDefinition,
|
||||
ORGANIZATION_INVITE_DISK,
|
||||
} from "@bitwarden/common/platform/state";
|
||||
import { OrgKey } from "@bitwarden/common/types/key";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
import { KeyService } from "@bitwarden/key-management";
|
||||
|
||||
import { OrganizationInvite } from "./organization-invite";
|
||||
|
||||
// We're storing the organization invite for 2 reasons:
|
||||
// 1. If the org requires a MP policy check, we need to keep track that the user has already been redirected when they return.
|
||||
// 2. The MP policy check happens on login/register flows, we need to store the token to retrieve the policies then.
|
||||
export const ORGANIZATION_INVITE = new KeyDefinition<OrganizationInvite | null>(
|
||||
ORGANIZATION_INVITE_DISK,
|
||||
"organizationInvite",
|
||||
{
|
||||
deserializer: (invite) => (invite ? OrganizationInvite.fromJSON(invite) : null),
|
||||
},
|
||||
);
|
||||
|
||||
@Injectable()
|
||||
export class AcceptOrganizationInviteService {
|
||||
private organizationInvitationState: GlobalState<OrganizationInvite | null>;
|
||||
private orgNameSubject: BehaviorSubject<string> = new BehaviorSubject<string>(null);
|
||||
private policyCache: Policy[];
|
||||
|
||||
@@ -64,34 +45,9 @@ export class AcceptOrganizationInviteService {
|
||||
private readonly organizationApiService: OrganizationApiServiceAbstraction,
|
||||
private readonly organizationUserApiService: OrganizationUserApiService,
|
||||
private readonly i18nService: I18nService,
|
||||
private readonly globalStateProvider: GlobalStateProvider,
|
||||
private readonly dialogService: DialogService,
|
||||
private readonly organizationInviteService: OrganizationInviteService,
|
||||
private readonly accountService: AccountService,
|
||||
) {
|
||||
this.organizationInvitationState = this.globalStateProvider.get(ORGANIZATION_INVITE);
|
||||
}
|
||||
|
||||
/** Returns the currently stored organization invite */
|
||||
async getOrganizationInvite(): Promise<OrganizationInvite | null> {
|
||||
return await firstValueFrom(this.organizationInvitationState.state$);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a new organization invite
|
||||
* @param invite an organization invite
|
||||
* @throws if the invite is nullish
|
||||
*/
|
||||
async setOrganizationInvitation(invite: OrganizationInvite): Promise<void> {
|
||||
if (invite == null) {
|
||||
throw new Error("Invite cannot be null. Use clearOrganizationInvitation instead.");
|
||||
}
|
||||
await this.organizationInvitationState.update(() => invite);
|
||||
}
|
||||
|
||||
/** Clears the currently stored organization invite */
|
||||
async clearOrganizationInvitation(): Promise<void> {
|
||||
await this.organizationInvitationState.update(() => null);
|
||||
}
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Validates and accepts the organization invitation if possible.
|
||||
@@ -113,7 +69,7 @@ export class AcceptOrganizationInviteService {
|
||||
|
||||
// Accepting an org invite from existing org
|
||||
if (await this.masterPasswordPolicyCheckRequired(invite)) {
|
||||
await this.setOrganizationInvitation(invite);
|
||||
await this.organizationInviteService.setOrganizationInvitation(invite);
|
||||
this.authService.logOut(() => {
|
||||
/* Do nothing */
|
||||
});
|
||||
@@ -134,7 +90,7 @@ export class AcceptOrganizationInviteService {
|
||||
),
|
||||
);
|
||||
await this.apiService.refreshIdentityToken();
|
||||
await this.clearOrganizationInvitation();
|
||||
await this.organizationInviteService.clearOrganizationInvitation();
|
||||
}
|
||||
|
||||
private async prepareAcceptAndInitRequest(
|
||||
@@ -170,7 +126,7 @@ export class AcceptOrganizationInviteService {
|
||||
);
|
||||
|
||||
await this.apiService.refreshIdentityToken();
|
||||
await this.clearOrganizationInvitation();
|
||||
await this.organizationInviteService.clearOrganizationInvitation();
|
||||
}
|
||||
|
||||
private async prepareAcceptRequest(
|
||||
@@ -224,10 +180,10 @@ export class AcceptOrganizationInviteService {
|
||||
(p) => p.type === PolicyType.MasterPassword && p.enabled,
|
||||
);
|
||||
|
||||
let storedInvite = await this.getOrganizationInvite();
|
||||
let storedInvite = await this.organizationInviteService.getOrganizationInvite();
|
||||
if (storedInvite?.email !== invite.email) {
|
||||
// clear stored invites if the email doesn't match
|
||||
await this.clearOrganizationInvitation();
|
||||
await this.organizationInviteService.clearOrganizationInvitation();
|
||||
storedInvite = null;
|
||||
}
|
||||
// if we don't have an org invite stored, we know the user hasn't been redirected yet to check the MP policy
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Params } from "@angular/router";
|
||||
import { Jsonify } from "type-fest";
|
||||
|
||||
export class OrganizationInvite {
|
||||
email: string;
|
||||
initOrganization: boolean;
|
||||
orgSsoIdentifier: string;
|
||||
orgUserHasExistingUser: boolean;
|
||||
organizationId: string;
|
||||
organizationName: string;
|
||||
organizationUserId: string;
|
||||
token: string;
|
||||
|
||||
static fromJSON(json: Jsonify<OrganizationInvite>): OrganizationInvite | null {
|
||||
if (json == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Object.assign(new OrganizationInvite(), json);
|
||||
}
|
||||
|
||||
static fromParams(params: Params): OrganizationInvite | null {
|
||||
if (params == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Object.assign(new OrganizationInvite(), {
|
||||
email: params.email,
|
||||
initOrganization: params.initOrganization?.toLocaleLowerCase() === "true",
|
||||
orgSsoIdentifier: params.orgSsoIdentifier,
|
||||
orgUserHasExistingUser: params.orgUserHasExistingUser?.toLocaleLowerCase() === "true",
|
||||
organizationId: params.organizationId,
|
||||
organizationName: params.organizationName,
|
||||
organizationUserId: params.organizationUserId,
|
||||
token: params.token,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,12 @@
|
||||
import { Component, inject } from "@angular/core";
|
||||
|
||||
import { SetPasswordComponent as BaseSetPasswordComponent } from "@bitwarden/angular/auth/components/set-password.component";
|
||||
import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service";
|
||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||
import { MasterKey, UserKey } from "@bitwarden/common/types/key";
|
||||
|
||||
import { RouterService } from "../core";
|
||||
|
||||
import { AcceptOrganizationInviteService } from "./organization-invite/accept-organization.service";
|
||||
|
||||
@Component({
|
||||
selector: "app-set-password",
|
||||
templateUrl: "set-password.component.html",
|
||||
@@ -15,7 +14,7 @@ import { AcceptOrganizationInviteService } from "./organization-invite/accept-or
|
||||
})
|
||||
export class SetPasswordComponent extends BaseSetPasswordComponent {
|
||||
routerService = inject(RouterService);
|
||||
acceptOrganizationInviteService = inject(AcceptOrganizationInviteService);
|
||||
organizationInviteService = inject(OrganizationInviteService);
|
||||
|
||||
protected override async onSetPasswordSuccess(
|
||||
masterKey: MasterKey,
|
||||
@@ -26,6 +25,6 @@ export class SetPasswordComponent extends BaseSetPasswordComponent {
|
||||
// SSO JIT accepts org invites when setting their MP, meaning
|
||||
// we can clear the deep linked url for accepting it.
|
||||
await this.routerService.getAndClearLoginRedirectUrl();
|
||||
await this.acceptOrganizationInviteService.clearOrganizationInvitation();
|
||||
await this.organizationInviteService.clearOrganizationInvitation();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,34 +43,34 @@ export class ChangePasswordComponent
|
||||
characterMinimumMessage = "";
|
||||
|
||||
constructor(
|
||||
i18nService: I18nService,
|
||||
keyService: KeyService,
|
||||
messagingService: MessagingService,
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
policyService: PolicyService,
|
||||
private auditService: AuditService,
|
||||
private cipherService: CipherService,
|
||||
private syncService: SyncService,
|
||||
private keyRotationService: UserKeyRotationService,
|
||||
private masterPasswordApiService: MasterPasswordApiService,
|
||||
private router: Router,
|
||||
dialogService: DialogService,
|
||||
private syncService: SyncService,
|
||||
private userVerificationService: UserVerificationService,
|
||||
private keyRotationService: UserKeyRotationService,
|
||||
kdfConfigService: KdfConfigService,
|
||||
protected accountService: AccountService,
|
||||
protected dialogService: DialogService,
|
||||
protected i18nService: I18nService,
|
||||
protected kdfConfigService: KdfConfigService,
|
||||
protected keyService: KeyService,
|
||||
protected masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
||||
accountService: AccountService,
|
||||
toastService: ToastService,
|
||||
protected messagingService: MessagingService,
|
||||
protected platformUtilsService: PlatformUtilsService,
|
||||
protected policyService: PolicyService,
|
||||
protected toastService: ToastService,
|
||||
) {
|
||||
super(
|
||||
accountService,
|
||||
dialogService,
|
||||
i18nService,
|
||||
kdfConfigService,
|
||||
keyService,
|
||||
masterPasswordService,
|
||||
messagingService,
|
||||
platformUtilsService,
|
||||
policyService,
|
||||
dialogService,
|
||||
kdfConfigService,
|
||||
masterPasswordService,
|
||||
accountService,
|
||||
toastService,
|
||||
);
|
||||
}
|
||||
@@ -244,8 +244,7 @@ export class ChangePasswordComponent
|
||||
await this.masterPasswordApiService.postPassword(request);
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: this.i18nService.t("masterPasswordChanged"),
|
||||
message: this.i18nService.t("masterPasswordChangedDesc"),
|
||||
message: this.i18nService.t("masterPasswordChanged"),
|
||||
});
|
||||
this.messagingService.send("logout");
|
||||
} catch {
|
||||
|
||||
@@ -71,15 +71,15 @@ export class EmergencyAccessTakeoverComponent
|
||||
protected toastService: ToastService,
|
||||
) {
|
||||
super(
|
||||
accountService,
|
||||
dialogService,
|
||||
i18nService,
|
||||
kdfConfigService,
|
||||
keyService,
|
||||
masterPasswordService,
|
||||
messagingService,
|
||||
platformUtilsService,
|
||||
policyService,
|
||||
dialogService,
|
||||
kdfConfigService,
|
||||
masterPasswordService,
|
||||
accountService,
|
||||
toastService,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<h1 class="tw-mt-6 tw-mb-2 tw-pb-2.5">{{ "changeMasterPassword" | i18n }}</h1>
|
||||
|
||||
<div class="tw-max-w-lg tw-mb-12">
|
||||
<bit-callout type="warning">{{ "loggedOutWarning" | i18n }}</bit-callout>
|
||||
<auth-change-password [inputPasswordFlow]="inputPasswordFlow"></auth-change-password>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@ import { Component, OnInit } from "@angular/core";
|
||||
import { Router } from "@angular/router";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { ChangePasswordComponent, InputPasswordFlow } from "@bitwarden/auth/angular";
|
||||
import { ChangePasswordComponent } from "@bitwarden/angular/auth/password-management/change-password";
|
||||
import { InputPasswordFlow } from "@bitwarden/auth/angular";
|
||||
import { UserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common";
|
||||
import { CalloutModule } from "@bitwarden/components";
|
||||
import { I18nPipe } from "@bitwarden/ui-common";
|
||||
@@ -16,6 +17,7 @@ import { WebauthnLoginSettingsModule } from "../../webauthn-login-settings";
|
||||
})
|
||||
export class PasswordSettingsComponent implements OnInit {
|
||||
inputPasswordFlow = InputPasswordFlow.ChangePasswordWithOptionalUserKeyRotation;
|
||||
changePasswordFeatureFlag = false;
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { Component, inject } from "@angular/core";
|
||||
|
||||
import { UpdatePasswordComponent as BaseUpdatePasswordComponent } from "@bitwarden/angular/auth/components/update-password.component";
|
||||
import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service";
|
||||
|
||||
import { RouterService } from "../core";
|
||||
|
||||
import { AcceptOrganizationInviteService } from "./organization-invite/accept-organization.service";
|
||||
|
||||
@Component({
|
||||
selector: "app-update-password",
|
||||
templateUrl: "update-password.component.html",
|
||||
@@ -13,13 +12,13 @@ import { AcceptOrganizationInviteService } from "./organization-invite/accept-or
|
||||
})
|
||||
export class UpdatePasswordComponent extends BaseUpdatePasswordComponent {
|
||||
private routerService = inject(RouterService);
|
||||
private acceptOrganizationInviteService = inject(AcceptOrganizationInviteService);
|
||||
private organizationInviteService = inject(OrganizationInviteService);
|
||||
|
||||
override 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.organizationInviteService.clearOrganizationInvitation();
|
||||
await super.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/mod
|
||||
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service";
|
||||
import {
|
||||
OrganizationBillingServiceAbstraction as OrganizationBillingService,
|
||||
OrganizationInformation,
|
||||
@@ -31,7 +32,6 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"
|
||||
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
||||
import { ToastService } from "@bitwarden/components";
|
||||
|
||||
import { AcceptOrganizationInviteService } from "../../../auth/organization-invite/accept-organization.service";
|
||||
import {
|
||||
OrganizationCreatedEvent,
|
||||
SubscriptionProduct,
|
||||
@@ -115,7 +115,7 @@ export class CompleteTrialInitiationComponent implements OnInit, OnDestroy {
|
||||
private i18nService: I18nService,
|
||||
private routerService: RouterService,
|
||||
private organizationBillingService: OrganizationBillingService,
|
||||
private acceptOrganizationInviteService: AcceptOrganizationInviteService,
|
||||
private organizationInviteService: OrganizationInviteService,
|
||||
private toastService: ToastService,
|
||||
private registrationFinishService: RegistrationFinishService,
|
||||
private validationService: ValidationService,
|
||||
@@ -174,7 +174,7 @@ export class CompleteTrialInitiationComponent implements OnInit, OnDestroy {
|
||||
this.setupFamilySponsorship(qParams.sponsorshipToken);
|
||||
});
|
||||
|
||||
const invite = await this.acceptOrganizationInviteService.getOrganizationInvite();
|
||||
const invite = await this.organizationInviteService.getOrganizationInvite();
|
||||
let policies: Policy[] | null = null;
|
||||
|
||||
if (invite != null) {
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
OrganizationUserApiService,
|
||||
CollectionService,
|
||||
} from "@bitwarden/admin-console/common";
|
||||
import { ChangePasswordService } from "@bitwarden/angular/auth/password-management/change-password";
|
||||
import { SetInitialPasswordService } from "@bitwarden/angular/auth/password-management/set-initial-password/set-initial-password.service.abstraction";
|
||||
import { SafeProvider, safeProvider } from "@bitwarden/angular/platform/utils/safe-provider";
|
||||
import {
|
||||
@@ -34,7 +35,6 @@ import {
|
||||
SsoComponentService,
|
||||
LoginDecryptionOptionsService,
|
||||
TwoFactorAuthDuoComponentService,
|
||||
ChangePasswordService,
|
||||
} from "@bitwarden/auth/angular";
|
||||
import {
|
||||
InternalUserDecryptionOptionsServiceAbstraction,
|
||||
@@ -52,6 +52,7 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction";
|
||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||
import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service";
|
||||
import { ClientType } from "@bitwarden/common/enums";
|
||||
import { ProcessReloadServiceAbstraction } from "@bitwarden/common/key-management/abstractions/process-reload.service";
|
||||
import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service";
|
||||
@@ -108,6 +109,7 @@ import {
|
||||
} from "@bitwarden/key-management";
|
||||
import { LockComponentService } from "@bitwarden/key-management-ui";
|
||||
import { DefaultSshImportPromptService, SshImportPromptService } from "@bitwarden/vault";
|
||||
import { WebOrganizationInviteService } from "@bitwarden/web-vault/app/auth/core/services/organization-invite/web-organization-invite.service";
|
||||
|
||||
import { flagEnabled } from "../../utils/flags";
|
||||
import { PolicyListService } from "../admin-console/core/policy-list.service";
|
||||
@@ -122,7 +124,6 @@ import {
|
||||
WebSetInitialPasswordService,
|
||||
} from "../auth";
|
||||
import { WebSsoComponentService } from "../auth/core/services/login/web-sso-component.service";
|
||||
import { AcceptOrganizationInviteService } from "../auth/organization-invite/accept-organization.service";
|
||||
import { HtmlStorageService } from "../core/html-storage.service";
|
||||
import { I18nService } from "../core/i18n.service";
|
||||
import { WebFileDownloadService } from "../core/web-file-download.service";
|
||||
@@ -246,17 +247,21 @@ const safeProviders: SafeProvider[] = [
|
||||
provide: CLIENT_TYPE,
|
||||
useValue: ClientType.Web,
|
||||
}),
|
||||
safeProvider({
|
||||
provide: OrganizationInviteService,
|
||||
useClass: WebOrganizationInviteService,
|
||||
deps: [GlobalStateProvider],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: RegistrationFinishServiceAbstraction,
|
||||
useClass: WebRegistrationFinishService,
|
||||
deps: [
|
||||
KeyServiceAbstraction,
|
||||
AccountApiServiceAbstraction,
|
||||
AcceptOrganizationInviteService,
|
||||
OrganizationInviteService,
|
||||
PolicyApiServiceAbstraction,
|
||||
LogService,
|
||||
PolicyService,
|
||||
AccountService,
|
||||
ConfigService,
|
||||
],
|
||||
}),
|
||||
@@ -275,12 +280,11 @@ const safeProviders: SafeProvider[] = [
|
||||
provide: SetPasswordJitService,
|
||||
useClass: WebSetPasswordJitService,
|
||||
deps: [
|
||||
ApiService,
|
||||
MasterPasswordApiService,
|
||||
KeyServiceAbstraction,
|
||||
EncryptService,
|
||||
I18nServiceAbstraction,
|
||||
KdfConfigService,
|
||||
KeyServiceAbstraction,
|
||||
MasterPasswordApiService,
|
||||
InternalMasterPasswordServiceAbstraction,
|
||||
OrganizationApiServiceAbstraction,
|
||||
OrganizationUserApiService,
|
||||
@@ -301,7 +305,7 @@ const safeProviders: SafeProvider[] = [
|
||||
OrganizationApiServiceAbstraction,
|
||||
OrganizationUserApiService,
|
||||
InternalUserDecryptionOptionsServiceAbstraction,
|
||||
AcceptOrganizationInviteService,
|
||||
OrganizationInviteService,
|
||||
RouterService,
|
||||
],
|
||||
}),
|
||||
@@ -314,7 +318,7 @@ const safeProviders: SafeProvider[] = [
|
||||
provide: LoginComponentService,
|
||||
useClass: WebLoginComponentService,
|
||||
deps: [
|
||||
AcceptOrganizationInviteService,
|
||||
OrganizationInviteService,
|
||||
LogService,
|
||||
PolicyApiServiceAbstraction,
|
||||
InternalPolicyService,
|
||||
@@ -326,6 +330,7 @@ const safeProviders: SafeProvider[] = [
|
||||
SsoLoginServiceAbstraction,
|
||||
Router,
|
||||
AccountService,
|
||||
ConfigService,
|
||||
],
|
||||
}),
|
||||
safeProvider({
|
||||
@@ -378,7 +383,7 @@ const safeProviders: SafeProvider[] = [
|
||||
safeProvider({
|
||||
provide: LoginDecryptionOptionsService,
|
||||
useClass: WebLoginDecryptionOptionsService,
|
||||
deps: [MessagingService, RouterService, AcceptOrganizationInviteService],
|
||||
deps: [MessagingService, RouterService, OrganizationInviteService],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: IpcService,
|
||||
@@ -398,6 +403,7 @@ const safeProviders: SafeProvider[] = [
|
||||
MasterPasswordApiService,
|
||||
InternalMasterPasswordServiceAbstraction,
|
||||
UserKeyRotationService,
|
||||
RouterService,
|
||||
],
|
||||
}),
|
||||
];
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
unauthGuardFn,
|
||||
activeAuthGuard,
|
||||
} from "@bitwarden/angular/auth/guards";
|
||||
import { ChangePasswordComponent } from "@bitwarden/angular/auth/password-management/change-password";
|
||||
import { SetInitialPasswordComponent } from "@bitwarden/angular/auth/password-management/set-initial-password/set-initial-password.component";
|
||||
import { canAccessFeature } from "@bitwarden/angular/platform/guard/feature-flag.guard";
|
||||
import {
|
||||
@@ -144,13 +145,29 @@ const routes: Routes = [
|
||||
{
|
||||
path: "update-temp-password",
|
||||
component: UpdateTempPasswordComponent,
|
||||
canActivate: [authGuard],
|
||||
canActivate: [
|
||||
canAccessFeature(
|
||||
FeatureFlag.PM16117_ChangeExistingPasswordRefactor,
|
||||
false,
|
||||
"change-password",
|
||||
false,
|
||||
),
|
||||
authGuard,
|
||||
],
|
||||
data: { titleId: "updateTempPassword" } satisfies RouteDataProperties,
|
||||
},
|
||||
{
|
||||
path: "update-password",
|
||||
component: UpdatePasswordComponent,
|
||||
canActivate: [authGuard],
|
||||
canActivate: [
|
||||
canAccessFeature(
|
||||
FeatureFlag.PM16117_ChangeExistingPasswordRefactor,
|
||||
false,
|
||||
"change-password",
|
||||
false,
|
||||
),
|
||||
authGuard,
|
||||
],
|
||||
data: { titleId: "updatePassword" } satisfies RouteDataProperties,
|
||||
},
|
||||
],
|
||||
@@ -580,6 +597,14 @@ const routes: Routes = [
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "change-password",
|
||||
component: ChangePasswordComponent,
|
||||
canActivate: [
|
||||
canAccessFeature(FeatureFlag.PM16117_ChangeExistingPasswordRefactor),
|
||||
authGuard,
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "setup-extension",
|
||||
data: {
|
||||
|
||||
Reference in New Issue
Block a user