mirror of
https://github.com/bitwarden/browser.git
synced 2024-09-30 04:28:19 +02:00
Refactor orgnaization policy management (#1147)
This commit is contained in:
parent
8a259516df
commit
2cbe023a38
@ -20,10 +20,10 @@ import { ProviderUserType } from 'jslib-common/enums/providerUserType';
|
|||||||
|
|
||||||
import { ValidationService } from 'jslib-angular/services/validation.service';
|
import { ValidationService } from 'jslib-angular/services/validation.service';
|
||||||
|
|
||||||
|
import { Organization } from 'jslib-common/models/domain/organization';
|
||||||
import {
|
import {
|
||||||
ProviderOrganizationOrganizationDetailsResponse
|
ProviderOrganizationOrganizationDetailsResponse
|
||||||
} from 'jslib-common/models/response/provider/providerOrganizationResponse';
|
} from 'jslib-common/models/response/provider/providerOrganizationResponse';
|
||||||
import { Organization } from 'jslib-common/models/domain/organization';
|
|
||||||
|
|
||||||
import { ModalComponent } from 'src/app/modal.component';
|
import { ModalComponent } from 'src/app/modal.component';
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ export class ClientsComponent implements OnInit {
|
|||||||
.map(o => o.id));
|
.map(o => o.id));
|
||||||
this.addableOrganizations = candidateOrgs.filter(o => allowedOrgsIds.includes(o.id));
|
this.addableOrganizations = candidateOrgs.filter(o => allowedOrgsIds.includes(o.id));
|
||||||
|
|
||||||
this.showAddExisting = this.addableOrganizations.length != 0;
|
this.showAddExisting = this.addableOrganizations.length !== 0;
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ export class SetupComponent implements OnInit {
|
|||||||
|
|
||||||
this.providerId = qParams.providerId;
|
this.providerId = qParams.providerId;
|
||||||
this.token = qParams.token;
|
this.token = qParams.token;
|
||||||
|
|
||||||
// Check if provider exists, redirect if it does
|
// Check if provider exists, redirect if it does
|
||||||
try {
|
try {
|
||||||
const provider = await this.apiService.getProvider(this.providerId);
|
const provider = await this.apiService.getProvider(this.providerId);
|
||||||
|
2
jslib
2
jslib
@ -1 +1 @@
|
|||||||
Subproject commit 1f0127966e85aa29f9e50144de9b2a03b00de5d4
|
Subproject commit add4b2f3e9d85a4a68d67a0da09be14cefe9a6b3
|
@ -46,8 +46,19 @@ import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.serv
|
|||||||
|
|
||||||
import { ConstantsService } from 'jslib-common/services/constants.service';
|
import { ConstantsService } from 'jslib-common/services/constants.service';
|
||||||
|
|
||||||
|
import { PolicyListService } from './services/policy-list.service';
|
||||||
import { RouterService } from './services/router.service';
|
import { RouterService } from './services/router.service';
|
||||||
|
|
||||||
|
import { DisableSendPolicy } from './organizations/policies/disable-send.component';
|
||||||
|
import { MasterPasswordPolicy } from './organizations/policies/master-password.component';
|
||||||
|
import { PasswordGeneratorPolicy } from './organizations/policies/password-generator.component';
|
||||||
|
import { PersonalOwnershipPolicy } from './organizations/policies/personal-ownership.component';
|
||||||
|
import { RequireSsoPolicy } from './organizations/policies/require-sso.component';
|
||||||
|
import { ResetPasswordPolicy } from './organizations/policies/reset-password.component';
|
||||||
|
import { SendOptionsPolicy } from './organizations/policies/send-options.component';
|
||||||
|
import { SingleOrgPolicy } from './organizations/policies/single-org.component';
|
||||||
|
import { TwoFactorAuthenticationPolicy } from './organizations/policies/two-factor-authentication.component';
|
||||||
|
|
||||||
const BroadcasterSubscriptionId = 'AppComponent';
|
const BroadcasterSubscriptionId = 'AppComponent';
|
||||||
const IdleTimeout = 60000 * 10; // 10 minutes
|
const IdleTimeout = 60000 * 10; // 10 minutes
|
||||||
|
|
||||||
@ -56,6 +67,7 @@ const IdleTimeout = 60000 * 10; // 10 minutes
|
|||||||
templateUrl: 'app.component.html',
|
templateUrl: 'app.component.html',
|
||||||
})
|
})
|
||||||
export class AppComponent implements OnDestroy, OnInit {
|
export class AppComponent implements OnDestroy, OnInit {
|
||||||
|
|
||||||
toasterConfig: ToasterConfig = new ToasterConfig({
|
toasterConfig: ToasterConfig = new ToasterConfig({
|
||||||
showCloseButton: true,
|
showCloseButton: true,
|
||||||
mouseoverTimerStop: true,
|
mouseoverTimerStop: true,
|
||||||
@ -80,7 +92,7 @@ export class AppComponent implements OnDestroy, OnInit {
|
|||||||
private sanitizer: DomSanitizer, private searchService: SearchService,
|
private sanitizer: DomSanitizer, private searchService: SearchService,
|
||||||
private notificationsService: NotificationsService, private routerService: RouterService,
|
private notificationsService: NotificationsService, private routerService: RouterService,
|
||||||
private stateService: StateService, private eventService: EventService,
|
private stateService: StateService, private eventService: EventService,
|
||||||
private policyService: PolicyService) { }
|
private policyService: PolicyService, protected policyListService: PolicyListService) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.ngZone.runOutsideAngular(() => {
|
this.ngZone.runOutsideAngular(() => {
|
||||||
@ -170,6 +182,18 @@ export class AppComponent implements OnDestroy, OnInit {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.policyListService.addPolicies([
|
||||||
|
new TwoFactorAuthenticationPolicy(),
|
||||||
|
new MasterPasswordPolicy(),
|
||||||
|
new PasswordGeneratorPolicy(),
|
||||||
|
new SingleOrgPolicy(),
|
||||||
|
new RequireSsoPolicy(),
|
||||||
|
new PersonalOwnershipPolicy(),
|
||||||
|
new DisableSendPolicy(),
|
||||||
|
new SendOptionsPolicy(),
|
||||||
|
new ResetPasswordPolicy(),
|
||||||
|
]);
|
||||||
|
|
||||||
this.setFullWidth();
|
this.setFullWidth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,3 @@
|
|||||||
<app-callout *ngIf="userCanAccessBusinessPortal" [type]="'warning'">
|
|
||||||
<p>{{'webPoliciesDeprecationWarning' | i18n}}</p>
|
|
||||||
<button type="button" class="btn btn-outline-secondary"
|
|
||||||
(click)="goToEnterprisePortal()">{{'businessPortal' | i18n}}</button>
|
|
||||||
</app-callout>
|
|
||||||
<div class="page-header d-flex">
|
<div class="page-header d-flex">
|
||||||
<h1>{{'policies' | i18n}}</h1>
|
<h1>{{'policies' | i18n}}</h1>
|
||||||
</div>
|
</div>
|
||||||
@ -13,10 +8,10 @@
|
|||||||
<table class="table table-hover table-list" *ngIf="!loading">
|
<table class="table table-hover table-list" *ngIf="!loading">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr *ngFor="let p of policies">
|
<tr *ngFor="let p of policies">
|
||||||
<td *ngIf="p.display">
|
<td *ngIf="p.display(organization)">
|
||||||
<a href="#" appStopClick (click)="edit(p)">{{p.name}}</a>
|
<a href="#" appStopClick (click)="edit(p)">{{p.name | i18n}}</a>
|
||||||
<span class="badge badge-success" *ngIf="p.enabled">{{'enabled' | i18n}}</span>
|
<span class="badge badge-success" *ngIf="policiesEnabledMap.get(p.type)">{{'enabled' | i18n}}</span>
|
||||||
<small class="text-muted d-block">{{p.description}}</small>
|
<small class="text-muted d-block">{{p.description | i18n}}</small>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -12,8 +12,8 @@ import {
|
|||||||
|
|
||||||
import { PolicyType } from 'jslib-common/enums/policyType';
|
import { PolicyType } from 'jslib-common/enums/policyType';
|
||||||
|
|
||||||
import { EnvironmentService } from 'jslib-common/abstractions';
|
|
||||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
import { ApiService } from 'jslib-common/abstractions/api.service';
|
||||||
|
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
||||||
import { UserService } from 'jslib-common/abstractions/user.service';
|
import { UserService } from 'jslib-common/abstractions/user.service';
|
||||||
@ -22,8 +22,13 @@ import { PolicyResponse } from 'jslib-common/models/response/policyResponse';
|
|||||||
|
|
||||||
import { ModalComponent } from '../../modal.component';
|
import { ModalComponent } from '../../modal.component';
|
||||||
|
|
||||||
|
import { Organization } from 'jslib-common/models/domain/organization';
|
||||||
|
|
||||||
import { PolicyEditComponent } from './policy-edit.component';
|
import { PolicyEditComponent } from './policy-edit.component';
|
||||||
|
|
||||||
|
import { PolicyListService } from 'src/app/services/policy-list.service';
|
||||||
|
import { BasePolicy } from '../policies/base-policy.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-org-policies',
|
selector: 'app-org-policies',
|
||||||
templateUrl: 'policies.component.html',
|
templateUrl: 'policies.component.html',
|
||||||
@ -33,11 +38,11 @@ export class PoliciesComponent implements OnInit {
|
|||||||
|
|
||||||
loading = true;
|
loading = true;
|
||||||
organizationId: string;
|
organizationId: string;
|
||||||
policies: any[];
|
policies: BasePolicy[];
|
||||||
|
organization: Organization;
|
||||||
|
|
||||||
// Remove when removing deprecation warning
|
// Remove when removing deprecation warning
|
||||||
enterpriseTokenPromise: Promise<any>;
|
enterpriseTokenPromise: Promise<any>;
|
||||||
userCanAccessBusinessPortal = false;
|
|
||||||
|
|
||||||
private enterpriseUrl: string;
|
private enterpriseUrl: string;
|
||||||
|
|
||||||
@ -48,81 +53,20 @@ export class PoliciesComponent implements OnInit {
|
|||||||
constructor(private apiService: ApiService, private route: ActivatedRoute,
|
constructor(private apiService: ApiService, private route: ActivatedRoute,
|
||||||
private i18nService: I18nService, private componentFactoryResolver: ComponentFactoryResolver,
|
private i18nService: I18nService, private componentFactoryResolver: ComponentFactoryResolver,
|
||||||
private platformUtilsService: PlatformUtilsService, private userService: UserService,
|
private platformUtilsService: PlatformUtilsService, private userService: UserService,
|
||||||
private router: Router, private environmentService: EnvironmentService) { }
|
private policyListService: PolicyListService, private router: Router,
|
||||||
|
private environmentService: EnvironmentService) { }
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
this.route.parent.parent.params.subscribe(async params => {
|
this.route.parent.parent.params.subscribe(async params => {
|
||||||
this.organizationId = params.organizationId;
|
this.organizationId = params.organizationId;
|
||||||
const organization = await this.userService.getOrganization(this.organizationId);
|
this.organization = await this.userService.getOrganization(this.organizationId);
|
||||||
if (organization == null || !organization.usePolicies) {
|
if (this.organization == null || !this.organization.usePolicies) {
|
||||||
this.router.navigate(['/organizations', this.organizationId]);
|
this.router.navigate(['/organizations', this.organizationId]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.userCanAccessBusinessPortal = organization.canAccessBusinessPortal;
|
|
||||||
this.policies = [
|
this.policies = this.policyListService.getPolicies();
|
||||||
{
|
|
||||||
name: this.i18nService.t('twoStepLogin'),
|
|
||||||
description: this.i18nService.t('twoStepLoginPolicyDesc'),
|
|
||||||
type: PolicyType.TwoFactorAuthentication,
|
|
||||||
enabled: false,
|
|
||||||
display: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: this.i18nService.t('masterPass'),
|
|
||||||
description: this.i18nService.t('masterPassPolicyDesc'),
|
|
||||||
type: PolicyType.MasterPassword,
|
|
||||||
enabled: false,
|
|
||||||
display: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: this.i18nService.t('passwordGenerator'),
|
|
||||||
description: this.i18nService.t('passwordGeneratorPolicyDesc'),
|
|
||||||
type: PolicyType.PasswordGenerator,
|
|
||||||
enabled: false,
|
|
||||||
display: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: this.i18nService.t('singleOrg'),
|
|
||||||
description: this.i18nService.t('singleOrgDesc'),
|
|
||||||
type: PolicyType.SingleOrg,
|
|
||||||
enabled: false,
|
|
||||||
display: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: this.i18nService.t('requireSso'),
|
|
||||||
description: this.i18nService.t('requireSsoPolicyDesc'),
|
|
||||||
type: PolicyType.RequireSso,
|
|
||||||
enabled: false,
|
|
||||||
display: organization.useSso,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: this.i18nService.t('personalOwnership'),
|
|
||||||
description: this.i18nService.t('personalOwnershipPolicyDesc'),
|
|
||||||
type: PolicyType.PersonalOwnership,
|
|
||||||
enabled: false,
|
|
||||||
display: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: this.i18nService.t('disableSend'),
|
|
||||||
description: this.i18nService.t('disableSendPolicyDesc'),
|
|
||||||
type: PolicyType.DisableSend,
|
|
||||||
enabled: false,
|
|
||||||
display: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: this.i18nService.t('sendOptions'),
|
|
||||||
description: this.i18nService.t('sendOptionsPolicyDesc'),
|
|
||||||
type: PolicyType.SendOptions,
|
|
||||||
enabled: false,
|
|
||||||
display: true,
|
|
||||||
}, {
|
|
||||||
name: this.i18nService.t('resetPasswordPolicy'),
|
|
||||||
description: this.i18nService.t('resetPasswordPolicyDescription'),
|
|
||||||
type: PolicyType.ResetPassword,
|
|
||||||
enabled: false,
|
|
||||||
display: organization.useResetPassword,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
await this.load();
|
await this.load();
|
||||||
|
|
||||||
// Handle policies component launch from Event message
|
// Handle policies component launch from Event message
|
||||||
@ -158,13 +102,11 @@ export class PoliciesComponent implements OnInit {
|
|||||||
this.orgPolicies.forEach(op => {
|
this.orgPolicies.forEach(op => {
|
||||||
this.policiesEnabledMap.set(op.type, op.enabled);
|
this.policiesEnabledMap.set(op.type, op.enabled);
|
||||||
});
|
});
|
||||||
this.policies.forEach(p => {
|
|
||||||
p.enabled = this.policiesEnabledMap.has(p.type) && this.policiesEnabledMap.get(p.type);
|
|
||||||
});
|
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
edit(p: any) {
|
edit(policy: BasePolicy) {
|
||||||
if (this.modal != null) {
|
if (this.modal != null) {
|
||||||
this.modal.close();
|
this.modal.close();
|
||||||
}
|
}
|
||||||
@ -174,9 +116,7 @@ export class PoliciesComponent implements OnInit {
|
|||||||
const childComponent = this.modal.show<PolicyEditComponent>(
|
const childComponent = this.modal.show<PolicyEditComponent>(
|
||||||
PolicyEditComponent, this.editModalRef);
|
PolicyEditComponent, this.editModalRef);
|
||||||
|
|
||||||
childComponent.name = p.name;
|
childComponent.policy = policy;
|
||||||
childComponent.description = p.description;
|
|
||||||
childComponent.type = p.type;
|
|
||||||
childComponent.organizationId = this.organizationId;
|
childComponent.organizationId = this.organizationId;
|
||||||
childComponent.policiesEnabledMap = this.policiesEnabledMap;
|
childComponent.policiesEnabledMap = this.policiesEnabledMap;
|
||||||
childComponent.onSavedPolicy.subscribe(() => {
|
childComponent.onSavedPolicy.subscribe(() => {
|
||||||
|
@ -2,178 +2,21 @@
|
|||||||
<div class="modal-dialog modal-dialog-scrollable" role="document">
|
<div class="modal-dialog modal-dialog-scrollable" role="document">
|
||||||
<form class="modal-content" #form (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate>
|
<form class="modal-content" #form (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate>
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h2 class="modal-title" id="policiesEditTitle">{{'editPolicy' | i18n}} - {{name}}</h2>
|
<h2 class="modal-title" id="policiesEditTitle">{{'editPolicy' | i18n}} - {{policy.name | i18n}}</h2>
|
||||||
<button type="button" class="close" data-dismiss="modal" appA11yTitle="{{'close' | i18n}}">
|
<button type="button" class="close" data-dismiss="modal" appA11yTitle="{{'close' | i18n}}">
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body" *ngIf="loading">
|
|
||||||
<i class="fa fa-spinner fa-spin text-muted" title="{{'loading' | i18n}}" aria-hidden="true"></i>
|
<div class="modal-body">
|
||||||
<span class="sr-only">{{'loading' | i18n}}</span>
|
<div class="modal-body" *ngIf="loading">
|
||||||
</div>
|
<i class="fa fa-spinner fa-spin text-muted" title="{{'loading' | i18n}}" aria-hidden="true"></i>
|
||||||
<div class="modal-body" *ngIf="!loading">
|
<span class="sr-only">{{'loading' | i18n}}</span>
|
||||||
<p>{{description}}</p>
|
</div>
|
||||||
<app-callout type="warning" *ngIf="type === policyType.TwoFactorAuthentication"
|
<div [hidden]="loading">
|
||||||
title="{{'warning' | i18n}}" icon="fa-warning">
|
<p>{{policy.description | i18n}}</p>
|
||||||
{{'twoStepLoginPolicyWarning' | i18n}}
|
<ng-template #policyForm></ng-template>
|
||||||
</app-callout>
|
|
||||||
<app-callout type="warning" *ngIf="type === policyType.SingleOrg" title="{{'warning' | i18n}}"
|
|
||||||
icon="fa-warning">
|
|
||||||
{{'singleOrgPolicyWarning' | i18n}}
|
|
||||||
</app-callout>
|
|
||||||
<ng-container *ngIf="type === policyType.RequireSso">
|
|
||||||
<app-callout type="tip" title="{{'prerequisite' | i18n}}">
|
|
||||||
{{'requireSsoPolicyReq' | i18n}}
|
|
||||||
</app-callout>
|
|
||||||
<app-callout type="warning">
|
|
||||||
{{'requireSsoExemption' | i18n}}
|
|
||||||
</app-callout>
|
|
||||||
</ng-container>
|
|
||||||
<app-callout type="warning" *ngIf="type === policyType.PersonalOwnership">
|
|
||||||
{{'personalOwnershipExemption' | i18n}}
|
|
||||||
</app-callout>
|
|
||||||
<app-callout type="warning" *ngIf="type === policyType.DisableSend">
|
|
||||||
{{'disableSendExemption' | i18n}}
|
|
||||||
</app-callout>
|
|
||||||
<app-callout type="warning" *ngIf="type === policyType.SendOptions">
|
|
||||||
{{'sendOptionsExemption' | i18n}}
|
|
||||||
</app-callout>
|
|
||||||
<app-callout type="warning" *ngIf="type === policyType.ResetPassword">
|
|
||||||
{{'resetPasswordPolicyWarning' | i18n}}
|
|
||||||
</app-callout>
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="checkbox" id="enabled" [(ngModel)]="enabled"
|
|
||||||
name="Enabled">
|
|
||||||
<label class="form-check-label" for="enabled">{{checkboxDesc}}</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<ng-container *ngIf="type === policyType.MasterPassword">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-6 form-group">
|
|
||||||
<label for="masterPassMinComplexity">{{'minComplexityScore' | i18n}}</label>
|
|
||||||
<select id="masterPassMinComplexity" name="MasterPassMinComplexity"
|
|
||||||
[(ngModel)]="masterPassMinComplexity" class="form-control">
|
|
||||||
<option *ngFor="let o of passwordScores" [ngValue]="o.value">{{o.name}}</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="col-6 form-group">
|
|
||||||
<label for="masterPassMinLength">{{'minLength' | i18n}}</label>
|
|
||||||
<input id="masterPassMinLength" class="form-control" type="number" min="8"
|
|
||||||
name="MasterPassMinLength" [(ngModel)]="masterPassMinLength">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="checkbox" id="masterPassRequireUpper"
|
|
||||||
[(ngModel)]="masterPassRequireUpper" name="MasterPassRequireUpper">
|
|
||||||
<label class="form-check-label" for="masterPassRequireUpper">A-Z</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="checkbox" id="masterPassRequireLower"
|
|
||||||
[(ngModel)]="masterPassRequireLower" name="MasterPassRequireLower">
|
|
||||||
<label class="form-check-label" for="masterPassRequireLower">a-z</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="checkbox" id="masterPassRequireNumbers"
|
|
||||||
[(ngModel)]="masterPassRequireNumbers" name="MasterPassRequireNumbers">
|
|
||||||
<label class="form-check-label" for="masterPassRequireNumbers">0-9</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="checkbox" id="masterPassRequireSpecial"
|
|
||||||
[(ngModel)]="masterPassRequireSpecial" name="MasterPassRequireSpecial">
|
|
||||||
<label class="form-check-label" for="masterPassRequireSpecial">!@#$%^&*</label>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
|
||||||
<ng-container *ngIf="type === policyType.PasswordGenerator">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-6 form-group mb-0">
|
|
||||||
<label for="passGenDefaultType">{{'defaultType' | i18n}}</label>
|
|
||||||
<select id="passGenDefaultType" name="PassGenDefaultType" [(ngModel)]="passGenDefaultType"
|
|
||||||
class="form-control">
|
|
||||||
<option *ngFor="let o of defaultTypes" [ngValue]="o.value">{{o.name}}</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<h3 class="mt-4">{{'password' | i18n}}</h3>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-6 form-group">
|
|
||||||
<label for="passGenMinLength">{{'minLength' | i18n}}</label>
|
|
||||||
<input id="passGenMinLength" class="form-control" type="number" name="PassGenMinLength"
|
|
||||||
min="5" max="128" [(ngModel)]="passGenMinLength">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-6 form-group">
|
|
||||||
<label for="passGenMinNumbers">{{'minNumbers' | i18n}}</label>
|
|
||||||
<input id="passGenMinNumbers" class="form-control" type="number" name="PassGenMinNumbers"
|
|
||||||
min="0" max="9" [(ngModel)]="passGenMinNumbers">
|
|
||||||
</div>
|
|
||||||
<div class="col-6 form-group">
|
|
||||||
<label for="passGenMinSpecial">{{'minSpecial' | i18n}}</label>
|
|
||||||
<input id="passGenMinSpecial" class="form-control" type="number" name="PassGenMinSpecial"
|
|
||||||
min="0" max="9" [(ngModel)]="passGenMinSpecial">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="checkbox" id="passGenUseUpper"
|
|
||||||
[(ngModel)]="passGenUseUpper" name="PassGenUseUpper">
|
|
||||||
<label class="form-check-label" for="passGenUseUpper">A-Z</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="checkbox" id="passGenUseLower"
|
|
||||||
[(ngModel)]="passGenUseLower" name="PassGenUseLower">
|
|
||||||
<label class="form-check-label" for="passGenUseLower">a-z</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="checkbox" id="passGenUseNumbers"
|
|
||||||
[(ngModel)]="passGenUseNumbers" name="PassGenUseNumbers">
|
|
||||||
<label class="form-check-label" for="passGenUseNumbers">0-9</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="checkbox" id="passGenUseSpecial"
|
|
||||||
[(ngModel)]="passGenUseSpecial" name="PassGenUseSpecial">
|
|
||||||
<label class="form-check-label" for="passGenUseSpecial">!@#$%^&*</label>
|
|
||||||
</div>
|
|
||||||
<h3 class="mt-4">{{'passphrase' | i18n}}</h3>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-6 form-group">
|
|
||||||
<label for="passGenMinNumberWords">{{'minimumNumberOfWords' | i18n}}</label>
|
|
||||||
<input id="passGenMinNumberWords" class="form-control" type="number"
|
|
||||||
name="PassGenMinNumberWords" min="3" max="20" [(ngModel)]="passGenMinNumberWords">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="checkbox" id="passGenCapitalize"
|
|
||||||
[(ngModel)]="passGenCapitalize" name="PassGenCapitalize">
|
|
||||||
<label class="form-check-label" for="passGenCapitalize">{{'capitalize' | i18n}}</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="checkbox" id="passGenIncludeNumber"
|
|
||||||
[(ngModel)]="passGenIncludeNumber" name="PassGenIncludeNumber">
|
|
||||||
<label class="form-check-label" for="passGenIncludeNumber">{{'includeNumber' | i18n}}</label>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
|
||||||
<ng-container *ngIf="type === policyType.SendOptions">
|
|
||||||
<h3 class="mt-4">{{'options' | i18n}}</h3>
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="checkbox" id="sendDisableHideEmail"
|
|
||||||
[(ngModel)]="sendDisableHideEmail" name="SendDisableHideEmail">
|
|
||||||
<label class="form-check-label" for="sendDisableHideEmail">{{'disableHideEmail' | i18n}}</label>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
|
||||||
<ng-container *ngIf="type === policyType.ResetPassword">
|
|
||||||
<h3 class="mt-4">{{'resetPasswordPolicyAutoEnroll' | i18n}}</h3>
|
|
||||||
<p>{{'resetPasswordPolicyAutoEnrollDescription' | i18n}}</p>
|
|
||||||
<app-callout type="warning">
|
|
||||||
{{'resetPasswordPolicyAutoEnrollWarning' | i18n}}
|
|
||||||
</app-callout>
|
|
||||||
<div class="form-check">
|
|
||||||
<input class="form-check-input" type="checkbox" id="autoEnrollEnabled"
|
|
||||||
[(ngModel)]="resetPasswordAutoEnroll" name="AutoEnrollEnabled">
|
|
||||||
<label class="form-check-label"
|
|
||||||
for="autoEnrollEnabled">{{'resetPasswordPolicyAutoEnrollCheckbox' | i18n }}</label>
|
|
||||||
</div>
|
|
||||||
</ng-container>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading">
|
<button type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading">
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
import {
|
import {
|
||||||
|
ChangeDetectorRef,
|
||||||
Component,
|
Component,
|
||||||
|
ComponentFactoryResolver,
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
Input,
|
Input,
|
||||||
OnInit,
|
|
||||||
Output,
|
Output,
|
||||||
|
ViewChild,
|
||||||
|
ViewContainerRef,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
|
|
||||||
import { ToasterService } from 'angular2-toaster';
|
import { ToasterService } from 'angular2-toaster';
|
||||||
@ -17,119 +20,52 @@ import { PolicyRequest } from 'jslib-common/models/request/policyRequest';
|
|||||||
|
|
||||||
import { PolicyResponse } from 'jslib-common/models/response/policyResponse';
|
import { PolicyResponse } from 'jslib-common/models/response/policyResponse';
|
||||||
|
|
||||||
|
import { BasePolicy, BasePolicyComponent } from '../policies/base-policy.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-policy-edit',
|
selector: 'app-policy-edit',
|
||||||
templateUrl: 'policy-edit.component.html',
|
templateUrl: 'policy-edit.component.html',
|
||||||
})
|
})
|
||||||
export class PolicyEditComponent implements OnInit {
|
export class PolicyEditComponent {
|
||||||
@Input() name: string;
|
@Input() policy: BasePolicy;
|
||||||
@Input() description: string;
|
|
||||||
@Input() type: PolicyType;
|
|
||||||
@Input() organizationId: string;
|
@Input() organizationId: string;
|
||||||
@Input() policiesEnabledMap: Map<PolicyType, boolean> = new Map<PolicyType, boolean>();
|
@Input() policiesEnabledMap: Map<PolicyType, boolean> = new Map<PolicyType, boolean>();
|
||||||
@Output() onSavedPolicy = new EventEmitter();
|
@Output() onSavedPolicy = new EventEmitter();
|
||||||
|
|
||||||
|
@ViewChild('policyForm', { read: ViewContainerRef, static: true }) policyFormRef: ViewContainerRef;
|
||||||
|
|
||||||
policyType = PolicyType;
|
policyType = PolicyType;
|
||||||
loading = true;
|
loading = true;
|
||||||
enabled = false;
|
enabled = false;
|
||||||
formPromise: Promise<any>;
|
formPromise: Promise<any>;
|
||||||
passwordScores: any[];
|
|
||||||
defaultTypes: any[];
|
defaultTypes: any[];
|
||||||
|
policyComponent: BasePolicyComponent;
|
||||||
|
|
||||||
// Master password
|
private policyResponse: PolicyResponse;
|
||||||
masterPassMinComplexity?: number = null;
|
|
||||||
masterPassMinLength?: number;
|
|
||||||
masterPassRequireUpper?: number;
|
|
||||||
masterPassRequireLower?: number;
|
|
||||||
masterPassRequireNumbers?: number;
|
|
||||||
masterPassRequireSpecial?: number;
|
|
||||||
|
|
||||||
// Password generator
|
|
||||||
passGenDefaultType?: string;
|
|
||||||
passGenMinLength?: number;
|
|
||||||
passGenUseUpper?: boolean;
|
|
||||||
passGenUseLower?: boolean;
|
|
||||||
passGenUseNumbers?: boolean;
|
|
||||||
passGenUseSpecial?: boolean;
|
|
||||||
passGenMinNumbers?: number;
|
|
||||||
passGenMinSpecial?: number;
|
|
||||||
passGenMinNumberWords?: number;
|
|
||||||
passGenCapitalize?: boolean;
|
|
||||||
passGenIncludeNumber?: boolean;
|
|
||||||
|
|
||||||
// Send options
|
|
||||||
sendDisableHideEmail?: boolean;
|
|
||||||
|
|
||||||
// Reset Password
|
|
||||||
resetPasswordAutoEnroll?: boolean;
|
|
||||||
|
|
||||||
private policy: PolicyResponse;
|
|
||||||
|
|
||||||
constructor(private apiService: ApiService, private i18nService: I18nService,
|
constructor(private apiService: ApiService, private i18nService: I18nService,
|
||||||
private toasterService: ToasterService) {
|
private toasterService: ToasterService, private componentFactoryResolver: ComponentFactoryResolver,
|
||||||
this.passwordScores = [
|
private cdr: ChangeDetectorRef) {
|
||||||
{ name: '-- ' + i18nService.t('select') + ' --', value: null },
|
|
||||||
{ name: i18nService.t('weak') + ' (0)', value: 0 },
|
|
||||||
{ name: i18nService.t('weak') + ' (1)', value: 1 },
|
|
||||||
{ name: i18nService.t('weak') + ' (2)', value: 2 },
|
|
||||||
{ name: i18nService.t('good') + ' (3)', value: 3 },
|
|
||||||
{ name: i18nService.t('strong') + ' (4)', value: 4 },
|
|
||||||
];
|
|
||||||
this.defaultTypes = [
|
|
||||||
{ name: i18nService.t('userPreference'), value: null },
|
|
||||||
{ name: i18nService.t('password'), value: 'password' },
|
|
||||||
{ name: i18nService.t('passphrase'), value: 'passphrase' },
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngAfterViewInit() {
|
||||||
await this.load();
|
await this.load();
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
|
|
||||||
|
const factory = this.componentFactoryResolver.resolveComponentFactory(this.policy.component);
|
||||||
|
this.policyComponent = this.policyFormRef.createComponent(factory).instance as BasePolicyComponent;
|
||||||
|
this.policyComponent.policy = this.policy;
|
||||||
|
this.policyComponent.policyResponse = this.policyResponse;
|
||||||
|
|
||||||
|
this.cdr.detectChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
async load() {
|
async load() {
|
||||||
try {
|
try {
|
||||||
this.policy = await this.apiService.getPolicy(this.organizationId, this.type);
|
this.policyResponse = await this.apiService.getPolicy(this.organizationId, this.policy.type);
|
||||||
|
|
||||||
if (this.policy != null) {
|
|
||||||
this.enabled = this.policy.enabled;
|
|
||||||
if (this.policy.data != null) {
|
|
||||||
switch (this.type) {
|
|
||||||
case PolicyType.PasswordGenerator:
|
|
||||||
this.passGenDefaultType = this.policy.data.defaultType;
|
|
||||||
this.passGenMinLength = this.policy.data.minLength;
|
|
||||||
this.passGenUseUpper = this.policy.data.useUpper;
|
|
||||||
this.passGenUseLower = this.policy.data.useLower;
|
|
||||||
this.passGenUseNumbers = this.policy.data.useNumbers;
|
|
||||||
this.passGenUseSpecial = this.policy.data.useSpecial;
|
|
||||||
this.passGenMinNumbers = this.policy.data.minNumbers;
|
|
||||||
this.passGenMinSpecial = this.policy.data.minSpecial;
|
|
||||||
this.passGenMinNumberWords = this.policy.data.minNumberWords;
|
|
||||||
this.passGenCapitalize = this.policy.data.capitalize;
|
|
||||||
this.passGenIncludeNumber = this.policy.data.includeNumber;
|
|
||||||
break;
|
|
||||||
case PolicyType.MasterPassword:
|
|
||||||
this.masterPassMinComplexity = this.policy.data.minComplexity;
|
|
||||||
this.masterPassMinLength = this.policy.data.minLength;
|
|
||||||
this.masterPassRequireUpper = this.policy.data.requireUpper;
|
|
||||||
this.masterPassRequireLower = this.policy.data.requireLower;
|
|
||||||
this.masterPassRequireNumbers = this.policy.data.requireNumbers;
|
|
||||||
this.masterPassRequireSpecial = this.policy.data.requireSpecial;
|
|
||||||
break;
|
|
||||||
case PolicyType.SendOptions:
|
|
||||||
this.sendDisableHideEmail = this.policy.data.disableHideEmail;
|
|
||||||
break;
|
|
||||||
case PolicyType.ResetPassword:
|
|
||||||
this.resetPasswordAutoEnroll = this.policy.data.autoEnrollEnabled;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.statusCode === 404) {
|
if (e.statusCode === 404) {
|
||||||
this.enabled = false;
|
this.policyResponse = new PolicyResponse({Enabled: false});
|
||||||
} else {
|
} else {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
@ -137,94 +73,19 @@ export class PolicyEditComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async submit() {
|
async submit() {
|
||||||
if (this.preValidate()) {
|
let request: PolicyRequest;
|
||||||
const request = new PolicyRequest();
|
try {
|
||||||
request.enabled = this.enabled;
|
request = await this.policyComponent.buildRequest(this.policiesEnabledMap);
|
||||||
request.type = this.type;
|
} catch (e) {
|
||||||
request.data = null;
|
this.toasterService.pop('error', null, e);
|
||||||
switch (this.type) {
|
return;
|
||||||
case PolicyType.PasswordGenerator:
|
|
||||||
request.data = {
|
|
||||||
defaultType: this.passGenDefaultType,
|
|
||||||
minLength: this.passGenMinLength || null,
|
|
||||||
useUpper: this.passGenUseUpper,
|
|
||||||
useLower: this.passGenUseLower,
|
|
||||||
useNumbers: this.passGenUseNumbers,
|
|
||||||
useSpecial: this.passGenUseSpecial,
|
|
||||||
minNumbers: this.passGenMinNumbers || null,
|
|
||||||
minSpecial: this.passGenMinSpecial || null,
|
|
||||||
minNumberWords: this.passGenMinNumberWords || null,
|
|
||||||
capitalize: this.passGenCapitalize,
|
|
||||||
includeNumber: this.passGenIncludeNumber,
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case PolicyType.MasterPassword:
|
|
||||||
request.data = {
|
|
||||||
minComplexity: this.masterPassMinComplexity || null,
|
|
||||||
minLength: this.masterPassMinLength || null,
|
|
||||||
requireUpper: this.masterPassRequireUpper,
|
|
||||||
requireLower: this.masterPassRequireLower,
|
|
||||||
requireNumbers: this.masterPassRequireNumbers,
|
|
||||||
requireSpecial: this.masterPassRequireSpecial,
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case PolicyType.SendOptions:
|
|
||||||
request.data = {
|
|
||||||
disableHideEmail: this.sendDisableHideEmail,
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case PolicyType.ResetPassword:
|
|
||||||
request.data = {
|
|
||||||
autoEnrollEnabled: this.resetPasswordAutoEnroll,
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
this.formPromise = this.apiService.putPolicy(this.organizationId, this.type, request);
|
|
||||||
await this.formPromise;
|
|
||||||
this.toasterService.popAsync('success', null, this.i18nService.t('editedPolicyId', this.name));
|
|
||||||
this.onSavedPolicy.emit();
|
|
||||||
} catch { }
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
get checkboxDesc(): string {
|
try {
|
||||||
return this.type === PolicyType.PersonalOwnership ? this.i18nService.t('personalOwnershipCheckboxDesc') :
|
this.formPromise = this.apiService.putPolicy(this.organizationId, this.policy.type, request);
|
||||||
this.i18nService.t('enabled');
|
await this.formPromise;
|
||||||
}
|
this.toasterService.popAsync('success', null, this.i18nService.t('editedPolicyId', this.i18nService.t(this.policy.name)));
|
||||||
|
this.onSavedPolicy.emit();
|
||||||
private preValidate(): boolean {
|
} catch {}
|
||||||
switch (this.type) {
|
|
||||||
case PolicyType.RequireSso:
|
|
||||||
// Don't need prevalidation checks if submitting to disable
|
|
||||||
if (!this.enabled) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// Have SingleOrg policy enabled?
|
|
||||||
if (!(this.policiesEnabledMap.has(PolicyType.SingleOrg)
|
|
||||||
&& this.policiesEnabledMap.get(PolicyType.SingleOrg))) {
|
|
||||||
this.toasterService.popAsync('error', null, this.i18nService.t('requireSsoPolicyReqError'));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case PolicyType.SingleOrg:
|
|
||||||
// Don't need prevalidation checks if submitting to enable
|
|
||||||
if (this.enabled) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// If RequireSso Policy is enabled prevent submittal
|
|
||||||
if (this.policiesEnabledMap.has(PolicyType.RequireSso)
|
|
||||||
&& this.policiesEnabledMap.get(PolicyType.RequireSso)) {
|
|
||||||
this.toasterService.popAsync('error', null, this.i18nService.t('disableRequireSsoError'));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
54
src/app/organizations/policies/base-policy.component.ts
Normal file
54
src/app/organizations/policies/base-policy.component.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import {
|
||||||
|
Directive,
|
||||||
|
Input,
|
||||||
|
OnInit,
|
||||||
|
} from '@angular/core';
|
||||||
|
import { FormControl, FormGroup } from '@angular/forms';
|
||||||
|
|
||||||
|
import { Organization } from 'jslib-common/models/domain/organization';
|
||||||
|
|
||||||
|
import { PolicyType } from 'jslib-common/enums/policyType';
|
||||||
|
|
||||||
|
import { PolicyRequest } from 'jslib-common/models/request/policyRequest';
|
||||||
|
|
||||||
|
import { PolicyResponse } from 'jslib-common/models/response/policyResponse';
|
||||||
|
|
||||||
|
export abstract class BasePolicy {
|
||||||
|
abstract name: string;
|
||||||
|
abstract description: string;
|
||||||
|
abstract type: PolicyType;
|
||||||
|
abstract component: any;
|
||||||
|
|
||||||
|
display(organization: Organization) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Directive()
|
||||||
|
export abstract class BasePolicyComponent implements OnInit {
|
||||||
|
@Input() policyResponse: PolicyResponse;
|
||||||
|
@Input() policy: BasePolicy;
|
||||||
|
|
||||||
|
enabled = new FormControl(false);
|
||||||
|
data: FormGroup = null;
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.enabled.setValue(this.policyResponse.enabled);
|
||||||
|
|
||||||
|
if (this.data != null) {
|
||||||
|
this.data.patchValue(this.policyResponse.data ?? {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildRequest(policiesEnabledMap: Map<PolicyType, boolean>) {
|
||||||
|
const request = new PolicyRequest();
|
||||||
|
request.enabled = this.enabled.value;
|
||||||
|
request.type = this.policy.type;
|
||||||
|
|
||||||
|
if (this.data != null) {
|
||||||
|
request.data = this.data.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve(request);
|
||||||
|
}
|
||||||
|
}
|
10
src/app/organizations/policies/disable-send.component.html
Normal file
10
src/app/organizations/policies/disable-send.component.html
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<app-callout type="warning">
|
||||||
|
{{'disableSendExemption' | i18n}}
|
||||||
|
</app-callout>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="enabled" [formControl]="enabled" name="Enabled">
|
||||||
|
<label class="form-check-label" for="enabled">{{'enabled' | i18n}}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
19
src/app/organizations/policies/disable-send.component.ts
Normal file
19
src/app/organizations/policies/disable-send.component.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
import { PolicyType } from 'jslib-common/enums/policyType';
|
||||||
|
|
||||||
|
import { BasePolicy, BasePolicyComponent } from './base-policy.component';
|
||||||
|
|
||||||
|
export class DisableSendPolicy extends BasePolicy {
|
||||||
|
name = 'disableSend';
|
||||||
|
description = 'disableSendPolicyDesc';
|
||||||
|
type = PolicyType.DisableSend;
|
||||||
|
component = DisableSendPolicyComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'policy-disable-send',
|
||||||
|
templateUrl: 'disable-send.component.html',
|
||||||
|
})
|
||||||
|
export class DisableSendPolicyComponent extends BasePolicyComponent {
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
<div [formGroup]="data">
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="enabled" [formControl]="enabled" name="Enabled">
|
||||||
|
<label class="form-check-label" for="enabled">{{'enabled' | i18n}}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6 form-group">
|
||||||
|
<label for="minComplexity">{{'minComplexityScore' | i18n}}</label>
|
||||||
|
<select id="minComplexity" name="minComplexity" formControlName="minComplexity" class="form-control">
|
||||||
|
<option *ngFor="let o of passwordScores" [ngValue]="o.value">{{o.name}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-6 form-group">
|
||||||
|
<label for="minLength">{{'minLength' | i18n}}</label>
|
||||||
|
<input id="minLength" class="form-control" type="number" min="8" name="minLength"
|
||||||
|
formControlName="minLength">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="requireUpper" name="requireUpper"
|
||||||
|
formControlName="requireUpper">
|
||||||
|
<label class="form-check-label" for="requireUpper">A-Z</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="requireLower" name="requireLower"
|
||||||
|
formControlName="requireLower">
|
||||||
|
<label class="form-check-label" for="requireLower">a-z</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="requireNumbers" name="requireNumbers"
|
||||||
|
formControlName="requireNumbers">
|
||||||
|
<label class="form-check-label" for="requireNumbers">0-9</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="requireSpecial" name="requireSpecial"
|
||||||
|
formControlName="requireSpecial">
|
||||||
|
<label class="form-check-label" for="requireSpecial">!@#$%^&*</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
46
src/app/organizations/policies/master-password.component.ts
Normal file
46
src/app/organizations/policies/master-password.component.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { FormBuilder } from '@angular/forms';
|
||||||
|
|
||||||
|
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||||
|
|
||||||
|
import { PolicyType } from 'jslib-common/enums/policyType';
|
||||||
|
|
||||||
|
import { BasePolicy, BasePolicyComponent } from './base-policy.component';
|
||||||
|
|
||||||
|
export class MasterPasswordPolicy extends BasePolicy {
|
||||||
|
name = 'masterPass';
|
||||||
|
description = 'masterPassPolicyDesc';
|
||||||
|
type = PolicyType.MasterPassword;
|
||||||
|
component = MasterPasswordPolicyComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'policy-master-password',
|
||||||
|
templateUrl: 'master-password.component.html',
|
||||||
|
})
|
||||||
|
export class MasterPasswordPolicyComponent extends BasePolicyComponent {
|
||||||
|
|
||||||
|
data = this.fb.group({
|
||||||
|
minComplexity: [null],
|
||||||
|
minLength: [null],
|
||||||
|
requireUpper: [null],
|
||||||
|
requireLower: [null],
|
||||||
|
requireNumbers: [null],
|
||||||
|
requireSpecial: [null],
|
||||||
|
});
|
||||||
|
|
||||||
|
passwordScores: { name: string; value: number; }[];
|
||||||
|
|
||||||
|
constructor(private fb: FormBuilder, i18nService: I18nService) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.passwordScores = [
|
||||||
|
{ name: '-- ' + i18nService.t('select') + ' --', value: null },
|
||||||
|
{ name: i18nService.t('weak') + ' (0)', value: 0 },
|
||||||
|
{ name: i18nService.t('weak') + ' (1)', value: 1 },
|
||||||
|
{ name: i18nService.t('weak') + ' (2)', value: 2 },
|
||||||
|
{ name: i18nService.t('good') + ' (3)', value: 3 },
|
||||||
|
{ name: i18nService.t('strong') + ' (4)', value: 4 },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
<div [formGroup]="data">
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="enabled" [formControl]="enabled" name="Enabled">
|
||||||
|
<label class="form-check-label" for="enabled">{{'enabled' | i18n}}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6 form-group mb-0">
|
||||||
|
<label for="defaultType">{{'defaultType' | i18n}}</label>
|
||||||
|
<select id="defaultType" name="defaultType" formControlName="defaultType" class="form-control">
|
||||||
|
<option *ngFor="let o of defaultTypes" [ngValue]="o.value">{{o.name}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h3 class="mt-4">{{'password' | i18n}}</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6 form-group">
|
||||||
|
<label for="minLength">{{'minLength' | i18n}}</label>
|
||||||
|
<input id="minLength" class="form-control" type="number" name="minLength" min="5" max="128"
|
||||||
|
formControlName="minLength">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6 form-group">
|
||||||
|
<label for="minNumbers">{{'minNumbers' | i18n}}</label>
|
||||||
|
<input id="minNumbers" class="form-control" type="number" name="minNumbers" min="0" max="9"
|
||||||
|
formControlName="minNumbers">
|
||||||
|
</div>
|
||||||
|
<div class="col-6 form-group">
|
||||||
|
<label for="minSpecial">{{'minSpecial' | i18n}}</label>
|
||||||
|
<input id="minSpecial" class="form-control" type="number" name="minSpecial" min="0" max="9"
|
||||||
|
formControlName="minSpecial">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="useUpper"
|
||||||
|
formControlName="useUpper" name="useUpper">
|
||||||
|
<label class="form-check-label" for="useUpper">A-Z</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="useLower" name="useLower" formControlName="useLower">
|
||||||
|
<label class="form-check-label" for="useLower">a-z</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="useNumbers" name="useNumbers" formControlName="useNumbers">
|
||||||
|
<label class="form-check-label" for="useNumbers">0-9</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="useSpecial" name="useSpecial" formControlName="useSpecial">
|
||||||
|
<label class="form-check-label" for="useSpecial">!@#$%^&*</label>
|
||||||
|
</div>
|
||||||
|
<h3 class="mt-4">{{'passphrase' | i18n}}</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6 form-group">
|
||||||
|
<label for="minNumberWords">{{'minimumNumberOfWords' | i18n}}</label>
|
||||||
|
<input id="minNumberWords" class="form-control" type="number" name="minNumberWords" min="3" max="20"
|
||||||
|
formControlName="minNumberWords">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="capitalize" name="capitalize"
|
||||||
|
formControlName="capitalize">
|
||||||
|
<label class="form-check-label" for="capitalize">{{'capitalize' | i18n}}</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="includeNumber" name="includeNumber"
|
||||||
|
formControlName="includeNumber">
|
||||||
|
<label class="form-check-label" for="includeNumber">{{'includeNumber' | i18n}}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,48 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { FormBuilder } from '@angular/forms';
|
||||||
|
|
||||||
|
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||||
|
|
||||||
|
import { PolicyType } from 'jslib-common/enums/policyType';
|
||||||
|
|
||||||
|
import { BasePolicy, BasePolicyComponent } from './base-policy.component';
|
||||||
|
|
||||||
|
export class PasswordGeneratorPolicy extends BasePolicy {
|
||||||
|
name = 'passwordGenerator';
|
||||||
|
description = 'passwordGeneratorPolicyDesc';
|
||||||
|
type = PolicyType.PasswordGenerator;
|
||||||
|
component = PasswordGeneratorPolicyComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'policy-password-generator',
|
||||||
|
templateUrl: 'password-generator.component.html',
|
||||||
|
})
|
||||||
|
export class PasswordGeneratorPolicyComponent extends BasePolicyComponent {
|
||||||
|
|
||||||
|
data = this.fb.group({
|
||||||
|
defaultType: [null],
|
||||||
|
minLength: [null],
|
||||||
|
useUpper: [null],
|
||||||
|
useLower: [null],
|
||||||
|
useNumbers: [null],
|
||||||
|
useSpecial: [null],
|
||||||
|
minNumbers: [null],
|
||||||
|
minSpecial: [null],
|
||||||
|
minNumberWords: [null],
|
||||||
|
capitalize: [null],
|
||||||
|
includeNumber: [null],
|
||||||
|
});
|
||||||
|
|
||||||
|
defaultTypes: { name: string; value: string; }[];
|
||||||
|
|
||||||
|
constructor(private fb: FormBuilder, i18nService: I18nService) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.defaultTypes = [
|
||||||
|
{ name: i18nService.t('userPreference'), value: null },
|
||||||
|
{ name: i18nService.t('password'), value: 'password' },
|
||||||
|
{ name: i18nService.t('passphrase'), value: 'passphrase' },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
<app-callout type="warning">
|
||||||
|
{{'personalOwnershipExemption' | i18n}}
|
||||||
|
</app-callout>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="enabled" [formControl]="enabled" name="Enabled">
|
||||||
|
<label class="form-check-label" for="enabled">{{'personalOwnershipCheckboxDesc' | i18n}}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,19 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
import { PolicyType } from 'jslib-common/enums/policyType';
|
||||||
|
|
||||||
|
import { BasePolicy, BasePolicyComponent } from './base-policy.component';
|
||||||
|
|
||||||
|
export class PersonalOwnershipPolicy extends BasePolicy {
|
||||||
|
name = 'personalOwnership';
|
||||||
|
description = 'personalOwnershipPolicyDesc';
|
||||||
|
type = PolicyType.PersonalOwnership;
|
||||||
|
component = PersonalOwnershipPolicyComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'policy-personal-ownership',
|
||||||
|
templateUrl: 'personal-ownership.component.html',
|
||||||
|
})
|
||||||
|
export class PersonalOwnershipPolicyComponent extends BasePolicyComponent {
|
||||||
|
}
|
13
src/app/organizations/policies/require-sso.component.html
Normal file
13
src/app/organizations/policies/require-sso.component.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<app-callout type="tip" title="{{'prerequisite' | i18n}}">
|
||||||
|
{{'requireSsoPolicyReq' | i18n}}
|
||||||
|
</app-callout>
|
||||||
|
<app-callout type="warning">
|
||||||
|
{{'requireSsoExemption' | i18n}}
|
||||||
|
</app-callout>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="enabled" [formControl]="enabled" name="Enabled">
|
||||||
|
<label class="form-check-label" for="enabled">{{'enabled' | i18n}}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
40
src/app/organizations/policies/require-sso.component.ts
Normal file
40
src/app/organizations/policies/require-sso.component.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||||
|
|
||||||
|
import { PolicyType } from 'jslib-common/enums/policyType';
|
||||||
|
|
||||||
|
import { Organization } from 'jslib-common/models/domain/organization';
|
||||||
|
import { PolicyRequest } from 'jslib-common/models/request/policyRequest';
|
||||||
|
|
||||||
|
import { BasePolicy, BasePolicyComponent } from './base-policy.component';
|
||||||
|
|
||||||
|
export class RequireSsoPolicy extends BasePolicy {
|
||||||
|
name = 'requireSso';
|
||||||
|
description = 'requireSsoPolicyDesc';
|
||||||
|
type = PolicyType.RequireSso;
|
||||||
|
component = RequireSsoPolicyComponent;
|
||||||
|
|
||||||
|
display(organization: Organization) {
|
||||||
|
return organization.useSso;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'policy-require-sso',
|
||||||
|
templateUrl: 'require-sso.component.html',
|
||||||
|
})
|
||||||
|
export class RequireSsoPolicyComponent extends BasePolicyComponent {
|
||||||
|
constructor(private i18nService: I18nService) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
buildRequest(policiesEnabledMap: Map<PolicyType, boolean>): Promise<PolicyRequest> {
|
||||||
|
const singleOrgEnabled = policiesEnabledMap.get(PolicyType.SingleOrg) ?? false;
|
||||||
|
if (this.enabled.value && singleOrgEnabled) {
|
||||||
|
throw new Error(this.i18nService.t('requireSsoPolicyReqError'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.buildRequest(policiesEnabledMap);
|
||||||
|
}
|
||||||
|
}
|
25
src/app/organizations/policies/reset-password.component.html
Normal file
25
src/app/organizations/policies/reset-password.component.html
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<app-callout type="warning">
|
||||||
|
{{'resetPasswordPolicyWarning' | i18n}}
|
||||||
|
</app-callout>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="enabled" [formControl]="enabled" name="Enabled">
|
||||||
|
<label class="form-check-label" for="enabled">{{'enabled' | i18n}}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div [formGroup]="data">
|
||||||
|
<h3 class="mt-4">{{'resetPasswordPolicyAutoEnroll' | i18n}}</h3>
|
||||||
|
<p>{{'resetPasswordPolicyAutoEnrollDescription' | i18n}}</p>
|
||||||
|
<app-callout type="warning">
|
||||||
|
{{'resetPasswordPolicyAutoEnrollWarning' | i18n}}
|
||||||
|
</app-callout>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="autoEnrollEnabled" name="AutoEnrollEnabled"
|
||||||
|
formControlName="autoEnroll">
|
||||||
|
<label class="form-check-label" for="autoEnrollEnabled">
|
||||||
|
{{'resetPasswordPolicyAutoEnrollCheckbox' | i18n }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
36
src/app/organizations/policies/reset-password.component.ts
Normal file
36
src/app/organizations/policies/reset-password.component.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { FormBuilder } from '@angular/forms';
|
||||||
|
|
||||||
|
import { PolicyType } from 'jslib-common/enums/policyType';
|
||||||
|
|
||||||
|
import { Organization } from 'jslib-common/models/domain/organization';
|
||||||
|
|
||||||
|
import { BasePolicy, BasePolicyComponent } from './base-policy.component';
|
||||||
|
|
||||||
|
export class ResetPasswordPolicy extends BasePolicy {
|
||||||
|
name = 'resetPasswordPolicy';
|
||||||
|
description = 'resetPasswordPolicyDescription';
|
||||||
|
type = PolicyType.ResetPassword;
|
||||||
|
component = ResetPasswordPolicyComponent;
|
||||||
|
|
||||||
|
display(organization: Organization) {
|
||||||
|
return organization.useResetPassword;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'policy-reset-password',
|
||||||
|
templateUrl: 'reset-password.component.html',
|
||||||
|
})
|
||||||
|
export class ResetPasswordPolicyComponent extends BasePolicyComponent {
|
||||||
|
|
||||||
|
data = this.fb.group({
|
||||||
|
autoEnroll: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
defaultTypes: { name: string; value: string; }[];
|
||||||
|
|
||||||
|
constructor(private fb: FormBuilder) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
}
|
19
src/app/organizations/policies/send-options.component.html
Normal file
19
src/app/organizations/policies/send-options.component.html
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<app-callout type="warning">
|
||||||
|
{{'sendOptionsExemption' | i18n}}
|
||||||
|
</app-callout>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="enabled" [formControl]="enabled" name="Enabled">
|
||||||
|
<label class="form-check-label" for="enabled">{{'enabled' | i18n}}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div [formGroup]="data">
|
||||||
|
<h3 class="mt-4">{{'options' | i18n}}</h3>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="disableHideEmail" name="DisableHideEmail"
|
||||||
|
formControlName="disableHideEmail">
|
||||||
|
<label class="form-check-label" for="disableHideEmail">{{'disableHideEmail' | i18n}}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
28
src/app/organizations/policies/send-options.component.ts
Normal file
28
src/app/organizations/policies/send-options.component.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { FormBuilder } from '@angular/forms';
|
||||||
|
|
||||||
|
import { PolicyType } from 'jslib-common/enums/policyType';
|
||||||
|
|
||||||
|
import { BasePolicy, BasePolicyComponent } from './base-policy.component';
|
||||||
|
|
||||||
|
export class SendOptionsPolicy extends BasePolicy {
|
||||||
|
name = 'sendOptions';
|
||||||
|
description = 'sendOptionsPolicyDesc';
|
||||||
|
type = PolicyType.SendOptions;
|
||||||
|
component = SendOptionsPolicyComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'policy-send-options',
|
||||||
|
templateUrl: 'send-options.component.html',
|
||||||
|
})
|
||||||
|
export class SendOptionsPolicyComponent extends BasePolicyComponent {
|
||||||
|
|
||||||
|
data = this.fb.group({
|
||||||
|
disableHideEmail: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
constructor(private fb: FormBuilder) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
}
|
10
src/app/organizations/policies/single-org.component.html
Normal file
10
src/app/organizations/policies/single-org.component.html
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<app-callout type="warning">
|
||||||
|
{{'singleOrgPolicyWarning' | i18n}}
|
||||||
|
</app-callout>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="enabled" [formControl]="enabled" name="Enabled">
|
||||||
|
<label class="form-check-label" for="enabled">{{'enabled' | i18n}}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
36
src/app/organizations/policies/single-org.component.ts
Normal file
36
src/app/organizations/policies/single-org.component.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
||||||
|
|
||||||
|
import { PolicyType } from 'jslib-common/enums/policyType';
|
||||||
|
|
||||||
|
import { PolicyRequest } from 'jslib-common/models/request/policyRequest';
|
||||||
|
|
||||||
|
import { BasePolicy, BasePolicyComponent } from './base-policy.component';
|
||||||
|
|
||||||
|
export class SingleOrgPolicy extends BasePolicy {
|
||||||
|
name = 'singleOrg';
|
||||||
|
description = 'singleOrgDesc';
|
||||||
|
type = PolicyType.SingleOrg;
|
||||||
|
component = SingleOrgPolicyComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'policy-single-org',
|
||||||
|
templateUrl: 'single-org.component.html',
|
||||||
|
})
|
||||||
|
export class SingleOrgPolicyComponent extends BasePolicyComponent {
|
||||||
|
|
||||||
|
constructor(private i18nService: I18nService) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
buildRequest(policiesEnabledMap: Map<PolicyType, boolean>): Promise<PolicyRequest> {
|
||||||
|
const requireSsoEnabled = policiesEnabledMap.get(PolicyType.RequireSso) ?? false;
|
||||||
|
if (!this.enabled.value && requireSsoEnabled) {
|
||||||
|
throw new Error(this.i18nService.t('disableRequireSsoError'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.buildRequest(policiesEnabledMap);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
<app-callout type="warning">
|
||||||
|
{{'twoStepLoginPolicyWarning' | i18n}}
|
||||||
|
</app-callout>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="enabled" [formControl]="enabled" name="Enabled">
|
||||||
|
<label class="form-check-label" for="enabled">{{'enabled' | i18n}}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,19 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
import { PolicyType } from 'jslib-common/enums/policyType';
|
||||||
|
|
||||||
|
import { BasePolicy, BasePolicyComponent } from './base-policy.component';
|
||||||
|
|
||||||
|
export class TwoFactorAuthenticationPolicy extends BasePolicy {
|
||||||
|
name = 'twoStepLogin';
|
||||||
|
description = 'twoStepLoginPolicyDesc';
|
||||||
|
type = PolicyType.TwoFactorAuthentication;
|
||||||
|
component = TwoFactorAuthenticationPolicyComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'policy-two-factor-authentication',
|
||||||
|
templateUrl: 'two-factor-authentication.component.html',
|
||||||
|
})
|
||||||
|
export class TwoFactorAuthenticationPolicyComponent extends BasePolicyComponent {
|
||||||
|
}
|
@ -234,6 +234,16 @@ import localeUk from '@angular/common/locales/uk';
|
|||||||
import localeZhCn from '@angular/common/locales/zh-Hans';
|
import localeZhCn from '@angular/common/locales/zh-Hans';
|
||||||
import localeZhTw from '@angular/common/locales/zh-Hant';
|
import localeZhTw from '@angular/common/locales/zh-Hant';
|
||||||
|
|
||||||
|
import { DisableSendPolicyComponent } from './organizations/policies/disable-send.component';
|
||||||
|
import { MasterPasswordPolicyComponent } from './organizations/policies/master-password.component';
|
||||||
|
import { PasswordGeneratorPolicyComponent } from './organizations/policies/password-generator.component';
|
||||||
|
import { PersonalOwnershipPolicyComponent } from './organizations/policies/personal-ownership.component';
|
||||||
|
import { RequireSsoPolicyComponent } from './organizations/policies/require-sso.component';
|
||||||
|
import { ResetPasswordPolicyComponent } from './organizations/policies/reset-password.component';
|
||||||
|
import { SendOptionsPolicyComponent } from './organizations/policies/send-options.component';
|
||||||
|
import { SingleOrgPolicyComponent } from './organizations/policies/single-org.component';
|
||||||
|
import { TwoFactorAuthenticationPolicyComponent } from './organizations/policies/two-factor-authentication.component';
|
||||||
|
|
||||||
registerLocaleData(localeAz, 'az');
|
registerLocaleData(localeAz, 'az');
|
||||||
registerLocaleData(localeBg, 'bg');
|
registerLocaleData(localeBg, 'bg');
|
||||||
registerLocaleData(localeCa, 'ca');
|
registerLocaleData(localeCa, 'ca');
|
||||||
@ -438,6 +448,15 @@ registerLocaleData(localeZhTw, 'zh-TW');
|
|||||||
VerifyRecoverDeleteComponent,
|
VerifyRecoverDeleteComponent,
|
||||||
WeakPasswordsReportComponent,
|
WeakPasswordsReportComponent,
|
||||||
ProvidersComponent,
|
ProvidersComponent,
|
||||||
|
TwoFactorAuthenticationPolicyComponent,
|
||||||
|
MasterPasswordPolicyComponent,
|
||||||
|
SingleOrgPolicyComponent,
|
||||||
|
PasswordGeneratorPolicyComponent,
|
||||||
|
RequireSsoPolicyComponent,
|
||||||
|
PersonalOwnershipPolicyComponent,
|
||||||
|
DisableSendPolicyComponent,
|
||||||
|
SendOptionsPolicyComponent,
|
||||||
|
ResetPasswordPolicyComponent,
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
A11yTitleDirective,
|
A11yTitleDirective,
|
||||||
|
13
src/app/services/policy-list.service.ts
Normal file
13
src/app/services/policy-list.service.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { BasePolicy } from '../organizations/policies/base-policy.component';
|
||||||
|
|
||||||
|
export class PolicyListService {
|
||||||
|
private policies: BasePolicy[] = [];
|
||||||
|
|
||||||
|
addPolicies(policies: BasePolicy[]) {
|
||||||
|
this.policies.push(...policies);
|
||||||
|
}
|
||||||
|
|
||||||
|
getPolicies(): BasePolicy[] {
|
||||||
|
return this.policies;
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,7 @@ import { WebPlatformUtilsService } from '../../services/webPlatformUtils.service
|
|||||||
import { EventService } from './event.service';
|
import { EventService } from './event.service';
|
||||||
import { OrganizationGuardService } from './organization-guard.service';
|
import { OrganizationGuardService } from './organization-guard.service';
|
||||||
import { OrganizationTypeGuardService } from './organization-type-guard.service';
|
import { OrganizationTypeGuardService } from './organization-type-guard.service';
|
||||||
|
import { PolicyListService } from './policy-list.service';
|
||||||
import { RouterService } from './router.service';
|
import { RouterService } from './router.service';
|
||||||
|
|
||||||
import { AuthGuardService } from 'jslib-angular/services/auth-guard.service';
|
import { AuthGuardService } from 'jslib-angular/services/auth-guard.service';
|
||||||
@ -191,6 +192,7 @@ export function initFactory(): Function {
|
|||||||
RouterService,
|
RouterService,
|
||||||
EventService,
|
EventService,
|
||||||
LockGuardService,
|
LockGuardService,
|
||||||
|
PolicyListService,
|
||||||
{ provide: AuditServiceAbstraction, useValue: auditService },
|
{ provide: AuditServiceAbstraction, useValue: auditService },
|
||||||
{ provide: AuthServiceAbstraction, useValue: authService },
|
{ provide: AuthServiceAbstraction, useValue: authService },
|
||||||
{ provide: CipherServiceAbstraction, useValue: cipherService },
|
{ provide: CipherServiceAbstraction, useValue: cipherService },
|
||||||
|
@ -3369,9 +3369,6 @@
|
|||||||
"linkSso": {
|
"linkSso": {
|
||||||
"message": "Link SSO"
|
"message": "Link SSO"
|
||||||
},
|
},
|
||||||
"webPoliciesDeprecationWarning": {
|
|
||||||
"message": "Policy configuration has been moved, and this page will soon be deprecated. Please click below to use the Business Portal policies page instead."
|
|
||||||
},
|
|
||||||
"singleOrg": {
|
"singleOrg": {
|
||||||
"message": "Single Organization"
|
"message": "Single Organization"
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user