1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-14 07:13:32 +00:00

[EC-376] Extract API logic from PolicyService to PolicyApiService (#3203)

* Added abstractions for PolicyApiService and PolicyService

* Added implementations for PolicyApiService and PolicyService

* Updated all references to new PolicyApiService and PolicyService

* Deleted old PolicyService abstraction and implementation

* Fixed CLI import path for policy.service

* Fixed main.background.ts policyApiService dependency for policyService

* Updated policy-api.service with the correct imports

* [EC-376] Sorted methods order in PolicyApiService

* [EC-376] Removed unused clearCache method from PolicyService

* [EC-376] Added upsert method to PolicyService

* [EC-376] PolicyApiService putPolicy method now upserts data to PolicyService
This commit is contained in:
Rui Tomé
2022-08-08 10:04:36 +01:00
committed by GitHub
parent 5f13c4722f
commit c263eacd88
73 changed files with 348 additions and 265 deletions

View File

@@ -1,6 +1,5 @@
import { OrganizationApiKeyType } from "../enums/organizationApiKeyType";
import { OrganizationConnectionType } from "../enums/organizationConnectionType";
import { PolicyType } from "../enums/policyType";
import { SetKeyConnectorKeyRequest } from "../models/request/account/setKeyConnectorKeyRequest";
import { VerifyOTPRequest } from "../models/request/account/verifyOTPRequest";
import { AttachmentRequest } from "../models/request/attachmentRequest";
@@ -59,7 +58,6 @@ import { OrganizationUserUpdateRequest } from "../models/request/organizationUse
import { PasswordHintRequest } from "../models/request/passwordHintRequest";
import { PasswordRequest } from "../models/request/passwordRequest";
import { PaymentRequest } from "../models/request/paymentRequest";
import { PolicyRequest } from "../models/request/policyRequest";
import { PreloginRequest } from "../models/request/preloginRequest";
import { ProviderAddOrganizationRequest } from "../models/request/provider/providerAddOrganizationRequest";
import { ProviderOrganizationCreateRequest } from "../models/request/provider/providerOrganizationCreateRequest";
@@ -366,24 +364,6 @@ export abstract class ApiService {
deleteGroup: (organizationId: string, id: string) => Promise<any>;
deleteGroupUser: (organizationId: string, id: string, organizationUserId: string) => Promise<any>;
getPolicy: (organizationId: string, type: PolicyType) => Promise<PolicyResponse>;
getPolicies: (organizationId: string) => Promise<ListResponse<PolicyResponse>>;
getPoliciesByToken: (
organizationId: string,
token: string,
email: string,
organizationUserId: string
) => Promise<ListResponse<PolicyResponse>>;
getPoliciesByInvitedUser: (
organizationId: string,
userId: string
) => Promise<ListResponse<PolicyResponse>>;
putPolicy: (
organizationId: string,
type: PolicyType,
request: PolicyRequest
) => Promise<PolicyResponse>;
getOrganizationUser: (
organizationId: string,
id: string

View File

@@ -0,0 +1,24 @@
import { PolicyType } from "@bitwarden/common/enums/policyType";
import { MasterPasswordPolicyOptions } from "@bitwarden/common/models/domain/masterPasswordPolicyOptions";
import { Policy } from "@bitwarden/common/models/domain/policy";
import { PolicyRequest } from "@bitwarden/common/models/request/policyRequest";
import { ListResponse } from "@bitwarden/common/models/response/listResponse";
import { PolicyResponse } from "@bitwarden/common/models/response/policyResponse";
export class PolicyApiServiceAbstraction {
getPolicy: (organizationId: string, type: PolicyType) => Promise<PolicyResponse>;
getPolicies: (organizationId: string) => Promise<ListResponse<PolicyResponse>>;
getPoliciesByToken: (
organizationId: string,
token: string,
email: string,
organizationUserId: string
) => Promise<ListResponse<PolicyResponse>>;
getPoliciesByInvitedUser: (
organizationId: string,
userId: string
) => Promise<ListResponse<PolicyResponse>>;
getPolicyForOrganization: (policyType: PolicyType, organizationId: string) => Promise<Policy>;
getMasterPasswordPoliciesForInvitedUsers: (orgId: string) => Promise<MasterPasswordPolicyOptions>;
putPolicy: (organizationId: string, type: PolicyType, request: PolicyRequest) => Promise<any>;
}

View File

@@ -1,18 +1,14 @@
import { PolicyType } from "../enums/policyType";
import { PolicyData } from "../models/data/policyData";
import { MasterPasswordPolicyOptions } from "../models/domain/masterPasswordPolicyOptions";
import { Policy } from "../models/domain/policy";
import { ResetPasswordPolicyOptions } from "../models/domain/resetPasswordPolicyOptions";
import { ListResponse } from "../models/response/listResponse";
import { PolicyResponse } from "../models/response/policyResponse";
import { PolicyType } from "../../enums/policyType";
import { PolicyData } from "../../models/data/policyData";
import { MasterPasswordPolicyOptions } from "../../models/domain/masterPasswordPolicyOptions";
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 abstract class PolicyService {
clearCache: () => void;
getAll: (type?: PolicyType, userId?: string) => Promise<Policy[]>;
getPolicyForOrganization: (policyType: PolicyType, organizationId: string) => Promise<Policy>;
replace: (policies: { [id: string]: PolicyData }) => Promise<any>;
clear: (userId?: string) => Promise<any>;
getMasterPasswordPoliciesForInvitedUsers: (orgId: string) => Promise<MasterPasswordPolicyOptions>;
getMasterPasswordPolicyOptions: (policies?: Policy[]) => Promise<MasterPasswordPolicyOptions>;
evaluateMasterPassword: (
passwordStrength: number,
@@ -30,3 +26,9 @@ export abstract class PolicyService {
userId?: string
) => Promise<boolean>;
}
export abstract class InternalPolicyService extends PolicyService {
upsert: (policy: PolicyData) => Promise<any>;
replace: (policies: { [id: string]: PolicyData }) => Promise<any>;
clear: (userId?: string) => Promise<any>;
}

View File

@@ -6,7 +6,6 @@ import { TokenService } from "../abstractions/token.service";
import { DeviceType } from "../enums/deviceType";
import { OrganizationApiKeyType } from "../enums/organizationApiKeyType";
import { OrganizationConnectionType } from "../enums/organizationConnectionType";
import { PolicyType } from "../enums/policyType";
import { Utils } from "../misc/utils";
import { SetKeyConnectorKeyRequest } from "../models/request/account/setKeyConnectorKeyRequest";
import { VerifyOTPRequest } from "../models/request/account/verifyOTPRequest";
@@ -67,7 +66,6 @@ import { OrganizationUserUpdateRequest } from "../models/request/organizationUse
import { PasswordHintRequest } from "../models/request/passwordHintRequest";
import { PasswordRequest } from "../models/request/passwordRequest";
import { PaymentRequest } from "../models/request/paymentRequest";
import { PolicyRequest } from "../models/request/policyRequest";
import { PreloginRequest } from "../models/request/preloginRequest";
import { ProviderAddOrganizationRequest } from "../models/request/provider/providerAddOrganizationRequest";
import { ProviderOrganizationCreateRequest } from "../models/request/provider/providerOrganizationCreateRequest";
@@ -1024,83 +1022,6 @@ export class ApiService implements ApiServiceAbstraction {
);
}
// Policy APIs
async getPolicy(organizationId: string, type: PolicyType): Promise<PolicyResponse> {
const r = await this.send(
"GET",
"/organizations/" + organizationId + "/policies/" + type,
null,
true,
true
);
return new PolicyResponse(r);
}
async getPolicies(organizationId: string): Promise<ListResponse<PolicyResponse>> {
const r = await this.send(
"GET",
"/organizations/" + organizationId + "/policies",
null,
true,
true
);
return new ListResponse(r, PolicyResponse);
}
async getPoliciesByToken(
organizationId: string,
token: string,
email: string,
organizationUserId: string
): Promise<ListResponse<PolicyResponse>> {
const r = await this.send(
"GET",
"/organizations/" +
organizationId +
"/policies/token?" +
"token=" +
encodeURIComponent(token) +
"&email=" +
encodeURIComponent(email) +
"&organizationUserId=" +
organizationUserId,
null,
false,
true
);
return new ListResponse(r, PolicyResponse);
}
async getPoliciesByInvitedUser(
organizationId: string,
userId: string
): Promise<ListResponse<PolicyResponse>> {
const r = await this.send(
"GET",
"/organizations/" + organizationId + "/policies/invited-user?" + "userId=" + userId,
null,
false,
true
);
return new ListResponse(r, PolicyResponse);
}
async putPolicy(
organizationId: string,
type: PolicyType,
request: PolicyRequest
): Promise<PolicyResponse> {
const r = await this.send(
"PUT",
"/organizations/" + organizationId + "/policies/" + type,
request,
true,
true
);
return new PolicyResponse(r);
}
// Organization User APIs
async getOrganizationUser(

View File

@@ -2,7 +2,7 @@ import * as zxcvbn from "zxcvbn";
import { CryptoService } from "../abstractions/crypto.service";
import { PasswordGenerationService as PasswordGenerationServiceAbstraction } from "../abstractions/passwordGeneration.service";
import { PolicyService } from "../abstractions/policy.service";
import { PolicyService } from "../abstractions/policy/policy.service.abstraction";
import { StateService } from "../abstractions/state.service";
import { PolicyType } from "../enums/policyType";
import { EEFLongWordList } from "../misc/wordlist";

View File

@@ -0,0 +1,120 @@
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { OrganizationService } from "@bitwarden/common/abstractions/organization.service";
import { PolicyApiServiceAbstraction } from "@bitwarden/common/abstractions/policy/policy-api.service.abstraction";
import { InternalPolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction";
import { StateService } from "@bitwarden/common/abstractions/state.service";
import { PolicyType } from "@bitwarden/common/enums/policyType";
import { PolicyData } from "@bitwarden/common/models/data/policyData";
import { MasterPasswordPolicyOptions } from "@bitwarden/common/models/domain/masterPasswordPolicyOptions";
import { Policy } from "@bitwarden/common/models/domain/policy";
import { PolicyRequest } from "@bitwarden/common/models/request/policyRequest";
import { ListResponse } from "@bitwarden/common/models/response/listResponse";
import { PolicyResponse } from "@bitwarden/common/models/response/policyResponse";
export class PolicyApiService implements PolicyApiServiceAbstraction {
constructor(
private policyService: InternalPolicyService,
private apiService: ApiService,
private stateService: StateService,
private organizationService: OrganizationService
) {}
async getPolicy(organizationId: string, type: PolicyType): Promise<PolicyResponse> {
const r = await this.apiService.send(
"GET",
"/organizations/" + organizationId + "/policies/" + type,
null,
true,
true
);
return new PolicyResponse(r);
}
async getPolicies(organizationId: string): Promise<ListResponse<PolicyResponse>> {
const r = await this.apiService.send(
"GET",
"/organizations/" + organizationId + "/policies",
null,
true,
true
);
return new ListResponse(r, PolicyResponse);
}
async getPoliciesByToken(
organizationId: string,
token: string,
email: string,
organizationUserId: string
): Promise<ListResponse<PolicyResponse>> {
const r = await this.apiService.send(
"GET",
"/organizations/" +
organizationId +
"/policies/token?" +
"token=" +
encodeURIComponent(token) +
"&email=" +
encodeURIComponent(email) +
"&organizationUserId=" +
organizationUserId,
null,
false,
true
);
return new ListResponse(r, PolicyResponse);
}
async getPoliciesByInvitedUser(
organizationId: string,
userId: string
): Promise<ListResponse<PolicyResponse>> {
const r = await this.apiService.send(
"GET",
"/organizations/" + organizationId + "/policies/invited-user?" + "userId=" + userId,
null,
false,
true
);
return new ListResponse(r, PolicyResponse);
}
async getPolicyForOrganization(policyType: PolicyType, organizationId: string): Promise<Policy> {
const org = await this.organizationService.get(organizationId);
if (org?.isProviderUser) {
const orgPolicies = await this.getPolicies(organizationId);
const policy = orgPolicies.data.find((p) => p.organizationId === organizationId);
if (policy == null) {
return null;
}
return new Policy(new PolicyData(policy));
}
const policies = await this.policyService.getAll(policyType);
return policies.find((p) => p.organizationId === organizationId);
}
async getMasterPasswordPoliciesForInvitedUsers(
orgId: string
): Promise<MasterPasswordPolicyOptions> {
const userId = await this.stateService.getUserId();
const response = await this.getPoliciesByInvitedUser(orgId, userId);
const policies = await this.policyService.mapPoliciesFromToken(response);
return this.policyService.getMasterPasswordPolicyOptions(policies);
}
async putPolicy(organizationId: string, type: PolicyType, request: PolicyRequest): Promise<any> {
const r = await this.apiService.send(
"PUT",
"/organizations/" + organizationId + "/policies/" + type,
request,
true,
true
);
const response = new PolicyResponse(r);
const data = new PolicyData(response);
await this.policyService.upsert(data);
}
}

View File

@@ -1,31 +1,25 @@
import { ApiService } from "../abstractions/api.service";
import { OrganizationService } from "../abstractions/organization.service";
import { PolicyService as PolicyServiceAbstraction } from "../abstractions/policy.service";
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";
import { OrganizationService } from "../../abstractions/organization.service";
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 PolicyServiceAbstraction {
export class PolicyService implements InternalPolicyServiceAbstraction {
policyCache: Policy[];
constructor(
private stateService: StateService,
private organizationService: OrganizationService,
private apiService: ApiService
private organizationService: OrganizationService
) {}
async clearCache(): Promise<void> {
await this.stateService.setDecryptedPolicies(null);
}
async getAll(type?: PolicyType, userId?: string): Promise<Policy[]> {
let response: Policy[] = [];
const decryptedPolicies = await this.stateService.getDecryptedPolicies({ userId: userId });
@@ -48,42 +42,6 @@ export class PolicyService implements PolicyServiceAbstraction {
}
}
async getPolicyForOrganization(policyType: PolicyType, organizationId: string): Promise<Policy> {
const org = await this.organizationService.get(organizationId);
if (org?.isProviderUser) {
const orgPolicies = await this.apiService.getPolicies(organizationId);
const policy = orgPolicies.data.find((p) => p.organizationId === organizationId);
if (policy == null) {
return null;
}
return new Policy(new PolicyData(policy));
}
const policies = await this.getAll(policyType);
return policies.find((p) => p.organizationId === organizationId);
}
async replace(policies: { [id: string]: PolicyData }): Promise<any> {
await this.stateService.setDecryptedPolicies(null);
await this.stateService.setEncryptedPolicies(policies);
}
async clear(userId?: string): Promise<any> {
await this.stateService.setDecryptedPolicies(null, { userId: userId });
await this.stateService.setEncryptedPolicies(null, { userId: userId });
}
async getMasterPasswordPoliciesForInvitedUsers(
orgId: string
): Promise<MasterPasswordPolicyOptions> {
const userId = await this.stateService.getUserId();
const response = await this.apiService.getPoliciesByInvitedUser(orgId, userId);
const policies = await this.mapPoliciesFromToken(response);
return this.getMasterPasswordPolicyOptions(policies);
}
async getMasterPasswordPolicyOptions(policies?: Policy[]): Promise<MasterPasswordPolicyOptions> {
let enforcedOptions: MasterPasswordPolicyOptions = null;
@@ -237,6 +195,28 @@ export class PolicyService implements PolicyServiceAbstraction {
);
}
async upsert(policy: PolicyData): Promise<any> {
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<any> {
await this.stateService.setDecryptedPolicies(null);
await this.stateService.setEncryptedPolicies(policies);
}
async clear(userId?: string): Promise<any> {
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;

View File

@@ -8,7 +8,7 @@ import { KeyConnectorService } from "../abstractions/keyConnector.service";
import { LogService } from "../abstractions/log.service";
import { MessagingService } from "../abstractions/messaging.service";
import { OrganizationService } from "../abstractions/organization.service";
import { PolicyService } from "../abstractions/policy.service";
import { InternalPolicyService } from "../abstractions/policy/policy.service.abstraction";
import { ProviderService } from "../abstractions/provider.service";
import { SendService } from "../abstractions/send.service";
import { SettingsService } from "../abstractions/settings.service";
@@ -46,7 +46,7 @@ export class SyncService implements SyncServiceAbstraction {
private cryptoService: CryptoService,
private collectionService: CollectionService,
private messagingService: MessagingService,
private policyService: PolicyService,
private policyService: InternalPolicyService,
private sendService: SendService,
private logService: LogService,
private keyConnectorService: KeyConnectorService,

View File

@@ -6,7 +6,7 @@ import { FolderService } from "../abstractions/folder/folder.service.abstraction
import { KeyConnectorService } from "../abstractions/keyConnector.service";
import { MessagingService } from "../abstractions/messaging.service";
import { PlatformUtilsService } from "../abstractions/platformUtils.service";
import { PolicyService } from "../abstractions/policy.service";
import { PolicyService } from "../abstractions/policy/policy.service.abstraction";
import { SearchService } from "../abstractions/search.service";
import { StateService } from "../abstractions/state.service";
import { TokenService } from "../abstractions/token.service";