diff options
Diffstat (limited to 'utils')
-rw-r--r-- | utils/deno.json | 5 | ||||
-rw-r--r-- | utils/env.ts | 5 | ||||
-rw-r--r-- | utils/mod.ts | 4 | ||||
-rw-r--r-- | utils/run.ts | 21 | ||||
-rw-r--r-- | utils/secret.ts | 46 | ||||
-rw-r--r-- | utils/validate_identifier.ts | 3 |
6 files changed, 84 insertions, 0 deletions
diff --git a/utils/deno.json b/utils/deno.json new file mode 100644 index 0000000..b85c47f --- /dev/null +++ b/utils/deno.json @@ -0,0 +1,5 @@ +{ + "name": "@liz-ci/utils", + "version": "0.1.0", + "exports": "./mod.ts" +} diff --git a/utils/env.ts b/utils/env.ts new file mode 100644 index 0000000..c0cf447 --- /dev/null +++ b/utils/env.ts @@ -0,0 +1,5 @@ +export const getRequiredEnv = (name: string): string => { + const value = Deno.env.get(name); + if (!value) throw new Error(`${name} environment variable is required`); + return value; +}; diff --git a/utils/mod.ts b/utils/mod.ts new file mode 100644 index 0000000..93457f0 --- /dev/null +++ b/utils/mod.ts @@ -0,0 +1,4 @@ +export * from "./env.ts"; +export * from "./run.ts"; +export * from "./secret.ts"; +export * from "./validate_identifier.ts"; diff --git a/utils/run.ts b/utils/run.ts new file mode 100644 index 0000000..f3ce3d3 --- /dev/null +++ b/utils/run.ts @@ -0,0 +1,21 @@ +export const getStdout = async ( + cmd: string[] | string, + options: Deno.CommandOptions = {}, +): Promise<string> => { + const [exec, ...args] = (typeof cmd === "string") ? cmd.split(" ") : cmd; + const command = new Deno.Command(exec, { + args, + stdout: "piped", + stderr: "piped", + ...options, + }); + + const { code, stdout, stderr } = await command.output(); + + const stdoutText = new TextDecoder().decode(stdout); + const stderrText = new TextDecoder().decode(stderr); + + if (code !== 0) throw new Error(`Command failed: ${cmd}\n${stderrText}`); + + return stdoutText; +}; diff --git a/utils/secret.ts b/utils/secret.ts new file mode 100644 index 0000000..9847aa6 --- /dev/null +++ b/utils/secret.ts @@ -0,0 +1,46 @@ +import { getRequiredEnv, getStdout } from "./mod.ts"; + +export class BitwardenSession { + private readonly sessionInitializer: Promise<string>; + + constructor(server = getRequiredEnv("BW_SERVER")) { + ["BW_CLIENTID", "BW_CLIENTSECRET"].forEach(getRequiredEnv); + + this.sessionInitializer = getStdout( + `bw config server ${server} --quiet`, + ).then(() => getStdout(`bw login --apikey --quiet`)) + .then(() => getStdout(`bw unlock --passwordenv BW_PASSWORD --raw`)) + .then((session) => session.trim()); + } + + public async getItem<T extends LoginItem | SecureNote>( + secretName: string, + ): Promise<T | undefined> { + return await this.sessionInitializer.then((session) => + getStdout(`bw list items`, { + env: { + BW_SESSION: session, + }, + }) + ).then((items) => JSON.parse(items)).then((items) => + items.find(({ name }: { name: string }) => name === secretName) + ); + } + + async close(): Promise<void> { + return await this.sessionInitializer.then((session) => + getStdout(`bw lock`, { env: { BW_SESSION: session } }) + ).then(() => {}); + } +} + +export type LoginItem = { + login: { + username: string; + password: string; + }; +}; + +export type SecureNote = { + notes: string; +}; diff --git a/utils/validate_identifier.ts b/utils/validate_identifier.ts new file mode 100644 index 0000000..c8a5213 --- /dev/null +++ b/utils/validate_identifier.ts @@ -0,0 +1,3 @@ +export const validateIdentifier = (token: string) => { + return (/^[a-zA-Z0-9_\-:. ]+$/).test(token) && !token.includes(".."); +}; |