diff options
author | Elizabeth Alexander Hunt <me@liz.coffee> | 2025-05-12 09:40:12 -0700 |
---|---|---|
committer | Elizabeth <me@liz.coffee> | 2025-05-26 14:15:42 -0700 |
commit | d51c9d74857aca3c2f172609297266968bc7f809 (patch) | |
tree | 64327f9cc4219729aa11af32d7d4c70cddfc2292 /worker/secret | |
parent | 30729a0cf707d9022bae0a7baaba77379dc31fd5 (diff) | |
download | ci-d51c9d74857aca3c2f172609297266968bc7f809.tar.gz ci-d51c9d74857aca3c2f172609297266968bc7f809.zip |
The big refactor TM
Diffstat (limited to 'worker/secret')
-rw-r--r-- | worker/secret/bitwarden.ts | 153 | ||||
-rw-r--r-- | worker/secret/ivault.ts | 24 | ||||
-rw-r--r-- | worker/secret/mod.ts | 2 |
3 files changed, 179 insertions, 0 deletions
diff --git a/worker/secret/bitwarden.ts b/worker/secret/bitwarden.ts new file mode 100644 index 0000000..0172a1b --- /dev/null +++ b/worker/secret/bitwarden.ts @@ -0,0 +1,153 @@ +import { + Either, + getRequiredEnvVars, + getStdout, + type IEither, + type ITraceable, + type LogMetricTraceSupplier, + Metric, + TraceUtil, +} from "@emprespresso/pengueno"; +import type { IVault, SecretItem } from "./mod.ts"; + +type TClient = ITraceable<unknown, LogMetricTraceSupplier>; +type TKey = string; +type TItemId = string; +export class Bitwarden implements IVault<TClient, TKey, TItemId> { + constructor(private readonly config: BitwardenConfig) {} + + public unlock(client: TClient) { + return client.move(this.config) + .bimap(TraceUtil.withMetricTrace(Bitwarden.loginMetric)) + .flatMap((tConfig) => + tConfig.move(`bw config server ${tConfig.get().server}`).map(getStdout) + ) + .map(async (tEitherWithConfig) => { + const eitherWithConfig = await tEitherWithConfig.get(); + tEitherWithConfig.trace.trace("logging in~ ^.^"); + return eitherWithConfig.flatMapAsync((_) => + tEitherWithConfig.move("bw login --apikey --quiet").map(getStdout) + .get() + ); + }) + .peek(async (tEitherWithAuthd) => { + const eitherWithAuthd = await tEitherWithAuthd.get(); + return tEitherWithAuthd.trace.trace( + eitherWithAuthd.fold((err, _val) => + Bitwarden.loginMetric[err ? "failure" : "success"] + ), + ); + }) + .map(async (tEitherWithAuthd) => { + const eitherWithAuthd = await tEitherWithAuthd.get(); + tEitherWithAuthd.trace.trace("unlocking the secret vault~ (◕ᴗ◕✿)"); + return eitherWithAuthd.flatMapAsync((_) => + tEitherWithAuthd.move("bw unlock --passwordenv BW_PASSWORD --raw") + .map(getStdout) + .get() + ); + }) + .peek(async (tEitherWithSession) => { + const eitherWithAuthd = await tEitherWithSession.get(); + return tEitherWithSession.trace.trace( + eitherWithAuthd.fold((err, _val) => + Bitwarden.unlockVaultMetric[err ? "failure" : "success"] + ), + ); + }) + .get(); + } + + public fetchSecret<T extends SecretItem>( + client: TClient, + key: string, + item: string, + ): Promise<IEither<Error, T>> { + return client.move(key) + .bimap(TraceUtil.withMetricTrace(Bitwarden.fetchSecretMetric)) + .peek((tSession) => + tSession.trace.trace(`looking for your secret ${item} (⑅˘꒳˘)`) + ) + .flatMap((tSession) => + tSession.move("bw list items").map((listCmd) => + getStdout(listCmd, { env: { BW_SESSION: tSession.get() } }) + ) + ) + .map( + TraceUtil.promiseify((tEitherItemsJson) => + tEitherItemsJson.get() + .flatMap((itemsJson): IEither<Error, Array<T & { name: string }>> => + Either.fromFailable(() => JSON.parse(itemsJson)) + ) + .flatMap((itemsList): IEither<Error, T> => { + const secret = itemsList.find(({ name }) => name === item); + if (!secret) { + return Either.left( + new Error(`couldn't find the item ${item} (。•́︿•̀。)`), + ); + } + return Either.right(secret); + }) + ), + ) + .peek(async (tEitherWithSecret) => { + const eitherWithSecret = await tEitherWithSecret.get(); + return tEitherWithSecret.trace.trace( + eitherWithSecret.fold((err, _val) => + Bitwarden.fetchSecretMetric[err ? "failure" : "success"] + ), + ); + }) + .get(); + } + + public lock(client: TClient, key: TKey) { + return client.move(key) + .bimap(TraceUtil.withMetricTrace(Bitwarden.lockVaultMetric)) + .peek((tSession) => + tSession.trace.trace(`taking care of locking the vault :3`) + ) + .flatMap((tSession) => + tSession.move("bw lock").map((lockCmd) => + getStdout(lockCmd, { env: { BW_SESSION: tSession.get() } }) + ) + ) + .peek(async (tEitherWithLocked) => { + const eitherWithLocked = await tEitherWithLocked.get(); + return eitherWithLocked.fold((err, _val) => { + tEitherWithLocked.trace.trace( + Bitwarden.lockVaultMetric[err ? "failure" : "success"], + ); + if (err) return; + tEitherWithLocked.trace.trace( + "all locked up and secure now~ (。•̀ᴗ-)✧", + ); + }); + }) + .get(); + } + + public static getConfigFromEnvironment(): IEither<Error, BitwardenConfig> { + return getRequiredEnvVars([ + "BW_SERVER", + "BW_CLIENTSECRET", + "BW_CLIENTID", + "BW_PASSWORD", + ]).mapRight(({ BW_SERVER, BW_CLIENTSECRET, BW_CLIENTID }) => ({ + clientId: BW_CLIENTID, + secret: BW_CLIENTSECRET, + server: BW_SERVER, + })); + } + + private static loginMetric = Metric.fromName("Bitwarden.login"); + private static unlockVaultMetric = Metric.fromName("Bitwarden.unlockVault"); + private static fetchSecretMetric = Metric.fromName("Bitwarden.fetchSecret"); + private static lockVaultMetric = Metric.fromName("Bitwarden.lock"); +} + +export interface BitwardenConfig { + server: string; + secret: string; + clientId: string; +} diff --git a/worker/secret/ivault.ts b/worker/secret/ivault.ts new file mode 100644 index 0000000..e101e56 --- /dev/null +++ b/worker/secret/ivault.ts @@ -0,0 +1,24 @@ +import type { IEither } from "@emprespresso/pengueno"; + +export interface LoginItem { + login: { + username: string; + password: string; + }; +} + +export interface SecureNote { + notes: string; +} + +export type SecretItem = LoginItem | SecureNote; +export interface IVault<TClient, TKey, TItemId> { + unlock: (client: TClient) => Promise<IEither<Error, TKey>>; + lock: (client: TClient, key: TKey) => Promise<IEither<Error, TKey>>; + + fetchSecret: <T extends SecretItem>( + client: TClient, + key: TKey, + item: TItemId, + ) => Promise<IEither<Error, T>>; +} diff --git a/worker/secret/mod.ts b/worker/secret/mod.ts new file mode 100644 index 0000000..70a1ea9 --- /dev/null +++ b/worker/secret/mod.ts @@ -0,0 +1,2 @@ +export * from "./ivault.ts"; +export * from "./bitwarden.ts"; |