summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rw-r--r--utils/deno.json5
-rw-r--r--utils/env.ts5
-rw-r--r--utils/mod.ts4
-rw-r--r--utils/run.ts21
-rw-r--r--utils/secret.ts46
-rw-r--r--utils/validate_identifier.ts3
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("..");
+};