import { OrganizationService } from "../../abstractions/organization/organization.service.abstraction"; import { InternalPolicyService as InternalPolicyServiceAbstraction } from "../../abstractions/policy/policy.service.abstraction"; import { StateService } from "../../abstractions/state.service"; import { OrganizationUserStatusType } from "../../enums/organizationUserStatusType"; import { OrganizationUserType } from "../../enums/organizationUserType"; import { PolicyType } from "../../enums/policyType"; import { PolicyData } from "../../models/data/policyData"; import { MasterPasswordPolicyOptions } from "../../models/domain/masterPasswordPolicyOptions"; import { Organization } from "../../models/domain/organization"; import { Policy } from "../../models/domain/policy"; import { ResetPasswordPolicyOptions } from "../../models/domain/resetPasswordPolicyOptions"; import { ListResponse } from "../../models/response/listResponse"; import { PolicyResponse } from "../../models/response/policyResponse"; export class PolicyService implements InternalPolicyServiceAbstraction { policyCache: Policy[]; constructor( private stateService: StateService, private organizationService: OrganizationService ) {} async getAll(type?: PolicyType, userId?: string): Promise { let response: Policy[] = []; const decryptedPolicies = await this.stateService.getDecryptedPolicies({ userId: userId }); if (decryptedPolicies != null) { response = decryptedPolicies; } else { const diskPolicies = await this.stateService.getEncryptedPolicies({ userId: userId }); for (const id in diskPolicies) { // eslint-disable-next-line if (diskPolicies.hasOwnProperty(id)) { response.push(new Policy(diskPolicies[id])); } } await this.stateService.setDecryptedPolicies(response, { userId: userId }); } if (type != null) { return response.filter((policy) => policy.type === type); } else { return response; } } async getMasterPasswordPolicyOptions(policies?: Policy[]): Promise { let enforcedOptions: MasterPasswordPolicyOptions = null; if (policies == null) { policies = await this.getAll(PolicyType.MasterPassword); } else { policies = policies.filter((p) => p.type === PolicyType.MasterPassword); } if (policies == null || policies.length === 0) { return enforcedOptions; } policies.forEach((currentPolicy) => { if (!currentPolicy.enabled || currentPolicy.data == null) { return; } if (enforcedOptions == null) { enforcedOptions = new MasterPasswordPolicyOptions(); } if ( currentPolicy.data.minComplexity != null && currentPolicy.data.minComplexity > enforcedOptions.minComplexity ) { enforcedOptions.minComplexity = currentPolicy.data.minComplexity; } if ( currentPolicy.data.minLength != null && currentPolicy.data.minLength > enforcedOptions.minLength ) { enforcedOptions.minLength = currentPolicy.data.minLength; } if (currentPolicy.data.requireUpper) { enforcedOptions.requireUpper = true; } if (currentPolicy.data.requireLower) { enforcedOptions.requireLower = true; } if (currentPolicy.data.requireNumbers) { enforcedOptions.requireNumbers = true; } if (currentPolicy.data.requireSpecial) { enforcedOptions.requireSpecial = true; } }); return enforcedOptions; } evaluateMasterPassword( passwordStrength: number, newPassword: string, enforcedPolicyOptions: MasterPasswordPolicyOptions ): boolean { if (enforcedPolicyOptions == null) { return true; } if ( enforcedPolicyOptions.minComplexity > 0 && enforcedPolicyOptions.minComplexity > passwordStrength ) { return false; } if ( enforcedPolicyOptions.minLength > 0 && enforcedPolicyOptions.minLength > newPassword.length ) { return false; } if (enforcedPolicyOptions.requireUpper && newPassword.toLocaleLowerCase() === newPassword) { return false; } if (enforcedPolicyOptions.requireLower && newPassword.toLocaleUpperCase() === newPassword) { return false; } if (enforcedPolicyOptions.requireNumbers && !/[0-9]/.test(newPassword)) { return false; } // eslint-disable-next-line if (enforcedPolicyOptions.requireSpecial && !/[!@#$%\^&*]/g.test(newPassword)) { return false; } return true; } getResetPasswordPolicyOptions( policies: Policy[], orgId: string ): [ResetPasswordPolicyOptions, boolean] { const resetPasswordPolicyOptions = new ResetPasswordPolicyOptions(); if (policies == null || orgId == null) { return [resetPasswordPolicyOptions, false]; } const policy = policies.find( (p) => p.organizationId === orgId && p.type === PolicyType.ResetPassword && p.enabled ); resetPasswordPolicyOptions.autoEnrollEnabled = policy?.data?.autoEnrollEnabled ?? false; return [resetPasswordPolicyOptions, policy?.enabled ?? false]; } mapPoliciesFromToken(policiesResponse: ListResponse): Policy[] { if (policiesResponse == null || policiesResponse.data == null) { return null; } const policiesData = policiesResponse.data.map((p) => new PolicyData(p)); return policiesData.map((p) => new Policy(p)); } async policyAppliesToUser( policyType: PolicyType, policyFilter?: (policy: Policy) => boolean, userId?: string ) { const policies = await this.getAll(policyType, userId); const organizations = await this.organizationService.getAll(userId); let filteredPolicies; if (policyFilter != null) { filteredPolicies = policies.filter((p) => p.enabled && policyFilter(p)); } else { filteredPolicies = policies.filter((p) => p.enabled); } const policySet = new Set(filteredPolicies.map((p) => p.organizationId)); return organizations.some( (o) => o.enabled && o.status >= OrganizationUserStatusType.Accepted && o.usePolicies && !this.isExcemptFromPolicies(o, policyType) && policySet.has(o.id) ); } async upsert(policy: PolicyData): Promise { let policies = await this.stateService.getEncryptedPolicies(); if (policies == null) { policies = {}; } policies[policy.id] = policy; await this.stateService.setDecryptedPolicies(null); await this.stateService.setEncryptedPolicies(policies); } async replace(policies: { [id: string]: PolicyData }): Promise { await this.stateService.setDecryptedPolicies(null); await this.stateService.setEncryptedPolicies(policies); } async clear(userId?: string): Promise { await this.stateService.setDecryptedPolicies(null, { userId: userId }); await this.stateService.setEncryptedPolicies(null, { userId: userId }); } private isExcemptFromPolicies(organization: Organization, policyType: PolicyType) { if (policyType === PolicyType.MaximumVaultTimeout) { return organization.type === OrganizationUserType.Owner; } return organization.isExemptFromPolicies; } }