From 0d78bc48aec3c53270668cfa4c4baaef2b624ec1 Mon Sep 17 00:00:00 2001 From: Julien Oculi Date: Mon, 13 May 2024 17:01:17 +0200 Subject: [PATCH] feat(model): :sparkles: add `credential` model --- src/models/src/credential.ts | 103 +++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 src/models/src/credential.ts diff --git a/src/models/src/credential.ts b/src/models/src/credential.ts new file mode 100644 index 0000000..5711ade --- /dev/null +++ b/src/models/src/credential.ts @@ -0,0 +1,103 @@ +import { ToJson } from '@/types.ts' +import { Ressource } from '@models/ressource.ts' + +export class Credential extends Ressource { + static fromJSON( + json: ToJson, + ): Credential { + return new Credential(json) + } + + static create( + { category, store, name }: Pick, + ): Credential { + const { uuid, createdAt, updatedAt } = super.create({ name }) + return new Credential({ uuid, createdAt, updatedAt, name, category, store }) + } + + #category: 'password' | 'ssh' | 'passkey' + #store: CredentialCategory + + private constructor( + { category, store, ...props }: + & Pick + & Pick, + ) { + super(props) + + if (!['password', 'ssh', 'passkey'].includes(category)) { + throw new TypeError( + `category is "${category}" but ('password' | 'ssh' | 'passkey') is required`, + ) + } + this.#category = category + this.#store = Object.freeze(store) + } + + get type(): 'credential' { + return 'credential' + } + + get category() { + return this.#category + } + + get store() { + return Object.freeze(this.#store) + } + + update( + props: Partial>, + ): Credential { + const { updatedAt } = super.update(props) + const credential = new Credential({ ...this, ...props, updatedAt }) + return credential + } + + toJSON() { + return { + ...super.toJSON(), + type: this.type, + category: this.category, + store: Object.freeze(this.store), + } as const + } + + toString(): string { + return `Credential (${JSON.stringify(this)})` + } +} + +export interface Credential extends Ressource { + type: 'credential' + category: 'password' | 'ssh' | 'passkey' + store: Readonly> +} + +type CredentialCategory = T extends + 'password' ? { + store: { + hash: Uint8Array + alg: string + salt: Uint8Array + } + } + : T extends 'ssh' ? { + store: { + publicKey: string + } + } + : T extends 'passkey' ? { + store: Record + } + : never + +/* +PassKey store: +{ + publicKey: Uint8Array + keyId: string + transport: string + counter: number +} +*/