- Implemented async utilities including delay, retryWithBackoff, withTimeout, parallelLimit, debounceAsync, AsyncMutex, and CircuitBreaker. - Created tests for async utilities to ensure functionality and reliability. - Developed AsyncFileSystem class with methods for file and directory operations, including ensureDir, readFile, writeFile, remove, and more. - Added tests for filesystem utilities to validate file operations and error handling.
92 lines
2.6 KiB
TypeScript
92 lines
2.6 KiB
TypeScript
import * as plugins from '../../plugins.js';
|
|
import { AsyncFileSystem } from '../../core/utils/fs-utils.js';
|
|
import type { ICertificateData } from './certificate-manager.js';
|
|
|
|
export class CertStore {
|
|
constructor(private certDir: string) {}
|
|
|
|
public async initialize(): Promise<void> {
|
|
await AsyncFileSystem.ensureDir(this.certDir);
|
|
}
|
|
|
|
public async getCertificate(routeName: string): Promise<ICertificateData | null> {
|
|
const certPath = this.getCertPath(routeName);
|
|
const metaPath = `${certPath}/meta.json`;
|
|
|
|
if (!await AsyncFileSystem.exists(metaPath)) {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
const meta = await AsyncFileSystem.readJSON(metaPath);
|
|
|
|
const [cert, key] = await Promise.all([
|
|
AsyncFileSystem.readFile(`${certPath}/cert.pem`),
|
|
AsyncFileSystem.readFile(`${certPath}/key.pem`)
|
|
]);
|
|
|
|
let ca: string | undefined;
|
|
const caPath = `${certPath}/ca.pem`;
|
|
if (await AsyncFileSystem.exists(caPath)) {
|
|
ca = await AsyncFileSystem.readFile(caPath);
|
|
}
|
|
|
|
return {
|
|
cert,
|
|
key,
|
|
ca,
|
|
expiryDate: new Date(meta.expiryDate),
|
|
issueDate: new Date(meta.issueDate)
|
|
};
|
|
} catch (error) {
|
|
console.error(`Failed to load certificate for ${routeName}: ${error}`);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public async saveCertificate(
|
|
routeName: string,
|
|
certData: ICertificateData
|
|
): Promise<void> {
|
|
const certPath = this.getCertPath(routeName);
|
|
await AsyncFileSystem.ensureDir(certPath);
|
|
|
|
// Save certificate files in parallel
|
|
const savePromises = [
|
|
AsyncFileSystem.writeFile(`${certPath}/cert.pem`, certData.cert),
|
|
AsyncFileSystem.writeFile(`${certPath}/key.pem`, certData.key)
|
|
];
|
|
|
|
if (certData.ca) {
|
|
savePromises.push(
|
|
AsyncFileSystem.writeFile(`${certPath}/ca.pem`, certData.ca)
|
|
);
|
|
}
|
|
|
|
// Save metadata
|
|
const meta = {
|
|
expiryDate: certData.expiryDate.toISOString(),
|
|
issueDate: certData.issueDate.toISOString(),
|
|
savedAt: new Date().toISOString()
|
|
};
|
|
|
|
savePromises.push(
|
|
AsyncFileSystem.writeJSON(`${certPath}/meta.json`, meta)
|
|
);
|
|
|
|
await Promise.all(savePromises);
|
|
}
|
|
|
|
public async deleteCertificate(routeName: string): Promise<void> {
|
|
const certPath = this.getCertPath(routeName);
|
|
if (await AsyncFileSystem.isDirectory(certPath)) {
|
|
await AsyncFileSystem.removeDir(certPath);
|
|
}
|
|
}
|
|
|
|
private getCertPath(routeName: string): string {
|
|
// Sanitize route name for filesystem
|
|
const safeName = routeName.replace(/[^a-zA-Z0-9-_]/g, '_');
|
|
return `${this.certDir}/${safeName}`;
|
|
}
|
|
} |