mirror of
https://github.com/bitwarden/browser
synced 2025-12-15 15:53:27 +00:00
Merge branch 'master' into feature/org-admin-refresh
This commit is contained in:
@@ -14,7 +14,8 @@
|
||||
"**/organizations/policies/*",
|
||||
"@bitwarden/web-vault/*",
|
||||
"src/**/*"
|
||||
]
|
||||
],
|
||||
"paths": ["@fluffy-spoon/substitute"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@bitwarden/web-vault",
|
||||
"version": "2022.9.2",
|
||||
"version": "2022.10.0",
|
||||
"scripts": {
|
||||
"build:oss": "webpack",
|
||||
"build:bit": "webpack -c ../../bitwarden_license/bit-web/webpack.config.js",
|
||||
|
||||
@@ -37,9 +37,11 @@ export class LoginWithDeviceComponent
|
||||
onSuccessfulLoginTwoFactorNavigate: () => Promise<any>;
|
||||
onSuccessfulLogin: () => Promise<any>;
|
||||
onSuccessfulLoginNavigate: () => Promise<any>;
|
||||
onSuccessfulLoginForceResetNavigate: () => Promise<any>;
|
||||
|
||||
protected twoFactorRoute = "2fa";
|
||||
protected successRoute = "vault";
|
||||
protected forcePasswordResetRoute = "update-temp-password";
|
||||
private authRequestKeyPair: [publicKey: ArrayBuffer, privateKey: ArrayBuffer];
|
||||
|
||||
constructor(
|
||||
@@ -119,14 +121,29 @@ export class LoginWithDeviceComponent
|
||||
}
|
||||
|
||||
const credentials = await this.buildLoginCredntials(requestId, response);
|
||||
await this.authService.logIn(credentials);
|
||||
if (this.onSuccessfulLogin != null) {
|
||||
this.onSuccessfulLogin();
|
||||
}
|
||||
if (this.onSuccessfulLoginNavigate != null) {
|
||||
this.onSuccessfulLoginNavigate();
|
||||
const loginResponse = await this.authService.logIn(credentials);
|
||||
|
||||
if (loginResponse.requiresTwoFactor) {
|
||||
if (this.onSuccessfulLoginTwoFactorNavigate != null) {
|
||||
this.onSuccessfulLoginTwoFactorNavigate();
|
||||
} else {
|
||||
this.router.navigate([this.twoFactorRoute]);
|
||||
}
|
||||
} else if (loginResponse.forcePasswordReset) {
|
||||
if (this.onSuccessfulLoginForceResetNavigate != null) {
|
||||
this.onSuccessfulLoginForceResetNavigate();
|
||||
} else {
|
||||
this.router.navigate([this.forcePasswordResetRoute]);
|
||||
}
|
||||
} else {
|
||||
this.router.navigate([this.successRoute]);
|
||||
if (this.onSuccessfulLogin != null) {
|
||||
this.onSuccessfulLogin();
|
||||
}
|
||||
if (this.onSuccessfulLoginNavigate != null) {
|
||||
this.onSuccessfulLoginNavigate();
|
||||
} else {
|
||||
this.router.navigate([this.successRoute]);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
this.logService.error(error);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Component, NgZone } from "@angular/core";
|
||||
import { Component, NgZone, OnDestroy, OnInit } from "@angular/core";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { Subject, takeUntil } from "rxjs";
|
||||
import { first } from "rxjs/operators";
|
||||
|
||||
import { LoginComponent as BaseLoginComponent } from "@bitwarden/angular/components/login.component";
|
||||
@@ -29,13 +30,14 @@ import { RouterService, StateService } from "../../core";
|
||||
selector: "app-login",
|
||||
templateUrl: "login.component.html",
|
||||
})
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
|
||||
export class LoginComponent extends BaseLoginComponent {
|
||||
export class LoginComponent extends BaseLoginComponent implements OnInit, OnDestroy {
|
||||
showResetPasswordAutoEnrollWarning = false;
|
||||
enforcedPasswordPolicyOptions: MasterPasswordPolicyOptions;
|
||||
policies: ListResponse<PolicyResponse>;
|
||||
showPasswordless = false;
|
||||
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
constructor(
|
||||
authService: AuthService,
|
||||
router: Router,
|
||||
@@ -128,14 +130,23 @@ export class LoginComponent extends BaseLoginComponent {
|
||||
this.showResetPasswordAutoEnrollWarning =
|
||||
resetPasswordPolicy[1] && resetPasswordPolicy[0].autoEnrollEnabled;
|
||||
|
||||
this.enforcedPasswordPolicyOptions =
|
||||
await this.policyService.getMasterPasswordPolicyOptions(policyList);
|
||||
this.policyService
|
||||
.masterPasswordPolicyOptions$(policyList)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((enforcedPasswordPolicyOptions) => {
|
||||
this.enforcedPasswordPolicyOptions = enforcedPasswordPolicyOptions;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
async goAfterLogIn() {
|
||||
const masterPassword = this.formGroup.get("masterPassword")?.value;
|
||||
const masterPassword = this.formGroup.value.masterPassword;
|
||||
|
||||
// Check master password against policy
|
||||
if (this.enforcedPasswordPolicyOptions != null) {
|
||||
@@ -170,7 +181,7 @@ export class LoginComponent extends BaseLoginComponent {
|
||||
}
|
||||
|
||||
async submit() {
|
||||
const rememberEmail = this.formGroup.get("rememberEmail")?.value;
|
||||
const rememberEmail = this.formGroup.value.rememberEmail;
|
||||
|
||||
await this.stateService.setRememberEmail(rememberEmail);
|
||||
if (!rememberEmail) {
|
||||
@@ -192,7 +203,7 @@ export class LoginComponent extends BaseLoginComponent {
|
||||
}
|
||||
|
||||
private getPasswordStrengthUserInput() {
|
||||
const email = this.formGroup.get("email")?.value;
|
||||
const email = this.formGroup.value.email;
|
||||
let userInput: string[] = [];
|
||||
const atPosition = email.indexOf("@");
|
||||
if (atPosition > -1) {
|
||||
|
||||
@@ -73,7 +73,7 @@ export class RegisterFormComponent extends BaseRegisterComponent {
|
||||
this.enforcedPolicyOptions != null &&
|
||||
!this.policyService.evaluateMasterPassword(
|
||||
this.passwordStrengthResult.score,
|
||||
this.formGroup.get("masterPassword")?.value,
|
||||
this.formGroup.value.masterPassword,
|
||||
this.enforcedPolicyOptions
|
||||
)
|
||||
) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||
import { UntypedFormBuilder } from "@angular/forms";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { Subject, takeUntil } from "rxjs";
|
||||
import { first } from "rxjs/operators";
|
||||
|
||||
import { RegisterComponent as BaseRegisterComponent } from "@bitwarden/angular/components/register.component";
|
||||
@@ -27,14 +28,14 @@ import { RouterService } from "../core";
|
||||
selector: "app-register",
|
||||
templateUrl: "register.component.html",
|
||||
})
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
|
||||
export class RegisterComponent extends BaseRegisterComponent {
|
||||
export class RegisterComponent extends BaseRegisterComponent implements OnInit, OnDestroy {
|
||||
email = "";
|
||||
showCreateOrgMessage = false;
|
||||
layout = "";
|
||||
enforcedPolicyOptions: MasterPasswordPolicyOptions;
|
||||
|
||||
private policies: Policy[];
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
constructor(
|
||||
formValidationErrorService: FormValidationErrorsService,
|
||||
@@ -130,11 +131,19 @@ export class RegisterComponent extends BaseRegisterComponent {
|
||||
}
|
||||
|
||||
if (this.policies != null) {
|
||||
this.enforcedPolicyOptions = await this.policyService.getMasterPasswordPolicyOptions(
|
||||
this.policies
|
||||
);
|
||||
this.policyService
|
||||
.masterPasswordPolicyOptions$(this.policies)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((enforcedPasswordPolicyOptions) => {
|
||||
this.enforcedPolicyOptions = enforcedPasswordPolicyOptions;
|
||||
});
|
||||
}
|
||||
|
||||
await super.ngOnInit();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,8 +57,8 @@ export class BillingComponent extends OrganizationPlansComponent {
|
||||
async ngOnInit() {
|
||||
const additionalSeats = this.product == ProductType.Families ? 0 : 1;
|
||||
this.formGroup.patchValue({
|
||||
name: this.orgInfoForm.get("name")?.value,
|
||||
billingEmail: this.orgInfoForm.get("email")?.value,
|
||||
name: this.orgInfoForm.value.name,
|
||||
billingEmail: this.orgInfoForm.value.email,
|
||||
additionalSeats: additionalSeats,
|
||||
plan: this.plan,
|
||||
product: this.product,
|
||||
|
||||
@@ -5,8 +5,9 @@ import { ComponentFixture, fakeAsync, TestBed, tick } from "@angular/core/testin
|
||||
import { FormBuilder, UntypedFormBuilder } from "@angular/forms";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { RouterTestingModule } from "@angular/router/testing";
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { Substitute } from "@fluffy-spoon/substitute";
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
import { BehaviorSubject, of } from "rxjs";
|
||||
|
||||
import { I18nPipe } from "@bitwarden/angular/pipes/i18n.pipe";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
@@ -46,7 +47,7 @@ describe("TrialInitiationComponent", () => {
|
||||
};
|
||||
|
||||
policyServiceMock = {
|
||||
getMasterPasswordPolicyOptions: jest.fn(),
|
||||
masterPasswordPolicyOptions$: jest.fn(),
|
||||
};
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
@@ -144,14 +145,16 @@ describe("TrialInitiationComponent", () => {
|
||||
},
|
||||
],
|
||||
});
|
||||
policyServiceMock.getMasterPasswordPolicyOptions.mockReturnValueOnce({
|
||||
minComplexity: 4,
|
||||
minLength: 10,
|
||||
requireLower: null,
|
||||
requireNumbers: null,
|
||||
requireSpecial: null,
|
||||
requireUpper: null,
|
||||
} as MasterPasswordPolicyOptions);
|
||||
policyServiceMock.masterPasswordPolicyOptions$.mockReturnValue(
|
||||
of({
|
||||
minComplexity: 4,
|
||||
minLength: 10,
|
||||
requireLower: null,
|
||||
requireNumbers: null,
|
||||
requireSpecial: null,
|
||||
requireUpper: null,
|
||||
} as MasterPasswordPolicyOptions)
|
||||
);
|
||||
|
||||
// Need to recreate component with new service mocks
|
||||
fixture = TestBed.createComponent(TrialInitiationComponent);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { StepperSelectionEvent } from "@angular/cdk/stepper";
|
||||
import { TitleCasePipe } from "@angular/common";
|
||||
import { Component, OnInit, ViewChild } from "@angular/core";
|
||||
import { Component, OnDestroy, OnInit, ViewChild } from "@angular/core";
|
||||
import { UntypedFormBuilder, Validators } from "@angular/forms";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { first } from "rxjs";
|
||||
import { first, Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||
@@ -24,8 +24,7 @@ import { VerticalStepperComponent } from "./vertical-stepper/vertical-stepper.co
|
||||
selector: "app-trial",
|
||||
templateUrl: "trial-initiation.component.html",
|
||||
})
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
|
||||
export class TrialInitiationComponent implements OnInit {
|
||||
export class TrialInitiationComponent implements OnInit, OnDestroy {
|
||||
email = "";
|
||||
org = "";
|
||||
orgInfoSubLabel = "";
|
||||
@@ -63,6 +62,8 @@ export class TrialInitiationComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
protected router: Router,
|
||||
@@ -140,12 +141,20 @@ export class TrialInitiationComponent implements OnInit {
|
||||
}
|
||||
|
||||
if (this.policies != null) {
|
||||
this.enforcedPolicyOptions = await this.policyService.getMasterPasswordPolicyOptions(
|
||||
this.policies
|
||||
);
|
||||
this.policyService
|
||||
.masterPasswordPolicyOptions$(this.policies)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((enforcedPasswordPolicyOptions) => {
|
||||
this.enforcedPolicyOptions = enforcedPasswordPolicyOptions;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
stepSelectionChange(event: StepperSelectionEvent) {
|
||||
// Set org info sub label
|
||||
if (event.selectedIndex === 1 && this.orgInfoFormGroup.controls.name.value === "") {
|
||||
|
||||
@@ -3,7 +3,6 @@ import { Directive, ViewChild, ViewContainerRef } from "@angular/core";
|
||||
import { SearchPipe } from "@bitwarden/angular/pipes/search.pipe";
|
||||
import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe";
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { ValidationService } from "@bitwarden/angular/services/validation.service";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||
@@ -11,6 +10,7 @@ import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||
import { StateService } from "@bitwarden/common/abstractions/state.service";
|
||||
import { ValidationService } from "@bitwarden/common/abstractions/validation.service";
|
||||
import { OrganizationUserStatusType } from "@bitwarden/common/enums/organizationUserStatusType";
|
||||
import { OrganizationUserType } from "@bitwarden/common/enums/organizationUserType";
|
||||
import { ProviderUserStatusType } from "@bitwarden/common/enums/providerUserStatusType";
|
||||
|
||||
@@ -1,16 +1,32 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { Injectable, OnDestroy, OnInit } from "@angular/core";
|
||||
import { Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
|
||||
import { DeviceType } from "@bitwarden/common/enums/deviceType";
|
||||
import { EventType } from "@bitwarden/common/enums/eventType";
|
||||
import { PolicyType } from "@bitwarden/common/enums/policyType";
|
||||
import { Policy } from "@bitwarden/common/models/domain/policy";
|
||||
import { EventResponse } from "@bitwarden/common/models/response/eventResponse";
|
||||
|
||||
@Injectable()
|
||||
export class EventService {
|
||||
export class EventService implements OnInit, OnDestroy {
|
||||
private destroy$ = new Subject<void>();
|
||||
private policies: Policy[];
|
||||
|
||||
constructor(private i18nService: I18nService, private policyService: PolicyService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.policyService.policies$.pipe(takeUntil(this.destroy$)).subscribe((policies) => {
|
||||
this.policies = policies;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
getDefaultDateFilters() {
|
||||
const d = new Date();
|
||||
const end = new Date(d.getFullYear(), d.getMonth(), d.getDate(), 23, 59);
|
||||
@@ -326,8 +342,7 @@ export class EventService {
|
||||
case EventType.Policy_Updated: {
|
||||
msg = this.i18nService.t("modifiedPolicyId", this.formatPolicyId(ev));
|
||||
|
||||
const policies = await this.policyService.getAll();
|
||||
const policy = policies.filter((p) => p.id === ev.policyId)[0];
|
||||
const policy = this.policies.filter((p) => p.id === ev.policyId)[0];
|
||||
let p1 = this.getShortId(ev.policyId);
|
||||
if (policy != null) {
|
||||
p1 = PolicyType[policy.type];
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { Component, OnInit, ViewChild, ViewContainerRef } from "@angular/core";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { first } from "rxjs/operators";
|
||||
import { Component, OnDestroy, OnInit, ViewChild, ViewContainerRef } from "@angular/core";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { combineLatest, concatMap, Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { SearchPipe } from "@bitwarden/angular/pipes/search.pipe";
|
||||
import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe";
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { ValidationService } from "@bitwarden/angular/services/validation.service";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||
@@ -13,11 +12,11 @@ import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization-api.service.abstraction";
|
||||
import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||
import { PolicyApiServiceAbstraction } from "@bitwarden/common/abstractions/policy/policy-api.service.abstraction";
|
||||
import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
|
||||
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||
import { StateService } from "@bitwarden/common/abstractions/state.service";
|
||||
import { SyncService } from "@bitwarden/common/abstractions/sync/sync.service.abstraction";
|
||||
import { ValidationService } from "@bitwarden/common/abstractions/validation.service";
|
||||
import { OrganizationUserStatusType } from "@bitwarden/common/enums/organizationUserStatusType";
|
||||
import { OrganizationUserType } from "@bitwarden/common/enums/organizationUserType";
|
||||
import { PolicyType } from "@bitwarden/common/enums/policyType";
|
||||
@@ -43,10 +42,9 @@ import { UserGroupsComponent } from "./user-groups.component";
|
||||
selector: "app-org-people",
|
||||
templateUrl: "people.component.html",
|
||||
})
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
|
||||
export class PeopleComponent
|
||||
extends BasePeopleComponent<OrganizationUserUserDetailsResponse>
|
||||
implements OnInit
|
||||
implements OnInit, OnDestroy
|
||||
{
|
||||
@ViewChild("addEdit", { read: ViewContainerRef, static: true }) addEditModalRef: ViewContainerRef;
|
||||
@ViewChild("groupsTemplate", { read: ViewContainerRef, static: true })
|
||||
@@ -77,6 +75,8 @@ export class PeopleComponent
|
||||
orgResetPasswordPolicyEnabled = false;
|
||||
callingUserType: OrganizationUserType = null;
|
||||
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
constructor(
|
||||
apiService: ApiService,
|
||||
private route: ActivatedRoute,
|
||||
@@ -84,10 +84,8 @@ export class PeopleComponent
|
||||
modalService: ModalService,
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
cryptoService: CryptoService,
|
||||
private router: Router,
|
||||
searchService: SearchService,
|
||||
validationService: ValidationService,
|
||||
private policyApiService: PolicyApiServiceAbstraction,
|
||||
private policyService: PolicyService,
|
||||
logService: LogService,
|
||||
searchPipe: SearchPipe,
|
||||
@@ -113,53 +111,63 @@ export class PeopleComponent
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
|
||||
this.route.parent.params.subscribe(async (params) => {
|
||||
this.organizationId = params.organizationId;
|
||||
const organization = await this.organizationService.get(this.organizationId);
|
||||
this.accessEvents = organization.useEvents;
|
||||
this.accessGroups = organization.useGroups;
|
||||
this.canResetPassword = organization.canManageUsersPassword;
|
||||
this.orgUseResetPassword = organization.useResetPassword;
|
||||
this.callingUserType = organization.type;
|
||||
this.orgHasKeys = organization.hasPublicAndPrivateKeys;
|
||||
combineLatest([this.route.params, this.route.queryParams, this.policyService.policies$])
|
||||
.pipe(
|
||||
concatMap(async ([params, qParams, policies]) => {
|
||||
this.organizationId = params.organizationId;
|
||||
const organization = await this.organizationService.get(this.organizationId);
|
||||
this.accessEvents = organization.useEvents;
|
||||
this.accessGroups = organization.useGroups;
|
||||
this.canResetPassword = organization.canManageUsersPassword;
|
||||
this.orgUseResetPassword = organization.useResetPassword;
|
||||
this.callingUserType = organization.type;
|
||||
this.orgHasKeys = organization.hasPublicAndPrivateKeys;
|
||||
|
||||
// Backfill pub/priv key if necessary
|
||||
if (this.canResetPassword && !this.orgHasKeys) {
|
||||
const orgShareKey = await this.cryptoService.getOrgKey(this.organizationId);
|
||||
const orgKeys = await this.cryptoService.makeKeyPair(orgShareKey);
|
||||
const request = new OrganizationKeysRequest(orgKeys[0], orgKeys[1].encryptedString);
|
||||
const response = await this.organizationApiService.updateKeys(this.organizationId, request);
|
||||
if (response != null) {
|
||||
this.orgHasKeys = response.publicKey != null && response.privateKey != null;
|
||||
await this.syncService.fullSync(true); // Replace oganizations with new data
|
||||
} else {
|
||||
throw new Error(this.i18nService.t("resetPasswordOrgKeysError"));
|
||||
}
|
||||
}
|
||||
|
||||
await this.load();
|
||||
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe, rxjs/no-nested-subscribe
|
||||
this.route.queryParams.pipe(first()).subscribe(async (qParams) => {
|
||||
this.searchText = qParams.search;
|
||||
if (qParams.viewEvents != null) {
|
||||
const user = this.users.filter((u) => u.id === qParams.viewEvents);
|
||||
if (user.length > 0 && user[0].status === OrganizationUserStatusType.Confirmed) {
|
||||
this.events(user[0]);
|
||||
// Backfill pub/priv key if necessary
|
||||
if (this.canResetPassword && !this.orgHasKeys) {
|
||||
const orgShareKey = await this.cryptoService.getOrgKey(this.organizationId);
|
||||
const orgKeys = await this.cryptoService.makeKeyPair(orgShareKey);
|
||||
const request = new OrganizationKeysRequest(orgKeys[0], orgKeys[1].encryptedString);
|
||||
const response = await this.organizationApiService.updateKeys(
|
||||
this.organizationId,
|
||||
request
|
||||
);
|
||||
if (response != null) {
|
||||
this.orgHasKeys = response.publicKey != null && response.privateKey != null;
|
||||
await this.syncService.fullSync(true); // Replace oganizations with new data
|
||||
} else {
|
||||
throw new Error(this.i18nService.t("resetPasswordOrgKeysError"));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const resetPasswordPolicy = policies
|
||||
.filter((policy) => policy.type === PolicyType.ResetPassword)
|
||||
.find((p) => p.organizationId === this.organizationId);
|
||||
this.orgResetPasswordPolicyEnabled = resetPasswordPolicy?.enabled;
|
||||
|
||||
await this.load();
|
||||
|
||||
this.searchText = qParams.search;
|
||||
if (qParams.viewEvents != null) {
|
||||
const user = this.users.filter((u) => u.id === qParams.viewEvents);
|
||||
if (user.length > 0 && user[0].status === OrganizationUserStatusType.Confirmed) {
|
||||
this.events(user[0]);
|
||||
}
|
||||
}
|
||||
}),
|
||||
takeUntil(this.destroy$)
|
||||
)
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
async load() {
|
||||
const resetPasswordPolicy = await this.policyApiService.getPolicyForOrganization(
|
||||
PolicyType.ResetPassword,
|
||||
this.organizationId
|
||||
);
|
||||
this.orgResetPasswordPolicyEnabled = resetPasswordPolicy?.enabled;
|
||||
super.load();
|
||||
await super.load();
|
||||
}
|
||||
|
||||
getUsers(): Promise<ListResponse<OrganizationUserUserDetailsResponse>> {
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from "@angular/core";
|
||||
import {
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
Output,
|
||||
ViewChild,
|
||||
} from "@angular/core";
|
||||
import { Subject, takeUntil } from "rxjs";
|
||||
import zxcvbn from "zxcvbn";
|
||||
|
||||
import { PasswordStrengthComponent } from "@bitwarden/angular/shared/components/password-strength/password-strength.component";
|
||||
@@ -18,7 +27,7 @@ import { OrganizationUserResetPasswordRequest } from "@bitwarden/common/models/r
|
||||
selector: "app-reset-password",
|
||||
templateUrl: "reset-password.component.html",
|
||||
})
|
||||
export class ResetPasswordComponent implements OnInit {
|
||||
export class ResetPasswordComponent implements OnInit, OnDestroy {
|
||||
@Input() name: string;
|
||||
@Input() email: string;
|
||||
@Input() id: string;
|
||||
@@ -32,6 +41,8 @@ export class ResetPasswordComponent implements OnInit {
|
||||
passwordStrengthResult: zxcvbn.ZXCVBNResult;
|
||||
formPromise: Promise<any>;
|
||||
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
constructor(
|
||||
private apiService: ApiService,
|
||||
private i18nService: I18nService,
|
||||
@@ -43,8 +54,18 @@ export class ResetPasswordComponent implements OnInit {
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
// Get Enforced Policy Options
|
||||
this.enforcedPolicyOptions = await this.policyService.getMasterPasswordPolicyOptions();
|
||||
this.policyService
|
||||
.masterPasswordPolicyOptions$()
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(
|
||||
(enforcedPasswordPolicyOptions) =>
|
||||
(this.enforcedPolicyOptions = enforcedPasswordPolicyOptions)
|
||||
);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
get loggedOutWarningName() {
|
||||
@@ -52,7 +73,7 @@ export class ResetPasswordComponent implements OnInit {
|
||||
}
|
||||
|
||||
async generatePassword() {
|
||||
const options = (await this.passwordGenerationService.getOptions())[0];
|
||||
const options = (await this.passwordGenerationService.getOptions())?.[0] ?? {};
|
||||
this.newPassword = await this.passwordGenerationService.generatePassword(options);
|
||||
this.passwordStrengthComponent.updatePasswordStrength(this.newPassword);
|
||||
}
|
||||
|
||||
@@ -4,12 +4,12 @@ import { Observable, Subject } from "rxjs";
|
||||
import { first, map, takeUntil } from "rxjs/operators";
|
||||
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { ValidationService } from "@bitwarden/angular/services/validation.service";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||
import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||
import { SyncService } from "@bitwarden/common/abstractions/sync/sync.service.abstraction";
|
||||
import { ValidationService } from "@bitwarden/common/abstractions/validation.service";
|
||||
import { PlanSponsorshipType } from "@bitwarden/common/enums/planSponsorshipType";
|
||||
import { PlanType } from "@bitwarden/common/enums/planType";
|
||||
import { ProductType } from "@bitwarden/common/enums/productType";
|
||||
|
||||
@@ -47,7 +47,6 @@ export class OrganizationImportComponent extends ImportComponent {
|
||||
this.organizationId = params.organizationId;
|
||||
this.successNavigate = ["organizations", this.organizationId, "vault"];
|
||||
await super.ngOnInit();
|
||||
this.importBlockedByPolicy = false;
|
||||
});
|
||||
const organization = await this.organizationService.get(this.organizationId);
|
||||
this.organizationName = organization.name;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core";
|
||||
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from "@angular/core";
|
||||
import { takeUntil } from "rxjs";
|
||||
|
||||
import { ChangePasswordComponent } from "@bitwarden/angular/components/change-password.component";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
@@ -21,7 +22,11 @@ import { PolicyResponse } from "@bitwarden/common/models/response/policyResponse
|
||||
selector: "emergency-access-takeover",
|
||||
templateUrl: "emergency-access-takeover.component.html",
|
||||
})
|
||||
export class EmergencyAccessTakeoverComponent extends ChangePasswordComponent implements OnInit {
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
|
||||
export class EmergencyAccessTakeoverComponent
|
||||
extends ChangePasswordComponent
|
||||
implements OnInit, OnDestroy
|
||||
{
|
||||
@Output() onDone = new EventEmitter();
|
||||
@Input() emergencyAccessId: string;
|
||||
@Input() name: string;
|
||||
@@ -59,12 +64,19 @@ export class EmergencyAccessTakeoverComponent extends ChangePasswordComponent im
|
||||
const policies = response.data.map(
|
||||
(policyResponse: PolicyResponse) => new Policy(new PolicyData(policyResponse))
|
||||
);
|
||||
this.enforcedPolicyOptions = await this.policyService.getMasterPasswordPolicyOptions(
|
||||
policies
|
||||
);
|
||||
|
||||
this.policyService
|
||||
.masterPasswordPolicyOptions$(policies)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((enforcedPolicyOptions) => (this.enforcedPolicyOptions = enforcedPolicyOptions));
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
|
||||
ngOnDestroy(): void {
|
||||
super.ngOnDestroy();
|
||||
}
|
||||
|
||||
async submit() {
|
||||
if (!(await this.strongPassword())) {
|
||||
return;
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from "@angular/core";
|
||||
import {
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
Output,
|
||||
ViewChild,
|
||||
} from "@angular/core";
|
||||
import { UntypedFormBuilder, Validators } from "@angular/forms";
|
||||
import { Router } from "@angular/router";
|
||||
import { Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
||||
@@ -35,7 +44,7 @@ interface OnSuccessArgs {
|
||||
selector: "app-organization-plans",
|
||||
templateUrl: "organization-plans.component.html",
|
||||
})
|
||||
export class OrganizationPlansComponent implements OnInit {
|
||||
export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
@ViewChild(PaymentComponent) paymentComponent: PaymentComponent;
|
||||
@ViewChild(TaxInfoComponent) taxComponent: TaxInfoComponent;
|
||||
|
||||
@@ -73,6 +82,8 @@ export class OrganizationPlansComponent implements OnInit {
|
||||
|
||||
plans: PlanResponse[];
|
||||
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
constructor(
|
||||
private apiService: ApiService,
|
||||
private i18nService: I18nService,
|
||||
@@ -114,9 +125,21 @@ export class OrganizationPlansComponent implements OnInit {
|
||||
this.formGroup.controls.billingEmail.addValidators(Validators.required);
|
||||
}
|
||||
|
||||
this.policyService
|
||||
.policyAppliesToActiveUser$(PolicyType.SingleOrg)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((policyAppliesToActiveUser) => {
|
||||
this.singleOrgPolicyBlock = policyAppliesToActiveUser;
|
||||
});
|
||||
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
get createOrganization() {
|
||||
return this.organizationId == null;
|
||||
}
|
||||
@@ -288,8 +311,6 @@ export class OrganizationPlansComponent implements OnInit {
|
||||
}
|
||||
|
||||
async submit() {
|
||||
this.singleOrgPolicyBlock = await this.userHasBlockingSingleOrgPolicy();
|
||||
|
||||
if (this.singleOrgPolicyBlock) {
|
||||
return;
|
||||
}
|
||||
@@ -353,10 +374,6 @@ export class OrganizationPlansComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
private async userHasBlockingSingleOrgPolicy() {
|
||||
return this.policyService.policyAppliesToUser(PolicyType.SingleOrg);
|
||||
}
|
||||
|
||||
private async updateOrganization(orgId: string) {
|
||||
const request = new OrganizationUpgradeRequest();
|
||||
request.businessName = this.formGroup.controls.businessOwned.value
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Component, OnInit, Type, ViewChild, ViewContainerRef } from "@angular/core";
|
||||
import { Component, OnDestroy, OnInit, Type, ViewChild, ViewContainerRef } from "@angular/core";
|
||||
import { Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { ModalRef } from "@bitwarden/angular/components/modal/modal.ref";
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
@@ -25,8 +26,7 @@ import { TwoFactorYubiKeyComponent } from "./two-factor-yubikey.component";
|
||||
selector: "app-two-factor-setup",
|
||||
templateUrl: "two-factor-setup.component.html",
|
||||
})
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
|
||||
export class TwoFactorSetupComponent implements OnInit {
|
||||
export class TwoFactorSetupComponent implements OnInit, OnDestroy {
|
||||
@ViewChild("recoveryTemplate", { read: ViewContainerRef, static: true })
|
||||
recoveryModalRef: ViewContainerRef;
|
||||
@ViewChild("authenticatorTemplate", { read: ViewContainerRef, static: true })
|
||||
@@ -49,6 +49,9 @@ export class TwoFactorSetupComponent implements OnInit {
|
||||
modal: ModalRef;
|
||||
formPromise: Promise<any>;
|
||||
|
||||
private destroy$ = new Subject<void>();
|
||||
private twoFactorAuthPolicyAppliesToActiveUser: boolean;
|
||||
|
||||
constructor(
|
||||
protected apiService: ApiService,
|
||||
protected modalService: ModalService,
|
||||
@@ -93,9 +96,22 @@ export class TwoFactorSetupComponent implements OnInit {
|
||||
}
|
||||
|
||||
this.providers.sort((a: any, b: any) => a.sort - b.sort);
|
||||
|
||||
this.policyService
|
||||
.policyAppliesToActiveUser$(PolicyType.TwoFactorAuthentication)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((policyAppliesToActiveUser) => {
|
||||
this.twoFactorAuthPolicyAppliesToActiveUser = policyAppliesToActiveUser;
|
||||
});
|
||||
|
||||
await this.load();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
async load() {
|
||||
this.loading = true;
|
||||
const providerList = await this.getTwoFactorProviders();
|
||||
@@ -203,9 +219,7 @@ export class TwoFactorSetupComponent implements OnInit {
|
||||
|
||||
private async evaluatePolicies() {
|
||||
if (this.organizationId == null && this.providers.filter((p) => p.enabled).length === 1) {
|
||||
this.showPolicyWarning = await this.policyService.policyAppliesToUser(
|
||||
PolicyType.TwoFactorAuthentication
|
||||
);
|
||||
this.showPolicyWarning = this.twoFactorAuthPolicyAppliesToActiveUser;
|
||||
} else {
|
||||
this.showPolicyWarning = false;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
CalloutModule,
|
||||
FormFieldModule,
|
||||
IconModule,
|
||||
AsyncActionsModule,
|
||||
MenuModule,
|
||||
TableModule,
|
||||
TabsModule,
|
||||
@@ -51,6 +52,7 @@ import "./locales";
|
||||
],
|
||||
exports: [
|
||||
CommonModule,
|
||||
AsyncActionsModule,
|
||||
DragDropModule,
|
||||
FormsModule,
|
||||
InfiniteScrollModule,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div class="page-header">
|
||||
<h1>{{ "importData" | i18n }}</h1>
|
||||
</div>
|
||||
<app-callout type="info" *ngIf="importBlockedByPolicy">
|
||||
<app-callout type="info" *ngIf="importBlockedByPolicy$ | async">
|
||||
{{ "personalOwnershipPolicyInEffectImports" | i18n }}
|
||||
</app-callout>
|
||||
<form #form (ngSubmit)="submit()" ngNativeValidate>
|
||||
@@ -14,7 +14,7 @@
|
||||
name="Format"
|
||||
[(ngModel)]="format"
|
||||
class="form-control"
|
||||
[disabled]="importBlockedByPolicy"
|
||||
[disabled]="importBlockedByPolicy$ | async"
|
||||
required
|
||||
>
|
||||
<option *ngFor="let o of featuredImportOptions" [ngValue]="o.id">{{ o.name }}</option>
|
||||
@@ -296,7 +296,7 @@
|
||||
id="file"
|
||||
class="form-control-file"
|
||||
name="file"
|
||||
[disabled]="importBlockedByPolicy"
|
||||
[disabled]="importBlockedByPolicy$ | async"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -308,14 +308,14 @@
|
||||
class="form-control"
|
||||
name="FileContents"
|
||||
[(ngModel)]="fileContents"
|
||||
[disabled]="importBlockedByPolicy"
|
||||
[disabled]="importBlockedByPolicy$ | async"
|
||||
></textarea>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary btn-submit"
|
||||
[disabled]="loading || importBlockedByPolicy"
|
||||
[ngClass]="{ manual: importBlockedByPolicy }"
|
||||
[disabled]="loading || importBlockedByPolicy$ | async"
|
||||
[ngClass]="{ manual: importBlockedByPolicy$ | async }"
|
||||
>
|
||||
<i class="bwi bwi-spinner bwi-spin" title="{{ 'loading' | i18n }}" aria-hidden="true"></i>
|
||||
<span>{{ "importData" | i18n }}</span>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||
import { Router } from "@angular/router";
|
||||
import * as JSZip from "jszip";
|
||||
import { firstValueFrom, Subject } from "rxjs";
|
||||
import Swal, { SweetAlertIcon } from "sweetalert2";
|
||||
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
@@ -19,18 +20,22 @@ import { FilePasswordPromptComponent } from "./file-password-prompt.component";
|
||||
selector: "app-import",
|
||||
templateUrl: "import.component.html",
|
||||
})
|
||||
export class ImportComponent implements OnInit {
|
||||
export class ImportComponent implements OnInit, OnDestroy {
|
||||
featuredImportOptions: ImportOption[];
|
||||
importOptions: ImportOption[];
|
||||
format: ImportType = null;
|
||||
fileContents: string;
|
||||
formPromise: Promise<ImportError>;
|
||||
loading = false;
|
||||
importBlockedByPolicy = false;
|
||||
importBlockedByPolicy$ = this.policyService.policyAppliesToActiveUser$(
|
||||
PolicyType.PersonalOwnership
|
||||
);
|
||||
|
||||
protected organizationId: string = null;
|
||||
protected successNavigate: any[] = ["vault"];
|
||||
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
constructor(
|
||||
protected i18nService: I18nService,
|
||||
protected importService: ImportService,
|
||||
@@ -43,14 +48,15 @@ export class ImportComponent implements OnInit {
|
||||
|
||||
async ngOnInit() {
|
||||
this.setImportOptions();
|
||||
}
|
||||
|
||||
this.importBlockedByPolicy = await this.policyService.policyAppliesToUser(
|
||||
PolicyType.PersonalOwnership
|
||||
);
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
async submit() {
|
||||
if (this.importBlockedByPolicy) {
|
||||
if (await firstValueFrom(this.importBlockedByPolicy$)) {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
null,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||
|
||||
import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/components/add-edit.component";
|
||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
||||
@@ -24,7 +24,7 @@ import { LoginUriView } from "@bitwarden/common/models/view/loginUriView";
|
||||
selector: "app-vault-add-edit",
|
||||
templateUrl: "add-edit.component.html",
|
||||
})
|
||||
export class AddEditComponent extends BaseAddEditComponent {
|
||||
export class AddEditComponent extends BaseAddEditComponent implements OnInit, OnDestroy {
|
||||
canAccessPremium: boolean;
|
||||
totpCode: string;
|
||||
totpCodeFormatted: string;
|
||||
@@ -95,6 +95,10 @@ export class AddEditComponent extends BaseAddEditComponent {
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
super.ngOnDestroy();
|
||||
}
|
||||
|
||||
toggleFavorite() {
|
||||
this.cipher.favorite = !this.cipher.favorite;
|
||||
}
|
||||
@@ -133,7 +137,7 @@ export class AddEditComponent extends BaseAddEditComponent {
|
||||
async generatePassword(): Promise<boolean> {
|
||||
const confirmed = await super.generatePassword();
|
||||
if (confirmed) {
|
||||
const options = (await this.passwordGenerationService.getOptions())[0];
|
||||
const options = (await this.passwordGenerationService.getOptions())?.[0] ?? {};
|
||||
this.cipher.login.password = await this.passwordGenerationService.generatePassword(options);
|
||||
}
|
||||
return confirmed;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Component, Inject } from "@angular/core";
|
||||
import { Component, Inject, OnDestroy, OnInit } from "@angular/core";
|
||||
import { map, Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
@@ -21,11 +22,13 @@ import { OrganizationFilter } from "../shared/models/vault-filter.type";
|
||||
selector: "app-organization-options",
|
||||
templateUrl: "organization-options.component.html",
|
||||
})
|
||||
export class OrganizationOptionsComponent {
|
||||
export class OrganizationOptionsComponent implements OnInit, OnDestroy {
|
||||
actionPromise: Promise<void | boolean>;
|
||||
policies: Policy[];
|
||||
loaded = false;
|
||||
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
constructor(
|
||||
@Inject(OptionsInput) private organization: OrganizationFilter,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
@@ -39,12 +42,20 @@ export class OrganizationOptionsComponent {
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
await this.load();
|
||||
this.policyService.policies$
|
||||
.pipe(
|
||||
map((policies) => policies.filter((policy) => policy.type === PolicyType.ResetPassword)),
|
||||
takeUntil(this.destroy$)
|
||||
)
|
||||
.subscribe((policies) => {
|
||||
this.policies = policies;
|
||||
this.loaded = true;
|
||||
});
|
||||
}
|
||||
|
||||
async load() {
|
||||
this.policies = await this.policyService.getAll(PolicyType.ResetPassword);
|
||||
this.loaded = true;
|
||||
ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
allowEnrollmentChanges(org: Organization): boolean {
|
||||
@@ -84,7 +95,6 @@ export class OrganizationOptionsComponent {
|
||||
});
|
||||
await this.actionPromise;
|
||||
this.platformUtilsService.showToast("success", null, "Unlinked SSO");
|
||||
await this.load();
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
@@ -106,7 +116,6 @@ export class OrganizationOptionsComponent {
|
||||
this.actionPromise = this.organizationApiService.leave(org.id);
|
||||
await this.actionPromise;
|
||||
this.platformUtilsService.showToast("success", null, this.i18nService.t("leftOrganization"));
|
||||
await this.load();
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
|
||||
@@ -5454,6 +5454,18 @@
|
||||
"numberOfUsers": {
|
||||
"message": "Number of users"
|
||||
},
|
||||
"multiSelectPlaceholder": {
|
||||
"message": "-- Type to Filter --"
|
||||
},
|
||||
"multiSelectLoading": {
|
||||
"message": "Retrieving options..."
|
||||
},
|
||||
"multiSelectNotFound": {
|
||||
"message": "No items found"
|
||||
},
|
||||
"multiSelectClearAll": {
|
||||
"message": "Clear all"
|
||||
},
|
||||
"from": {
|
||||
"message": "From"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user