Files
Termix/src/backend/utils/system-key-manager.ts
ZacharyZcR b9caa82ad4 Complete codebase internationalization: Replace Chinese comments with English
Major improvements:
- Replaced 226 Chinese comments with clear English equivalents across 16 files
- Backend security files: Complete English documentation for KEK-DEK architecture
- Frontend drag-drop hooks: Full English comments for file operations
- Database routes: English comments for all encryption operations
- Removed V1/V2 version identifiers, unified to single secure architecture

Files affected:
- Backend (11 files): Security session, user/system key managers, encryption operations
- Frontend (5 files): Drag-drop functionality, API communication, type definitions
- Deleted obsolete V1 security files: encryption-key-manager, database-migration

Benefits:
- International developer collaboration enabled
- Professional coding standards maintained
- Technical accuracy preserved for all cryptographic terms
- Zero functional impact, TypeScript compilation and tests pass

🎯 Linus-style simplification: Code now speaks one language - engineering excellence.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-21 20:59:04 +08:00

229 lines
6.0 KiB
TypeScript

import crypto from "crypto";
import { db } from "../database/db/index.js";
import { settings } from "../database/db/schema.js";
import { eq } from "drizzle-orm";
import { databaseLogger } from "./logger.js";
/**
* SystemKeyManager - Manage system-level keys (JWT etc.)
*
* Responsibilities:
* - JWT Secret generation, storage and retrieval
* - System-level key lifecycle management
* - Complete separation from user data keys
*/
class SystemKeyManager {
private static instance: SystemKeyManager;
private jwtSecret: string | null = null;
private constructor() {}
static getInstance(): SystemKeyManager {
if (!this.instance) {
this.instance = new SystemKeyManager();
}
return this.instance;
}
/**
* Initialize JWT key - called at system startup
*/
async initializeJWTSecret(): Promise<void> {
try {
databaseLogger.info("Initializing system JWT secret", {
operation: "system_jwt_init",
});
const existingSecret = await this.getStoredJWTSecret();
if (existingSecret) {
this.jwtSecret = existingSecret;
databaseLogger.success("System JWT secret loaded from storage", {
operation: "system_jwt_loaded",
});
} else {
const newSecret = await this.generateJWTSecret();
this.jwtSecret = newSecret;
databaseLogger.success("New system JWT secret generated", {
operation: "system_jwt_generated",
secretLength: newSecret.length,
});
}
} catch (error) {
databaseLogger.error("Failed to initialize JWT secret", error, {
operation: "system_jwt_init_failed",
});
throw new Error("System JWT secret initialization failed");
}
}
/**
* Get JWT key - for JWT signing and verification
*/
async getJWTSecret(): Promise<string> {
if (!this.jwtSecret) {
await this.initializeJWTSecret();
}
return this.jwtSecret!;
}
/**
* Generate new JWT key
*/
private async generateJWTSecret(): Promise<string> {
const secret = crypto.randomBytes(64).toString("hex");
const secretId = crypto.randomBytes(8).toString("hex");
const secretData = {
secret: Buffer.from(secret, "hex").toString("base64"), // Simple base64 encoding
secretId,
createdAt: new Date().toISOString(),
algorithm: "HS256",
};
try {
// Store to settings table
const existing = await db
.select()
.from(settings)
.where(eq(settings.key, "system_jwt_secret"));
const encodedData = JSON.stringify(secretData);
if (existing.length > 0) {
await db
.update(settings)
.set({ value: encodedData })
.where(eq(settings.key, "system_jwt_secret"));
} else {
await db.insert(settings).values({
key: "system_jwt_secret",
value: encodedData,
});
}
databaseLogger.info("System JWT secret stored successfully", {
operation: "system_jwt_stored",
secretId,
});
return secret;
} catch (error) {
databaseLogger.error("Failed to store JWT secret", error, {
operation: "system_jwt_store_failed",
});
throw error;
}
}
/**
* Read JWT key from database
*/
private async getStoredJWTSecret(): Promise<string | null> {
try {
const result = await db
.select()
.from(settings)
.where(eq(settings.key, "system_jwt_secret"));
if (result.length === 0) {
return null;
}
const secretData = JSON.parse(result[0].value);
return Buffer.from(secretData.secret, "base64").toString("hex");
} catch (error) {
databaseLogger.warn("Failed to load stored JWT secret", {
operation: "system_jwt_load_failed",
error: error instanceof Error ? error.message : "Unknown error",
});
return null;
}
}
/**
* Regenerate JWT key - admin operation
*/
async regenerateJWTSecret(): Promise<string> {
databaseLogger.warn("Regenerating system JWT secret - ALL TOKENS WILL BE INVALIDATED", {
operation: "system_jwt_regenerate",
});
const newSecret = await this.generateJWTSecret();
this.jwtSecret = newSecret;
databaseLogger.success("System JWT secret regenerated", {
operation: "system_jwt_regenerated",
warning: "All existing JWT tokens are now invalid",
});
return newSecret;
}
/**
* Validate if JWT key is available
*/
async validateJWTSecret(): Promise<boolean> {
try {
const secret = await this.getJWTSecret();
if (!secret || secret.length < 32) {
return false;
}
// Test JWT operations
const jwt = await import("jsonwebtoken");
const testPayload = { test: true, timestamp: Date.now() };
const token = jwt.default.sign(testPayload, secret, { expiresIn: "1s" });
const decoded = jwt.default.verify(token, secret);
return !!decoded;
} catch (error) {
databaseLogger.error("JWT secret validation failed", error, {
operation: "system_jwt_validation_failed",
});
return false;
}
}
/**
* Get system key status
*/
async getSystemKeyStatus() {
const isValid = await this.validateJWTSecret();
const hasSecret = this.jwtSecret !== null;
try {
const result = await db
.select()
.from(settings)
.where(eq(settings.key, "system_jwt_secret"));
const hasStored = result.length > 0;
let createdAt = null;
let secretId = null;
if (hasStored) {
const secretData = JSON.parse(result[0].value);
createdAt = secretData.createdAt;
secretId = secretData.secretId;
}
return {
hasSecret,
hasStored,
isValid,
createdAt,
secretId,
algorithm: "HS256",
};
} catch (error) {
return {
hasSecret,
hasStored: false,
isValid: false,
error: error instanceof Error ? error.message : "Unknown error",
};
}
}
}
export { SystemKeyManager };