dh secret manager

This commit is contained in:
2024-03-17 09:31:30 -06:00
parent df20a47253
commit 2f3f2fd81e
11 changed files with 5660 additions and 10 deletions

99
lib/secret/index.ts Normal file
View File

@@ -0,0 +1,99 @@
// import { mkdirSync, readFileSync, writeFileSync } from "fs";
// import { writeFile } from "fs/promises";
export class DHSecretClient {
private token!: Promise<string>; //Set by init
private headerName = "x-hoard-auth-token";
private cache: Record<string, { value: string; expires?: number }> = {};
private cacheLocation: string;
/**
* @param dhBaseUri uri for hosted Dragon's Hoard instance
* @param cacheDir path to cache dir
*/
constructor(
private dhBaseUri: string,
private cacheDir: string,
) {
this.cacheLocation = this.cacheDir.trim().replace(/\/^/, "") + "/.dh_cache";
// mkdirSync(this.cacheDir, { recursive: true });
// writeFileSync(this.cacheLocation, "{}", { encoding: "utf-8", flag: "wx" });
// this.readDiskCache();
this.token = this.fetchToken();
}
private async fetchToken() {
const cacheKey = "token";
if (this.cache[cacheKey]) {
return this.cache[cacheKey].value;
}
const req = await fetch(this.dhBaseUri + "/api/access/token");
if (req.status !== 200) throw Error(await req.text());
const token = await req.text();
if (!token) throw Error("Token not included in response body");
this.writeCache(cacheKey, token);
return token;
}
// private readDiskCache() {
// const cache = readFileSync(this.cacheLocation, "utf-8");
// this.cache = JSON.parse(cache || "{}");
// }
// private async writeDiskCache() {
// await writeFile(this.cacheLocation, JSON.stringify(this.cache), "utf-8");
// }
private writeCache(key: string, value: string, expires?: number) {
this.cache[key] = { value, expires };
// this.writeDiskCache();
}
private readCache(key: string) {
const item = this.cache[key];
if (!item) return null;
if (item && item.expires && item.expires < Date.now()) {
delete this.cache[key];
// this.writeDiskCache();
return null;
}
return item.value;
}
async fetchSecret(secret_name: string, environment?: string) {
const uri = this.dhBaseUri + "/api/keys/" + secret_name +
(environment ? "?env=" + environment : "");
const cached = this.readCache(secret_name);
if (cached !== null) return cached;
const req = await fetch(uri, {
headers: {
[this.headerName]: await this.token,
},
});
if (req.status !== 200) throw Error(await req.text());
const secret = await req.text();
if (!secret) throw Error("Secret not included in response body");
this.writeCache(secret_name, secret);
return secret;
}
}

12
lib/secret/init.ts Normal file
View File

@@ -0,0 +1,12 @@
import { DHSecretClient } from ".";
if (!globalThis.Secrets) {
globalThis.Secrets = new DHSecretClient(
"https://dragonshoard.cyborggrizzly.com",
process.env.NODE_ENV === "development"
? "./.dragonshoard"
: "/.dragonshoard",
);
}
export const SecretClient = () => globalThis.Secrets;