Files
onebox/ts/classes/registries.ts

196 lines
5.1 KiB
TypeScript
Raw Normal View History

/**
* Registry Manager for Onebox
*
* Manages Docker registry credentials and authentication
*/
2025-11-18 00:03:24 +00:00
import * as plugins from '../plugins.ts';
import type { IRegistry } from '../types.ts';
import { logger } from '../logging.ts';
import { OneboxDatabase } from './database.ts';
export class OneboxRegistriesManager {
private oneboxRef: any; // Will be Onebox instance
private database: OneboxDatabase;
constructor(oneboxRef: any) {
this.oneboxRef = oneboxRef;
this.database = oneboxRef.database;
}
/**
* Encrypt a password (simple base64 for now, should use proper encryption)
*/
private encryptPassword(password: string): string {
// TODO: Use proper encryption with a secret key
// For now, using base64 encoding (NOT SECURE, just for structure)
return plugins.encoding.encodeBase64(new TextEncoder().encode(password));
}
/**
* Decrypt a password
*/
private decryptPassword(encrypted: string): string {
// TODO: Use proper decryption
return new TextDecoder().decode(plugins.encoding.decodeBase64(encrypted));
}
/**
* Add a registry
*/
async addRegistry(url: string, username: string, password: string): Promise<IRegistry> {
try {
// Check if registry already exists
const existing = this.database.getRegistryByURL(url);
if (existing) {
throw new Error(`Registry already exists: ${url}`);
}
// Encrypt password
const passwordEncrypted = this.encryptPassword(password);
// Create registry in database
const registry = await this.database.createRegistry({
url,
username,
passwordEncrypted,
createdAt: Date.now(),
});
logger.success(`Registry added: ${url}`);
// Perform Docker login
await this.loginToRegistry(registry);
return registry;
} catch (error) {
logger.error(`Failed to add registry ${url}: ${error.message}`);
throw error;
}
}
/**
* Remove a registry
*/
async removeRegistry(url: string): Promise<void> {
try {
const registry = this.database.getRegistryByURL(url);
if (!registry) {
throw new Error(`Registry not found: ${url}`);
}
this.database.deleteRegistry(url);
logger.success(`Registry removed: ${url}`);
// Note: We don't perform docker logout as it might affect other users
} catch (error) {
logger.error(`Failed to remove registry ${url}: ${error.message}`);
throw error;
}
}
/**
* List all registries
*/
listRegistries(): IRegistry[] {
return this.database.getAllRegistries();
}
/**
* Get registry by URL
*/
getRegistry(url: string): IRegistry | null {
return this.database.getRegistryByURL(url);
}
/**
* Perform Docker login for a registry
*/
async loginToRegistry(registry: IRegistry): Promise<void> {
try {
logger.info(`Logging into registry: ${registry.url}`);
const password = this.decryptPassword(registry.passwordEncrypted);
// Use docker login command
const command = [
'docker',
'login',
registry.url,
'--username',
registry.username,
'--password-stdin',
];
const process = new Deno.Command('docker', {
args: ['login', registry.url, '--username', registry.username, '--password-stdin'],
stdin: 'piped',
stdout: 'piped',
stderr: 'piped',
});
const child = process.spawn();
// Write password to stdin
const writer = child.stdin.getWriter();
await writer.write(new TextEncoder().encode(password));
await writer.close();
const { code, stdout, stderr } = await child.output();
if (code !== 0) {
const errorMsg = new TextDecoder().decode(stderr);
throw new Error(`Docker login failed: ${errorMsg}`);
}
logger.success(`Logged into registry: ${registry.url}`);
} catch (error) {
logger.error(`Failed to login to registry ${registry.url}: ${error.message}`);
throw error;
}
}
/**
* Login to all registries (useful on daemon start)
*/
async loginToAllRegistries(): Promise<void> {
const registries = this.listRegistries();
for (const registry of registries) {
try {
await this.loginToRegistry(registry);
} catch (error) {
logger.warn(`Failed to login to ${registry.url}: ${error.message}`);
// Continue with other registries
}
}
}
/**
* Test registry connection
*/
async testRegistry(url: string, username: string, password: string): Promise<boolean> {
try {
const command = new Deno.Command('docker', {
args: ['login', url, '--username', username, '--password-stdin'],
stdin: 'piped',
stdout: 'piped',
stderr: 'piped',
});
const child = command.spawn();
const writer = child.stdin.getWriter();
await writer.write(new TextEncoder().encode(password));
await writer.close();
const { code } = await child.output();
return code === 0;
} catch (error) {
logger.error(`Failed to test registry ${url}: ${error.message}`);
return false;
}
}
}