import { getRequiredEnv, getStdout, loggerWithPrefix, type PrefixLogger, } from "./mod.ts"; export class BitwardenSession { private readonly sessionInitializer: Promise; private readonly logger: PrefixLogger; constructor( server = getRequiredEnv("BW_SERVER"), logger = loggerWithPrefix(), ) { ["BW_CLIENTID", "BW_CLIENTSECRET"].forEach(getRequiredEnv); const instanceId = crypto.randomUUID().split("-").at(0); this.logger = logger.withAdditionalPrefix(() => `[BitwardenSession.instance.${instanceId}]` ); this.sessionInitializer = getStdout( `bw config server ${server} --quiet`, ) .then(() => { this.logger.log("logging in via api (˘ω˘)"); return getStdout(`bw login --apikey --quiet`); }) .then(() => { this.logger.log("unlocking the secret vault~ (◕ᴗ◕✿)"); return getStdout(`bw unlock --passwordenv BW_PASSWORD --raw`); }) .then((session) => { const _session = session.trim(); this.logger.log(`got my session key (>ᴗ<) ${_session}`); return _session; }); } public async getItem( secretName: string, ): Promise { this.logger.log(`looking for your secret ${secretName} (⑅˘꒳˘)`); 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) ).then((item) => { if (!item) { throw new Error( "couldn't find the bitwarden item " + secretName + " (。•́︿•̀。)", ); } this.logger.log(`yay! found secret: ${secretName} (*ˊᗜˋ*)`); return item; }); } async close(): Promise { return await this.sessionInitializer.then((session) => getStdout(`bw lock`, { env: { BW_SESSION: session } }) ).then(() => { this.logger.log("all locked up and secure now~ (。•̀ᴗ-)✧"); }); } } export type LoginItem = { login: { username: string; password: string; }; }; export type SecureNote = { notes: string; };