mirror of
https://github.com/bitwarden/browser
synced 2026-02-10 13:40:06 +00:00
input and output definitions
This commit is contained in:
0
libs/common/src/tools/achievements/event-store.ts
Normal file
0
libs/common/src/tools/achievements/event-store.ts
Normal file
104
libs/common/src/tools/achievements/events.ts
Normal file
104
libs/common/src/tools/achievements/events.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import { of } from "rxjs";
|
||||
|
||||
const itemAdded$ = of({
|
||||
"@timestamp": Date.now(),
|
||||
user: {
|
||||
id: "1E2EDBC3-4449-4583-A4AC-ACDFA5C2EC71",
|
||||
},
|
||||
event: {
|
||||
kind: "event",
|
||||
category: "session",
|
||||
type: "creation",
|
||||
outcome: "success",
|
||||
provider: "vault",
|
||||
},
|
||||
service: {
|
||||
name: "chrome-extension",
|
||||
type: "client",
|
||||
node: { name: "commotion-amused-rinse-trivial-sadly" },
|
||||
environment: "production",
|
||||
version: "37899",
|
||||
},
|
||||
transaction: { id: "00f067aa0ba902b7" },
|
||||
action: "vault-item-added",
|
||||
labels: { "vault-item-type": "login", "vault-item-uri-quantity": 1 },
|
||||
tags: ["with-attachment"],
|
||||
});
|
||||
|
||||
const itemUpdated$ = of({
|
||||
"@timestamp": Date.now(),
|
||||
user: {
|
||||
id: "1E2EDBC3-4449-4583-A4AC-ACDFA5C2EC71",
|
||||
},
|
||||
event: {
|
||||
kind: "event",
|
||||
category: "session",
|
||||
type: "creation",
|
||||
outcome: "success",
|
||||
provider: "bitwarden-chrome-extension",
|
||||
},
|
||||
service: {
|
||||
name: "chrome-extension",
|
||||
type: "client",
|
||||
node: { name: "commotion-amused-rinse-trivial-sadly" },
|
||||
environment: "production",
|
||||
version: "37899",
|
||||
},
|
||||
transaction: { id: "00f067aa0ba902b8" },
|
||||
action: "vault-item-updated",
|
||||
labels: { "vault-item-type": "login", "uri-quantity": 1 },
|
||||
tags: ["with-folder"],
|
||||
});
|
||||
|
||||
const itemMovedToCollection$ = of(
|
||||
{
|
||||
"@timestamp": Date.now(),
|
||||
user: {
|
||||
id: "1E2EDBC3-4449-4583-A4AC-ACDFA5C2EC71",
|
||||
},
|
||||
event: {
|
||||
kind: "event",
|
||||
category: "session",
|
||||
type: "deletion",
|
||||
outcome: "success",
|
||||
provider: "bitwarden-chrome-extension",
|
||||
},
|
||||
service: {
|
||||
name: "chrome-extension",
|
||||
type: "client",
|
||||
node: { name: "commotion-amused-rinse-trivial-sadly" },
|
||||
environment: "production",
|
||||
version: "37899",
|
||||
},
|
||||
transaction: { id: "00f067aa0ba902b9" },
|
||||
action: "vault-item-moved",
|
||||
labels: { "vault-item-type": "login", "uri-quantity": 1 },
|
||||
tags: ["collection"],
|
||||
},
|
||||
{
|
||||
"@timestamp": Date.now(),
|
||||
user: {
|
||||
id: "1E2EDBC3-4449-4583-A4AC-ACDFA5C2EC71",
|
||||
},
|
||||
event: {
|
||||
kind: "event",
|
||||
category: "session",
|
||||
type: "info",
|
||||
outcome: "success",
|
||||
provider: "bitwarden-chrome-extension",
|
||||
},
|
||||
service: {
|
||||
name: "chrome-extension",
|
||||
type: "client",
|
||||
node: { name: "commotion-amused-rinse-trivial-sadly" },
|
||||
environment: "production",
|
||||
version: "37899",
|
||||
},
|
||||
transaction: { id: "00f067aa0ba902b9" },
|
||||
action: "vault-item-moved",
|
||||
labels: { "vault-item-type": "login", "uri-quantity": 1 },
|
||||
tags: ["collection"],
|
||||
},
|
||||
);
|
||||
|
||||
export { itemAdded$, itemUpdated$, itemMovedToCollection$ };
|
||||
28
libs/common/src/tools/achievements/inputs.ts
Normal file
28
libs/common/src/tools/achievements/inputs.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Subject } from "rxjs";
|
||||
|
||||
import { EventFormat } from "../log/ecs-format";
|
||||
|
||||
import { Achievement, AchievementFormat, AchievementWatch } from "./types";
|
||||
|
||||
// sync data from the server (consumed by event store)
|
||||
const replicationIn$ = new Subject<AchievementFormat>();
|
||||
|
||||
// data incoming from the UI (consumed by validator)
|
||||
const userActionIn$ = new Subject<EventFormat>();
|
||||
|
||||
// what to look for (consumed by validator)
|
||||
const achievementMonitors$ = new Subject<AchievementWatch>();
|
||||
|
||||
// data stored in local state (consumed by validator and achievement list)
|
||||
const achievementsLocal$ = new Subject<AchievementFormat>();
|
||||
|
||||
// metadata (consumed by achievement list)
|
||||
const achievementMetadata$ = new Subject<Achievement>();
|
||||
|
||||
export {
|
||||
replicationIn$,
|
||||
userActionIn$,
|
||||
achievementsLocal$,
|
||||
achievementMonitors$,
|
||||
achievementMetadata$,
|
||||
};
|
||||
32
libs/common/src/tools/achievements/types.ts
Normal file
32
libs/common/src/tools/achievements/types.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { RequireAtLeastOne } from "type-fest";
|
||||
import { Tagged } from "type-fest/source/opaque";
|
||||
|
||||
import { EcsFormat, EventFormat } from "../log/ecs-format";
|
||||
|
||||
export type AchievementId = string & Tagged<"achievement">;
|
||||
|
||||
type Progress = { type: "progress"; name: AchievementId; value: number };
|
||||
type Earned = { type: "earned"; name: AchievementId };
|
||||
export type AchievementFormat = EcsFormat & EventFormat & { achievement: Progress | Earned };
|
||||
|
||||
// consumed by validator and achievement list (should this include a "toast-alerter"?)
|
||||
export type Achievement = {
|
||||
achievement: AchievementId;
|
||||
|
||||
// pre-filter that disables the rule if it's met
|
||||
trigger: "once" | RequireAtLeastOne<{ low: number; high: number }>;
|
||||
|
||||
hidden: boolean;
|
||||
};
|
||||
|
||||
// consumed by validator
|
||||
export type AchievementWatch = Achievement & {
|
||||
// when the watch triggers on incoming user events
|
||||
filter: (item: EventFormat) => boolean;
|
||||
|
||||
// what to do when an incoming event is triggered
|
||||
action: (
|
||||
item: EventFormat,
|
||||
progress?: AchievementFormat,
|
||||
) => [AchievementFormat] | [AchievementFormat, AchievementFormat];
|
||||
};
|
||||
@@ -1,22 +1,35 @@
|
||||
import { Primitive } from "type-fest";
|
||||
|
||||
/** Elastic Common Schema log format - core fields.
|
||||
*/
|
||||
export interface EcsFormat {
|
||||
"@timestamp": Date,
|
||||
"@timestamp": Date;
|
||||
|
||||
/** custom key/value pairs */
|
||||
labels?: Record<string, string>,
|
||||
labels?: Record<string, Primitive>;
|
||||
|
||||
/** system message related to the event */
|
||||
message?: string,
|
||||
/** system message related to the event (for humans) */
|
||||
message?: string;
|
||||
|
||||
/** keywords tagging the event */
|
||||
tags?: Array<string>,
|
||||
tags?: Array<string>;
|
||||
|
||||
/** describe the event; it is recommended that all events have these. */
|
||||
event: {
|
||||
kind?: "alert" | "enrichment" | "event" | "metric" | "state",
|
||||
category?: "api" | "authentication" | "iam" | "process" | "session" ,
|
||||
type?: "access" | "admin" | "allowed" | "creation" | "deletion" | "denied" | "end" | "error" | "info" | "start" | "user",
|
||||
outcome?: "failure" | "success" | "unknown",
|
||||
}
|
||||
};
|
||||
kind?: "alert" | "enrichment" | "event" | "metric" | "state";
|
||||
category?: "api" | "authentication" | "iam" | "process" | "session";
|
||||
type?:
|
||||
| "access"
|
||||
| "admin"
|
||||
| "allowed"
|
||||
| "creation"
|
||||
| "deletion"
|
||||
| "denied"
|
||||
| "end"
|
||||
| "error"
|
||||
| "info"
|
||||
| "start"
|
||||
| "user";
|
||||
outcome?: "failure" | "success" | "unknown";
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user