Files
smartsecret/ts/smartsecret.classes.smartsecret.ts
Juergen Kunz 7a19f01def feat(core): initial release with 3-tier secret storage
Implements SmartSecret with macOS Keychain, Linux secret-tool, and AES-256-GCM encrypted file fallback backends. Zero runtime dependencies.
2026-02-24 15:40:14 +00:00

67 lines
2.0 KiB
TypeScript

import type { ISecretBackend, TBackendType } from './smartsecret.backends.base.js';
import { MacosKeychainBackend } from './smartsecret.backends.macos.js';
import { LinuxSecretServiceBackend } from './smartsecret.backends.linux.js';
import { FileEncryptedBackend } from './smartsecret.backends.file.js';
export interface ISmartSecretOptions {
service?: string;
vaultPath?: string;
}
export class SmartSecret {
private service: string;
private vaultPath?: string;
private backend: ISecretBackend | null = null;
constructor(options?: ISmartSecretOptions) {
this.service = options?.service ?? 'smartsecret';
this.vaultPath = options?.vaultPath;
}
private async getBackend(): Promise<ISecretBackend> {
if (this.backend) return this.backend;
const candidates: ISecretBackend[] = [
new MacosKeychainBackend(this.service),
new LinuxSecretServiceBackend(this.service),
new FileEncryptedBackend(this.service, this.vaultPath),
];
for (const candidate of candidates) {
if (await candidate.isAvailable()) {
this.backend = candidate;
return this.backend;
}
}
// File backend is always available, so we should never reach here
this.backend = candidates[candidates.length - 1];
return this.backend;
}
async setSecret(account: string, secret: string): Promise<void> {
const backend = await this.getBackend();
await backend.setSecret(account, secret);
}
async getSecret(account: string): Promise<string | null> {
const backend = await this.getBackend();
return backend.getSecret(account);
}
async deleteSecret(account: string): Promise<boolean> {
const backend = await this.getBackend();
return backend.deleteSecret(account);
}
async listAccounts(): Promise<string[]> {
const backend = await this.getBackend();
return backend.listAccounts();
}
async getBackendType(): Promise<TBackendType> {
const backend = await this.getBackend();
return backend.backendType;
}
}