summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjoonhoekim <26rote@gmail.com>2025-11-06 21:05:36 +0900
committerjoonhoekim <26rote@gmail.com>2025-11-06 21:05:36 +0900
commitaac4e61398ed829e9dfa2c038f76405f92563d14 (patch)
treef7300e55af0eff26c6f2e2d110e55f55a49a8bfb
parent6440d8cefec035c204ac427c30d49e481713eff2 (diff)
(김준회) 견적 이메일 발송시, 첨부파일 복호화 처리
-rw-r--r--components/drm/drmUtils.ts63
-rw-r--r--lib/rfq-last/service.ts41
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: "-"
};
}
}