Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโ€™ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PM-14416] Risk Insights - Initial security task service #12446

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
4 changes: 2 additions & 2 deletions libs/common/src/abstractions/api.service.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import {
CollectionRequest,
CollectionAccessDetailsResponse,
CollectionDetailsResponse,
CollectionRequest,
CollectionResponse,
} from "@bitwarden/admin-console/common";

Expand Down Expand Up @@ -137,7 +137,7 @@ import { OptionalCipherResponse } from "../vault/models/response/optional-cipher
*/
export abstract class ApiService {
send: (
method: "GET" | "POST" | "PUT" | "DELETE",
method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH",
path: string,
body: any,
authed: boolean,
Expand Down
1 change: 1 addition & 0 deletions libs/common/src/platform/state/state-definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,3 +182,4 @@ export const NEW_DEVICE_VERIFICATION_NOTICE = new StateDefinition(
"disk",
);
export const VAULT_APPEARANCE = new StateDefinition("vaultAppearance", "disk");
export const SECURITY_TASKS_DISK = new StateDefinition("securityTasks", "disk");
6 changes: 3 additions & 3 deletions libs/common/src/services/api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import { firstValueFrom } from "rxjs";

import {
CollectionRequest,
CollectionAccessDetailsResponse,
CollectionDetailsResponse,
CollectionRequest,
CollectionResponse,
} from "@bitwarden/admin-console/common";
import { LogoutReason } from "@bitwarden/auth/common";
Expand Down Expand Up @@ -1835,7 +1835,7 @@ export class ApiService implements ApiServiceAbstraction {
}

async send(
method: "GET" | "POST" | "PUT" | "DELETE",
method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH",
path: string,
body: any,
authed: boolean,
Expand Down Expand Up @@ -1875,7 +1875,7 @@ export class ApiService implements ApiServiceAbstraction {
return responseJson;
} else if (hasResponse && response.status === 200 && responseIsCsv) {
return await response.text();
} else if (response.status !== 200) {
} else if (response.status !== 200 && response.status !== 204) {
const error = await this.handleError(response, false, authed);
return Promise.reject(error);
}
Expand Down
1 change: 1 addition & 0 deletions libs/common/src/types/guid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export type PolicyId = Opaque<string, "PolicyId">;
export type CipherId = Opaque<string, "CipherId">;
export type SendId = Opaque<string, "SendId">;
export type IndexedEntityId = Opaque<string, "IndexedEntityId">;
export type SecurityTaskId = Opaque<string, "SecurityTaskId">;
2 changes: 2 additions & 0 deletions libs/vault/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ export { DownloadAttachmentComponent } from "./components/download-attachment/do
export { PasswordHistoryViewComponent } from "./components/password-history-view/password-history-view.component";

export * as VaultIcons from "./icons";

export * from "./tasks";
45 changes: 45 additions & 0 deletions libs/vault/src/tasks/abstractions/task.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Observable } from "rxjs";

import { SecurityTaskId, UserId } from "@bitwarden/common/types/guid";
import { SecurityTask } from "@bitwarden/vault";

export abstract class TaskService {
/**
* Observable indicating if tasks are enabled for a given user.
*
* @remarks Internally, this checks the user's organization details to determine if tasks are enabled.
* @param userId
*/
abstract tasksEnabled$(userId: UserId): Observable<boolean>;

/**
* Observable of all tasks for a given user.
* @param userId
*/
abstract tasks$(userId: UserId): Observable<SecurityTask[]>;

/**
* Observable of pending tasks for a given user.
* @param userId
*/
abstract pendingTasks$(userId: UserId): Observable<SecurityTask[]>;

/**
* Retrieves tasks from the API for a given user and updates the local state.
* @param userId
*/
abstract refreshTasks(userId: UserId): Promise<void>;

/**
* Clears all the tasks from state for the given user.
* @param userId
*/
abstract clear(userId: UserId): Promise<void>;

/**
* Marks a task as complete in local state and updates the server.
* @param taskId - The ID of the task to mark as complete.
* @param userId - The user who is completing the task.
*/
abstract markAsComplete(taskId: SecurityTaskId, userId: UserId): Promise<void>;
}
2 changes: 2 additions & 0 deletions libs/vault/src/tasks/enums/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./security-task-status.enum";
export * from "./security-task-type.enum";
11 changes: 11 additions & 0 deletions libs/vault/src/tasks/enums/security-task-status.enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export enum SecurityTaskStatus {
/**
* Default status for newly created tasks that have not been completed.
*/
Pending = 0,

/**
* Status when a task is considered complete and has no remaining actions
*/
Completed = 1,
}
6 changes: 6 additions & 0 deletions libs/vault/src/tasks/enums/security-task-type.enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export enum SecurityTaskType {
/**
* Task to update a cipher's password that was found to be at-risk by an administrator
*/
UpdateAtRiskCredential = 0,
}
5 changes: 5 additions & 0 deletions libs/vault/src/tasks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export * from "./enums";
export * from "./models";

export * from "./abstractions/task.service";
export * from "./services/default-task.service";
1 change: 1 addition & 0 deletions libs/vault/src/tasks/models/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./security-task";
38 changes: 38 additions & 0 deletions libs/vault/src/tasks/models/security-task.data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Jsonify } from "type-fest";

import { CipherId, OrganizationId, SecurityTaskId } from "@bitwarden/common/types/guid";

import { SecurityTaskStatus, SecurityTaskType } from "../enums";

import { SecurityTaskResponse } from "./security-task.response";

export class SecurityTaskData {
id: SecurityTaskId;
organizationId: OrganizationId;
cipherId: CipherId | undefined;
type: SecurityTaskType;
status: SecurityTaskStatus;
creationDate: Date;
revisionDate: Date;

constructor(response?: SecurityTaskResponse) {
if (response == null) {
return;
}

this.id = response.id;
this.organizationId = response.organizationId;
this.cipherId = response.cipherId;
this.type = response.type;
this.status = response.status;
this.creationDate = response.creationDate;
this.revisionDate = response.revisionDate;
}

static fromJSON(obj: Jsonify<SecurityTaskData>) {
return Object.assign(new SecurityTaskData(), obj, {
creationDate: new Date(obj.creationDate),
revisionDate: new Date(obj.revisionDate),
});
}
}
28 changes: 28 additions & 0 deletions libs/vault/src/tasks/models/security-task.response.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { BaseResponse } from "@bitwarden/common/models/response/base.response";
import { CipherId, OrganizationId, SecurityTaskId } from "@bitwarden/common/types/guid";

import { SecurityTaskStatus, SecurityTaskType } from "../enums";

export class SecurityTaskResponse extends BaseResponse {
id: SecurityTaskId;
organizationId: OrganizationId;
/**
* Optional cipherId for tasks that are related to a cipher.
*/
cipherId: CipherId | undefined;
type: SecurityTaskType;
status: SecurityTaskStatus;
creationDate: Date;
revisionDate: Date;

constructor(response: any) {
super(response);
this.id = this.getResponseProperty("Id");
this.organizationId = this.getResponseProperty("OrganizationId");
this.cipherId = this.getResponseProperty("CipherId") || undefined;
this.type = this.getResponseProperty("Type");
this.status = this.getResponseProperty("Status");
this.creationDate = this.getResponseProperty("CreationDate");
this.revisionDate = this.getResponseProperty("RevisionDate");
}
}
32 changes: 32 additions & 0 deletions libs/vault/src/tasks/models/security-task.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { CipherId, OrganizationId, SecurityTaskId } from "@bitwarden/common/types/guid";

import { SecurityTaskStatus, SecurityTaskType } from "../enums";

import { SecurityTaskData } from "./security-task.data";

export class SecurityTask {
id: SecurityTaskId;
organizationId: OrganizationId;
/**
* Optional cipherId for tasks that are related to a cipher.
*/
cipherId: CipherId | undefined;
type: SecurityTaskType;
status: SecurityTaskStatus;
creationDate: Date;
revisionDate: Date;

constructor(obj?: SecurityTaskData) {
if (obj == null) {
return;
}

this.id = obj.id;
this.organizationId = obj.organizationId;
this.cipherId = obj.cipherId;
this.type = obj.type;
this.status = obj.status;
this.creationDate = obj.creationDate;
this.revisionDate = obj.revisionDate;
}
}
Loading
Loading