diff options
| author | joonhoekim <26rote@gmail.com> | 2025-11-06 21:05:36 +0900 |
|---|---|---|
| committer | joonhoekim <26rote@gmail.com> | 2025-11-06 21:05:36 +0900 |
| commit | aac4e61398ed829e9dfa2c038f76405f92563d14 (patch) | |
| tree | f7300e55af0eff26c6f2e2d110e55f55a49a8bfb | |
| parent | 6440d8cefec035c204ac427c30d49e481713eff2 (diff) | |
(김준회) 견적 이메일 발송시, 첨부파일 복호화 처리
| -rw-r--r-- | components/drm/drmUtils.ts | 63 | ||||
| -rw-r--r-- | lib/rfq-last/service.ts | 41 |
2 files changed, 94 insertions, 10 deletions
diff --git a/components/drm/drmUtils.ts b/components/drm/drmUtils.ts index e0343535..4ba63090 100644 --- a/components/drm/drmUtils.ts +++ b/components/drm/drmUtils.ts @@ -64,3 +64,66 @@ export async function decryptWithServerAction(file: File): Promise<ArrayBuffer> return await file.arrayBuffer(); } } + +/** + * Buffer를 사용하여 복호화하는 함수 (서버 측 파일 처리용) + * @param fileBuffer - 복호화할 파일의 Buffer + * @param fileName - 원본 파일명 + * @returns 복호화된 Buffer + */ +export async function decryptBufferWithServerAction( + fileBuffer: Buffer, + fileName: string +): Promise<Buffer> { + try { + // Buffer를 Blob으로 변환하여 FormData에 추가 + const blob = new Blob([fileBuffer]); + const formData = new FormData(); + formData.append('file', blob, fileName); + + // 로컬 6543 포트에 drm-proxy 서버가 실행되고 있어야 함 + const backendUrl = "http://localhost:6543/api/drm-proxy/decrypt"; + + console.log(`[DRM] 파일 복호화 시도: ${fileName} (크기: ${fileBuffer.length} bytes)`); + + // POST 요청으로 파일을 file 이라는 키로 Body에 담아 전송하면, 복호화된 파일을 응답받음 + const response = await fetch(backendUrl, { + method: "POST", + body: formData, + }); + + if (!response.ok) { + const errorText = await response.text().catch(() => '응답 텍스트를 가져올 수 없음'); + throw new Error(`DRM 서버 응답 오류 [${response.status}]: ${errorText}`); + } + + // 응답을 ArrayBuffer로 받아서 Buffer로 변환 + const arrayBuffer = await response.arrayBuffer(); + const decryptedBuffer = Buffer.from(arrayBuffer); + console.log(`[DRM] 파일 복호화 성공: ${fileName} (결과 크기: ${decryptedBuffer.length} bytes)`); + + return decryptedBuffer; + } catch (error) { + // 오류 발생시 로깅하며, 폴백으로 복호화되지 않은 Buffer를 리턴 + const errorMessage = error instanceof Error + ? `${error.name}: ${error.message}` + : String(error); + + console.error(`[DRM] 복호화 오류: ${errorMessage}`, { + fileName: fileName, + fileSize: fileBuffer.length, + remark: ` + [정상 동작 안내] + DTS 개발 서버나 로컬 환경에서는 에러가 발생하는 것이 정상적인 동작입니다. + 이 경우 원본 Buffer가 그대로 반환됩니다. + + [발생 가능한 에러 케이스] + 1. DRM 백엔드 서버가 없는 경우 - CONNECTION_REJECTED 발생 + 2. DRM 중앙 서버와 통신 불가한 경우 - PARENT CERT 속성 추가 불가로 인한 백엔드측 500 에러 + `, + error + }); + + return fileBuffer; + } +}
\ No newline at end of file diff --git a/lib/rfq-last/service.ts b/lib/rfq-last/service.ts index 65ead12b..462b5604 100644 --- a/lib/rfq-last/service.ts +++ b/lib/rfq-last/service.ts @@ -3153,6 +3153,12 @@ export interface SendRfqParams { fileName: string; }>; hasToSendEmail?: boolean; // 이메일 발송 여부 + currentUser?: { // ⚠️ cronjob 환경을 위한 선택적 파라미터 + id: string | number; + name?: string | null; + email?: string | null; + epId?: string | null; + }; } export async function sendRfqToVendors({ @@ -3162,14 +3168,22 @@ export async function sendRfqToVendors({ attachmentIds, message, generatedPdfs, - hasToSendEmail = true + hasToSendEmail = true, + currentUser: providedUser // ⚠️ cronjob 환경에서는 payload로 받은 유저 정보 사용 }: SendRfqParams) { - const session = await getServerSession(authOptions); - if (!session?.user) { - throw new Error("인증이 필요합니다."); - } + let currentUser; - const currentUser = session.user; + if (providedUser) { + // ✅ Cronjob 환경: payload에서 받은 유저 정보 사용 + currentUser = providedUser; + } else { + // ✅ 일반 환경: session에서 유저 정보 가져오기 + const session = await getServerSession(authOptions); + if (!session?.user) { + throw new Error("인증이 필요합니다."); + } + currentUser = session.user; + } try { // 1. RFQ 기본 정보 조회 (트랜잭션 외부) @@ -4183,13 +4197,20 @@ async function handleRfqSendEmail({ ? path.join(process.cwd(), `public`, cleanPath) : path.join(`${process.env.NAS_PATH}`, cleanPath); + // 파일 읽기 const fileBuffer = await fs.readFile(fullPath); + + // DRM 복호화 처리 + const fileName = revision.originalFileName || `${attachment.attachmentType}_${attachment.serialNo}`; + const { decryptBufferWithServerAction } = await import('@/components/drm/drmUtils'); + const decryptedBuffer = await decryptBufferWithServerAction(fileBuffer, fileName); + emailAttachmentsList.push({ - filename: revision.originalFileName || `${attachment.attachmentType}_${attachment.serialNo}`, - content: fileBuffer + filename: fileName, + content: decryptedBuffer }); } catch (error) { - console.error(`이메일 첨부파일 읽기 실패: ${cleanPath}`, error); + console.error(`이메일 첨부파일 처리 실패: ${revision.filePath || 'unknown'}`, error); } } } @@ -5367,7 +5388,7 @@ export async function getAvlVendorsForRfq(rfqId: number) { console.error("AVL 벤더 조회 오류:", error); return { success: false, - error: "AVL 벤더 정보를 가져오는 중 오류가 발생했습니다." + error: "-" }; } } |
