UNPKG

@workspace-fs/core

Version:

Multi-project workspace manager for Firesystem with support for multiple sources

215 lines (184 loc) 5.82 kB
import type { SourceAuth, ProjectSource } from "../types"; export interface CredentialProvider { /** * Get credentials for a specific project */ getCredentials(projectId: string, source: ProjectSource): Promise<any>; /** * Store credentials securely */ storeCredentials(projectId: string, credentials: any): Promise<void>; /** * Remove stored credentials */ removeCredentials(projectId: string): Promise<void>; } /** * Manages credentials for different project sources */ export class CredentialManager { private providers = new Map<string, CredentialProvider>(); private memoryCache = new Map<string, any>(); /** * Register a credential provider */ registerProvider(name: string, provider: CredentialProvider): void { this.providers.set(name, provider); } /** * Get credentials for a project source */ async getCredentials(projectId: string, source: ProjectSource): Promise<any> { // Check memory cache first const cacheKey = `${projectId}:${source.type}`; if (this.memoryCache.has(cacheKey)) { return this.memoryCache.get(cacheKey); } // Use provider if available const provider = this.providers.get(source.type); if (provider) { const credentials = await provider.getCredentials(projectId, source); this.memoryCache.set(cacheKey, credentials); return credentials; } // Fallback to source auth if provided if (source.auth) { return this.extractCredentials(source.auth); } // Return empty object if no credentials needed return {}; } /** * Extract credentials from auth config */ private extractCredentials(auth: SourceAuth): any { switch (auth.type) { case "bearer": return { token: auth.credentials.token }; case "basic": return { username: auth.credentials.username, password: auth.credentials.password, }; case "token": return { apiKey: auth.credentials.apiKey }; case "oauth2": return { accessToken: auth.credentials.accessToken, refreshToken: auth.credentials.refreshToken, }; default: return auth.credentials; } } /** * Clear cached credentials */ clearCache(projectId?: string): void { if (projectId) { // Clear specific project for (const [key] of this.memoryCache) { if (key.startsWith(`${projectId}:`)) { this.memoryCache.delete(key); } } } else { // Clear all this.memoryCache.clear(); } } } /** * Browser-based credential provider using Web Crypto API */ export class BrowserCredentialProvider implements CredentialProvider { private dbName = "@firesystem/credentials"; private storeName = "credentials"; async getCredentials(projectId: string, source: ProjectSource): Promise<any> { // For demo purposes, return config as-is // In production, this would decrypt from secure storage return source.config; } async storeCredentials(projectId: string, credentials: any): Promise<void> { // In production, encrypt before storing console.warn( "Storing credentials in browser - consider security implications", ); } async removeCredentials(projectId: string): Promise<void> { // Remove from secure storage } } /** * Environment variable credential provider (for Node.js) */ export class EnvCredentialProvider implements CredentialProvider { async getCredentials(projectId: string, source: ProjectSource): Promise<any> { const prefix = `FIRESYSTEM_${source.type.toUpperCase()}_`; switch (source.type) { case "s3": return { accessKeyId: process.env[`${prefix}ACCESS_KEY_ID`], secretAccessKey: process.env[`${prefix}SECRET_ACCESS_KEY`], region: process.env[`${prefix}REGION`] || "us-east-1", bucket: source.config.bucket, // Bucket from config }; case "github": return { token: process.env[`${prefix}TOKEN`] || process.env.GITHUB_TOKEN, }; case "api": return { apiKey: process.env[`${prefix}API_KEY`], baseUrl: source.config.baseUrl, }; default: return source.config; } } async storeCredentials(): Promise<void> { throw new Error("Cannot store credentials in environment variables"); } async removeCredentials(): Promise<void> { throw new Error("Cannot remove credentials from environment variables"); } } /** * Interactive credential provider that prompts user */ export class InteractiveCredentialProvider implements CredentialProvider { constructor( private prompter: (message: string, secure?: boolean) => Promise<string>, ) {} async getCredentials(projectId: string, source: ProjectSource): Promise<any> { console.log(`Credentials needed for ${source.type} project: ${projectId}`); switch (source.type) { case "s3": return { accessKeyId: await this.prompter("AWS Access Key ID:"), secretAccessKey: await this.prompter("AWS Secret Access Key:", true), region: (await this.prompter("AWS Region (default: us-east-1):")) || "us-east-1", bucket: source.config.bucket, }; case "github": return { token: await this.prompter("GitHub Personal Access Token:", true), }; case "api": return { apiKey: await this.prompter("API Key:", true), baseUrl: source.config.baseUrl, }; default: return source.config; } } async storeCredentials(): Promise<void> { // No storage in interactive mode } async removeCredentials(): Promise<void> { // No storage in interactive mode } }