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>
388 lines
9.8 KiB
TypeScript
388 lines
9.8 KiB
TypeScript
import jwt from "jsonwebtoken";
|
|
import { SystemKeyManager } from "./system-key-manager.js";
|
|
import { UserKeyManager } from "./user-key-manager.js";
|
|
import { databaseLogger } from "./logger.js";
|
|
import type { Request, Response, NextFunction } from "express";
|
|
|
|
interface AuthenticationResult {
|
|
success: boolean;
|
|
token?: string;
|
|
userId?: string;
|
|
isAdmin?: boolean;
|
|
username?: string;
|
|
requiresTOTP?: boolean;
|
|
tempToken?: string;
|
|
error?: string;
|
|
}
|
|
|
|
interface RequestContext {
|
|
userId: string;
|
|
dataKey: Buffer | null;
|
|
isUnlocked: boolean;
|
|
}
|
|
|
|
interface JWTPayload {
|
|
userId: string;
|
|
pendingTOTP?: boolean;
|
|
iat?: number;
|
|
exp?: number;
|
|
}
|
|
|
|
/**
|
|
* SecuritySession - Unified security session management
|
|
*
|
|
* Responsibilities:
|
|
* - Coordinate system key and user key management
|
|
* - Provide unified authentication and authorization interface
|
|
* - Manage JWT generation and verification
|
|
* - Handle security middleware
|
|
*/
|
|
class SecuritySession {
|
|
private static instance: SecuritySession;
|
|
private systemKeyManager: SystemKeyManager;
|
|
private userKeyManager: UserKeyManager;
|
|
private initialized: boolean = false;
|
|
|
|
private constructor() {
|
|
this.systemKeyManager = SystemKeyManager.getInstance();
|
|
this.userKeyManager = UserKeyManager.getInstance();
|
|
}
|
|
|
|
static getInstance(): SecuritySession {
|
|
if (!this.instance) {
|
|
this.instance = new SecuritySession();
|
|
}
|
|
return this.instance;
|
|
}
|
|
|
|
/**
|
|
* Initialize security system
|
|
*/
|
|
async initialize(): Promise<void> {
|
|
if (this.initialized) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
databaseLogger.info("Initializing security session system", {
|
|
operation: "security_init",
|
|
});
|
|
|
|
// Initialize system keys (JWT etc.)
|
|
await this.systemKeyManager.initializeJWTSecret();
|
|
|
|
this.initialized = true;
|
|
|
|
databaseLogger.success("Security session system initialized successfully", {
|
|
operation: "security_init_complete",
|
|
});
|
|
} catch (error) {
|
|
databaseLogger.error("Failed to initialize security system", error, {
|
|
operation: "security_init_failed",
|
|
});
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* User registration - set up user encryption
|
|
*/
|
|
async registerUser(userId: string, password: string): Promise<void> {
|
|
await this.userKeyManager.setupUserEncryption(userId, password);
|
|
}
|
|
|
|
/**
|
|
* User authentication (login)
|
|
*/
|
|
async authenticateUser(username: string, password: string): Promise<AuthenticationResult> {
|
|
try {
|
|
databaseLogger.info("User authentication attempt", {
|
|
operation: "user_auth",
|
|
username,
|
|
});
|
|
|
|
// Need to get user info from database (will be implemented when refactoring users.ts)
|
|
// Return basic structure for now
|
|
return {
|
|
success: false,
|
|
error: "Authentication implementation pending refactor",
|
|
};
|
|
} catch (error) {
|
|
databaseLogger.error("Authentication failed", error, {
|
|
operation: "user_auth_failed",
|
|
username,
|
|
});
|
|
|
|
return {
|
|
success: false,
|
|
error: "Authentication failed",
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generate JWT token
|
|
*/
|
|
async generateJWTToken(
|
|
userId: string,
|
|
options: {
|
|
expiresIn?: string;
|
|
pendingTOTP?: boolean;
|
|
} = {}
|
|
): Promise<string> {
|
|
const jwtSecret = await this.systemKeyManager.getJWTSecret();
|
|
|
|
const payload: JWTPayload = {
|
|
userId,
|
|
};
|
|
|
|
if (options.pendingTOTP) {
|
|
payload.pendingTOTP = true;
|
|
}
|
|
|
|
const token = jwt.sign(
|
|
payload,
|
|
jwtSecret,
|
|
{
|
|
expiresIn: options.expiresIn || "24h",
|
|
} as jwt.SignOptions
|
|
);
|
|
|
|
databaseLogger.info("JWT token generated", {
|
|
operation: "jwt_generated",
|
|
userId,
|
|
pendingTOTP: !!options.pendingTOTP,
|
|
expiresIn: options.expiresIn || "24h",
|
|
});
|
|
|
|
return token;
|
|
}
|
|
|
|
/**
|
|
* Verify JWT token
|
|
*/
|
|
async verifyJWTToken(token: string): Promise<JWTPayload | null> {
|
|
try {
|
|
const jwtSecret = await this.systemKeyManager.getJWTSecret();
|
|
const payload = jwt.verify(token, jwtSecret) as JWTPayload;
|
|
|
|
databaseLogger.debug("JWT token verified", {
|
|
operation: "jwt_verified",
|
|
userId: payload.userId,
|
|
pendingTOTP: !!payload.pendingTOTP,
|
|
});
|
|
|
|
return payload;
|
|
} catch (error) {
|
|
databaseLogger.warn("JWT token verification failed", {
|
|
operation: "jwt_verify_failed",
|
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
});
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create authentication middleware
|
|
*/
|
|
createAuthMiddleware() {
|
|
return async (req: Request, res: Response, next: NextFunction) => {
|
|
const authHeader = req.headers["authorization"];
|
|
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
databaseLogger.warn("Missing or invalid Authorization header", {
|
|
operation: "auth_middleware",
|
|
method: req.method,
|
|
url: req.url,
|
|
});
|
|
return res.status(401).json({
|
|
error: "Missing or invalid Authorization header"
|
|
});
|
|
}
|
|
|
|
const token = authHeader.split(" ")[1];
|
|
|
|
try {
|
|
const payload = await this.verifyJWTToken(token);
|
|
if (!payload) {
|
|
return res.status(401).json({ error: "Invalid or expired token" });
|
|
}
|
|
|
|
// Add user information to request object
|
|
(req as any).userId = payload.userId;
|
|
(req as any).pendingTOTP = payload.pendingTOTP;
|
|
|
|
next();
|
|
} catch (error) {
|
|
databaseLogger.warn("Authentication middleware failed", {
|
|
operation: "auth_middleware_failed",
|
|
method: req.method,
|
|
url: req.url,
|
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
});
|
|
return res.status(401).json({ error: "Authentication failed" });
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Create data access middleware (requires unlocked data keys)
|
|
*/
|
|
createDataAccessMiddleware() {
|
|
return async (req: Request, res: Response, next: NextFunction) => {
|
|
const userId = (req as any).userId;
|
|
if (!userId) {
|
|
return res.status(401).json({
|
|
error: "Authentication required"
|
|
});
|
|
}
|
|
|
|
const dataKey = this.userKeyManager.getUserDataKey(userId);
|
|
if (!dataKey) {
|
|
databaseLogger.warn("Data access denied - user not unlocked", {
|
|
operation: "data_access_denied",
|
|
userId,
|
|
method: req.method,
|
|
url: req.url,
|
|
});
|
|
return res.status(423).json({
|
|
error: "Data access locked - please re-authenticate with password",
|
|
code: "DATA_LOCKED"
|
|
});
|
|
}
|
|
|
|
// Add data key to request context
|
|
(req as any).dataKey = dataKey;
|
|
(req as any).isUnlocked = true;
|
|
|
|
next();
|
|
};
|
|
}
|
|
|
|
/**
|
|
* User unlock data (after entering password)
|
|
*/
|
|
async unlockUserData(userId: string, password: string): Promise<boolean> {
|
|
return await this.userKeyManager.authenticateAndUnlockUser(userId, password);
|
|
}
|
|
|
|
/**
|
|
* User logout
|
|
*/
|
|
logoutUser(userId: string): void {
|
|
this.userKeyManager.logoutUser(userId);
|
|
|
|
databaseLogger.info("User logged out", {
|
|
operation: "user_logout",
|
|
userId,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Check if user has unlocked data
|
|
*/
|
|
isUserDataUnlocked(userId: string): boolean {
|
|
return this.userKeyManager.isUserUnlocked(userId);
|
|
}
|
|
|
|
/**
|
|
* Get user data key (for data encryption operations)
|
|
*/
|
|
getUserDataKey(userId: string): Buffer | null {
|
|
return this.userKeyManager.getUserDataKey(userId);
|
|
}
|
|
|
|
/**
|
|
* Change user password
|
|
*/
|
|
async changeUserPassword(
|
|
userId: string,
|
|
oldPassword: string,
|
|
newPassword: string
|
|
): Promise<boolean> {
|
|
return await this.userKeyManager.changeUserPassword(userId, oldPassword, newPassword);
|
|
}
|
|
|
|
/**
|
|
* Get request context (for data operations)
|
|
*/
|
|
getRequestContext(req: Request): RequestContext {
|
|
const userId = (req as any).userId;
|
|
const dataKey = (req as any).dataKey || null;
|
|
const isUnlocked = !!dataKey;
|
|
|
|
return {
|
|
userId,
|
|
dataKey,
|
|
isUnlocked,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Regenerate JWT key (admin operation)
|
|
*/
|
|
async regenerateJWTSecret(): Promise<string> {
|
|
return await this.systemKeyManager.regenerateJWTSecret();
|
|
}
|
|
|
|
/**
|
|
* Get security status
|
|
*/
|
|
async getSecurityStatus() {
|
|
const systemStatus = await this.systemKeyManager.getSystemKeyStatus();
|
|
const activeSessions = this.userKeyManager.getAllActiveSessions();
|
|
|
|
return {
|
|
initialized: this.initialized,
|
|
system: systemStatus,
|
|
activeSessions,
|
|
activeSessionCount: Object.keys(activeSessions).length,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Clear all user sessions (emergency)
|
|
*/
|
|
clearAllUserSessions(): void {
|
|
// Get all active sessions and clear them
|
|
const activeSessions = this.userKeyManager.getAllActiveSessions();
|
|
for (const userId of Object.keys(activeSessions)) {
|
|
this.userKeyManager.logoutUser(userId);
|
|
}
|
|
|
|
databaseLogger.warn("All user sessions cleared", {
|
|
operation: "emergency_session_clear",
|
|
clearedCount: Object.keys(activeSessions).length,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Validate entire security system
|
|
*/
|
|
async validateSecuritySystem(): Promise<boolean> {
|
|
try {
|
|
// Validate JWT system
|
|
const jwtValid = await this.systemKeyManager.validateJWTSecret();
|
|
if (!jwtValid) {
|
|
databaseLogger.error("JWT system validation failed", undefined, {
|
|
operation: "security_validation",
|
|
});
|
|
return false;
|
|
}
|
|
|
|
// Can add more validations...
|
|
|
|
databaseLogger.success("Security system validation passed", {
|
|
operation: "security_validation_success",
|
|
});
|
|
|
|
return true;
|
|
} catch (error) {
|
|
databaseLogger.error("Security system validation failed", error, {
|
|
operation: "security_validation_failed",
|
|
});
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
export { SecuritySession, type AuthenticationResult, type RequestContext, type JWTPayload }; |