Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
6 changes: 6 additions & 0 deletions src/lib/secretsManager/encryptedStorage/IEncryptedStorage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface IEncryptedStorage {
initialize(): Promise<void>;
save<T extends Record<string, any>>(key: string, data: T): Promise<void>;
load<T extends Record<string, any>>(key: string): Promise<T>;
delete(key: string): Promise<void>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { safeStorage } from "electron";
import { IEncryptedStorage } from "./IEncryptedStorage";

export class EncryptedFsStorageService implements IEncryptedStorage {
constructor(private readonly baseFolderPath: string) {}

async initialize(): Promise<void> {
if (!safeStorage.isEncryptionAvailable()) {
// Show trouble shooting steps to user
throw new Error("Encryption is not available on this system. ");
}

// initialize directories
}

async save<T extends Record<string, any>>(
key: string,
data: T
): Promise<void> {
// encrypted
}

async load<T extends Record<string, any>>(key: string): Promise<T> {}

async delete(key: string): Promise<void> {}
}
80 changes: 80 additions & 0 deletions src/lib/secretsManager/providerRegistry/FsProviderRegistry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import * as fs from "fs/promises";
import * as path from "path";
import { IProviderRegistry } from "./IProviderRegistry";
import { SecretProviderConfig, SecretProviderType } from "../types";
import { IEncryptedStorage } from "../encryptedStorage/IEncryptedStorage";

const MANIFEST_FILENAME = "providers.json";

export interface ProvidersManifest {
version: string;
providers: {
id: string;
storagePath: string;
type: SecretProviderType;
}[];
}

export class FileBasedProviderRegistry implements IProviderRegistry {
private manifestPath: string;

constructor(
private readonly encryptedStorage: IEncryptedStorage,
private readonly configDir: string
) {
this.manifestPath = path.join(configDir, MANIFEST_FILENAME);
}

async initialize(): Promise<void> {
await this.ensureConfigDir();
}

async listProviders(): Promise<string[]> {
const manifest = await this.loadManifest();
return manifest.providers.map((p) => p.id);
}

async loadAllProviderConfigs(): Promise<SecretProviderConfig[]> {}

async saveProviderConfig(config: SecretProviderConfig): Promise<void> {
const manifest = await this.loadManifest();
const storageKey = config.id;

await this.encryptedStorage.save(storageKey, config);

// Update manifest

await this.saveManifest(manifest);
}

async deleteProviderConfig(id: string): Promise<void> {
const manifest = await this.loadManifest();
const entry = manifest.providers.find((p) => p.id === id);
if (!entry) return;

await this.encryptedStorage.delete(id);

manifest.providers = manifest.providers.filter((p) => p.id !== id);
await this.saveManifest(manifest);
}

async getProviderConfig(id: string): Promise<SecretProviderConfig | null> {
const manifest = await this.loadManifest();
const entry = manifest.providers.find((p) => p.id === id);
if (!entry) return null;

return this.encryptedStorage.load<SecretProviderConfig>(id);
}

private async ensureConfigDir(): Promise<void> {
try {
await fs.mkdir(this.configDir, { recursive: true });
} catch (error) {
console.error("Failed to create config directory:", error);
}
}

private async loadManifest(): Promise<ProvidersManifest> {}

private async saveManifest(manifest: ProvidersManifest): Promise<void> {}
}
10 changes: 10 additions & 0 deletions src/lib/secretsManager/providerRegistry/IProviderRegistry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { SecretProviderConfig } from "../types";

export interface IProviderRegistry {
initialize(): Promise<void>;
listProviders(): Promise<string[]>;
loadAllProviderConfigs(): Promise<SecretProviderConfig[]>;
saveProviderConfig(config: SecretProviderConfig): Promise<void>;
deleteProviderConfig(id: string): Promise<void>;
getProviderConfig(id: string): Promise<SecretProviderConfig | null>;
}
12 changes: 12 additions & 0 deletions src/lib/secretsManager/providerService/ISecretProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { SecretProviderType } from "../types";

export interface ISecretProvider {
type: SecretProviderType;
id: string;

testConnection(): Promise<boolean>;
fetchSecret(secretName: string): Promise<string>;
listSecrets(): Promise<string[]>;

validateConfig(): boolean;
}
Empty file.
48 changes: 48 additions & 0 deletions src/lib/secretsManager/secretsManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { IProviderRegistry } from "./providerRegistry/IProviderRegistry";
import { ISecretProvider } from "./providerService/ISecretProvider";
import { SecretProviderConfig } from "./types";

export class SecretsManager {
private registry: IProviderRegistry;

private providers: Map<string, ISecretProvider> = new Map();

constructor(registry: IProviderRegistry) {
this.registry = registry;
}

async initialize(): Promise<void> {
this.registry.initialize();
this.initProvidersFromManifest();
}

private async initProvidersFromManifest() {
const configs = await this.registry.loadAllProviderConfigs();
configs.forEach((config) => {
this.providers.set(config.id, this.createProviderInstance(config));
});
}

async addProviderConfig(config: SecretProviderConfig) {
this.providers.set(config.id, this.createProviderInstance(config));
this.registry.saveProviderConfig(config);
}

async removeProviderConfig(id: string) {
this.providers.delete(id);
this.registry.deleteProviderConfig(id);
}

async getProviderConfig(id: string): Promise<SecretProviderConfig | null> {
return this.registry.getProviderConfig(id);
}

async testProviderConnection(id: string): Promise<boolean> {
const provider = this.providers.get(id);
return provider?.testConnection();
}

private createProviderInstance(
config: SecretProviderConfig
): ISecretProvider {}
}
19 changes: 19 additions & 0 deletions src/lib/secretsManager/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export enum SecretProviderType {
AWS_SECRETS_MANGER = "aws",
}

export interface AWSSecretsManagerConfig {
accessKeyId: string;
secretAccessKey: string;
region: string;
sessionToken?: string;
}

export interface SecretProviderConfig {
id: string;
type: SecretProviderType;
name: string;
createdAt: number;
updatedAt: number;
config: AWSSecretsManagerConfig;
}