import fs from 'fs/promises'; import path from 'path'; import { encryptionService } from './encryptionService'; export interface MailAccount { id: string; name: string; email: string; smtpHost: string; smtpPort: number; smtpSecure: boolean; smtpUsername: string; smtpPassword: string; // 암호화된 비밀번호 dailyLimit: number; status: 'active' | 'inactive' | 'suspended'; createdAt: string; updatedAt: string; } class MailAccountFileService { private accountsDir: string; constructor() { this.accountsDir = path.join(process.cwd(), 'uploads', 'mail-accounts'); this.ensureDirectoryExists(); } private async ensureDirectoryExists() { try { await fs.access(this.accountsDir); } catch { await fs.mkdir(this.accountsDir, { recursive: true }); } } private getAccountPath(id: string): string { return path.join(this.accountsDir, `${id}.json`); } async getAllAccounts(): Promise { await this.ensureDirectoryExists(); try { const files = await fs.readdir(this.accountsDir); const jsonFiles = files.filter(f => f.endsWith('.json')); const accounts = await Promise.all( jsonFiles.map(async (file) => { const content = await fs.readFile( path.join(this.accountsDir, file), 'utf-8' ); return JSON.parse(content) as MailAccount; }) ); return accounts.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime() ); } catch { return []; } } async getAccountById(id: string): Promise { try { const content = await fs.readFile(this.getAccountPath(id), 'utf-8'); return JSON.parse(content); } catch { return null; } } async createAccount( data: Omit ): Promise { const id = `account-${Date.now()}`; const now = new Date().toISOString(); // 비밀번호 암호화 const encryptedPassword = encryptionService.encrypt(data.smtpPassword); const account: MailAccount = { ...data, id, smtpPassword: encryptedPassword, createdAt: now, updatedAt: now, }; await fs.writeFile( this.getAccountPath(id), JSON.stringify(account, null, 2), 'utf-8' ); return account; } async updateAccount( id: string, data: Partial> ): Promise { const existing = await this.getAccountById(id); if (!existing) { return null; } // 비밀번호가 변경되면 암호화 if (data.smtpPassword && data.smtpPassword !== existing.smtpPassword) { data.smtpPassword = encryptionService.encrypt(data.smtpPassword); } const updated: MailAccount = { ...existing, ...data, id: existing.id, createdAt: existing.createdAt, updatedAt: new Date().toISOString(), }; await fs.writeFile( this.getAccountPath(id), JSON.stringify(updated, null, 2), 'utf-8' ); return updated; } async deleteAccount(id: string): Promise { try { await fs.unlink(this.getAccountPath(id)); return true; } catch { return false; } } async getAccountByEmail(email: string): Promise { const accounts = await this.getAllAccounts(); return accounts.find(a => a.email === email) || null; } async getActiveAccounts(): Promise { const accounts = await this.getAllAccounts(); return accounts.filter(a => a.status === 'active'); } /** * 비밀번호 복호화 */ decryptPassword(encryptedPassword: string): string { return encryptionService.decrypt(encryptedPassword); } } export const mailAccountFileService = new MailAccountFileService();