import { PolicyService as PolicyServiceAbstraction } from '../abstractions/policy.service'; import { StorageService } from '../abstractions/storage.service'; import { UserService } from '../abstractions/user.service'; import { PolicyData } from '../models/data/policyData'; import { MasterPasswordPolicyOptions } from '../models/domain/masterPasswordPolicyOptions'; import { Policy } from '../models/domain/policy'; import { PolicyType } from '../enums/policyType'; const Keys = { policiesPrefix: 'policies_', }; export class PolicyService implements PolicyServiceAbstraction { policyCache: Policy[]; constructor(private userService: UserService, private storageService: StorageService) { } clearCache(): void { this.policyCache = null; } async getAll(type?: PolicyType): Promise { if (this.policyCache == null) { const userId = await this.userService.getUserId(); const policies = await this.storageService.get<{ [id: string]: PolicyData; }>( Keys.policiesPrefix + userId); const response: Policy[] = []; for (const id in policies) { if (policies.hasOwnProperty(id)) { response.push(new Policy(policies[id])); } } this.policyCache = response; } if (type != null) { return this.policyCache.filter((p) => p.type === type); } else { return this.policyCache; } } async replace(policies: { [id: string]: PolicyData; }): Promise { const userId = await this.userService.getUserId(); await this.storageService.save(Keys.policiesPrefix + userId, policies); this.policyCache = null; } async clear(userId: string): Promise { await this.storageService.remove(Keys.policiesPrefix + userId); this.policyCache = null; } 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; } if (enforcedPolicyOptions.requireSpecial && !(/[!@#$%\^&*]/g.test(newPassword))) { return false; } return true; } }