// import { mkdirSync, readFileSync, writeFileSync } from "fs"; // import { writeFile } from "fs/promises"; export class DHSecretClient { private token!: Promise; //Set by init private headerName = "x-hoard-auth-token"; private cache: Record = {}; 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; } }