summaryrefslogtreecommitdiff
path: root/worker/secret.ts
diff options
context:
space:
mode:
Diffstat (limited to 'worker/secret.ts')
-rw-r--r--worker/secret.ts83
1 files changed, 41 insertions, 42 deletions
diff --git a/worker/secret.ts b/worker/secret.ts
index 30316bd..11daf06 100644
--- a/worker/secret.ts
+++ b/worker/secret.ts
@@ -2,12 +2,16 @@ import {
Either,
getRequiredEnvVars,
getStdout,
+ getStdoutMany,
type IEither,
type ITraceable,
type LogMetricTraceSupplier,
Metric,
TraceUtil,
} from '@emprespresso/pengueno';
+import { randomUUID } from 'node:crypto';
+import { mkdirSync } from 'node:fs';
+import path from 'node:path';
// -- <ISecret> --
export interface SecretItem {
@@ -35,55 +39,51 @@ export interface IVault<TClient, TKey, TItemId> {
// -- <Vault> --
type TClient = ITraceable<unknown, LogMetricTraceSupplier>;
-type TKey = string;
+type TKey = {
+ BW_SESSION: string;
+ BITWARDENCLI_APPDATA_DIR: string;
+};
type TItemId = string;
export class Bitwarden implements IVault<TClient, TKey, TItemId> {
constructor(private readonly config: BitwardenConfig) {}
public unlock(client: TClient) {
- const authed = client
+ return client
.move(this.config)
.flatMap(TraceUtil.withMetricTrace(Bitwarden.loginMetric))
- .flatMap((tConfig) => tConfig.move(`bw config server ${tConfig.get().server}`).map(getStdout))
- .map(async (tEitherWithConfig) => {
- const eitherWithConfig = await tEitherWithConfig.get();
- return eitherWithConfig.flatMapAsync((_) =>
- tEitherWithConfig
- .peek((t) => t.trace.trace('logging in~ ^.^'))
- .move('bw login --apikey --quiet')
- .map(getStdout)
- .get(),
- );
- })
- .peek(TraceUtil.promiseify(TraceUtil.traceResultingEither(Bitwarden.loginMetric)));
- const unlocked = authed
- .flatMap(TraceUtil.withMetricTrace(Bitwarden.unlockVaultMetric))
- .map(async (tEitherWithAuthd) => {
- const eitherWithAuthd = await tEitherWithAuthd.get();
- return eitherWithAuthd.flatMapAsync((_) =>
- tEitherWithAuthd
- .peek((t) => t.trace.trace('unlocking the secret vault~ (◕ᴗ◕✿)'))
- .move('bw unlock --passwordenv BW_PASSWORD --raw')
- .map(getStdout)
- .get(),
- );
- })
- .peek(TraceUtil.promiseify(TraceUtil.traceResultingEither(Bitwarden.unlockVaultMetric)));
- return unlocked.get();
+ .map((tConfig) =>
+ Either.fromFailable<Error, { config: BitwardenConfig; key: Pick<TKey, 'BITWARDENCLI_APPDATA_DIR'> }>(
+ () => {
+ const sessionPath = path.join(this.config.sessionBaseDirectory, randomUUID());
+ mkdirSync(sessionPath, { recursive: true });
+ return { config: tConfig.get(), key: { BITWARDENCLI_APPDATA_DIR: sessionPath } };
+ },
+ ),
+ )
+ .map((tEitherConfig) =>
+ tEitherConfig
+ .get()
+ .flatMapAsync(({ config: { server }, key }) =>
+ getStdoutMany(
+ tEitherConfig.move([
+ `bw config server ${server}`,
+ `bw login --apikey --quiet`,
+ `bw unlock --passwordenv BW_PASSWORD --raw`,
+ ]),
+ { env: key },
+ ).then((res) => res.mapRight((out) => ({ ...key, BW_SESSION: out.at(-1)! }))),
+ ),
+ )
+ .peek(TraceUtil.promiseify(TraceUtil.traceResultingEither(Bitwarden.loginMetric)))
+ .get();
}
- public fetchSecret<T extends SecretItem>(client: TClient, key: string, item: string): Promise<IEither<Error, T>> {
+ public fetchSecret<T extends SecretItem>(client: TClient, key: TKey, item: string): Promise<IEither<Error, T>> {
return client
.move(key)
.flatMap(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() },
- }),
- ),
- )
+ .flatMap((tSession) => tSession.move('bw list items').map((listCmd) => getStdout(listCmd, { env: key })))
.map(
TraceUtil.promiseify((tEitherItemsJson) =>
tEitherItemsJson
@@ -110,11 +110,7 @@ export class Bitwarden implements IVault<TClient, TKey, TItemId> {
.flatMap(TraceUtil.withMetricTrace(Bitwarden.lockVaultMetric))
.peek((tSession) => tSession.trace.trace(`taking care of locking the vault :3`))
.flatMap((tSession) =>
- tSession.move('bw lock && bw logout').map((lockCmd) =>
- getStdout(lockCmd, {
- env: { BW_SESSION: tSession.get() },
- }),
- ),
+ tSession.move('bw lock && bw logout').map((lockCmd) => getStdout(lockCmd, { env: key })),
)
.peek(TraceUtil.promiseify(TraceUtil.traceResultingEither(Bitwarden.lockVaultMetric)))
.peek(
@@ -124,12 +120,14 @@ export class Bitwarden implements IVault<TClient, TKey, TItemId> {
.mapRight(() => tEitherWithLocked.trace.trace('all locked up and secure now~ (。•̀ᴗ-)✧')),
),
)
+ .map(TraceUtil.promiseify((e) => e.get().mapRight(() => key)))
.get();
}
- public static getConfigFromEnvironment(): IEither<Error, BitwardenConfig> {
+ public static getConfigFromEnvironment(sessionBaseDirectory = '/tmp/secret'): IEither<Error, BitwardenConfig> {
return getRequiredEnvVars(['BW_SERVER', 'BW_CLIENTSECRET', 'BW_CLIENTID', 'BW_PASSWORD']).mapRight(
({ BW_SERVER, BW_CLIENTSECRET, BW_CLIENTID }) => ({
+ sessionBaseDirectory,
clientId: BW_CLIENTID,
secret: BW_CLIENTSECRET,
server: BW_SERVER,
@@ -144,6 +142,7 @@ export class Bitwarden implements IVault<TClient, TKey, TItemId> {
}
export interface BitwardenConfig {
+ sessionBaseDirectory: string;
server: string;
secret: string;
clientId: string;