1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
|
import type { NextApiRequest, NextApiResponse } from "next";
import type { File as FormidableFile } from "formidable";
import formidable from "formidable";
import fs from "fs/promises";
import { createReport } from "@/lib/pdftron/serverSDK/createReport";
export const config = {
api: {
bodyParser: false, // ✅ 이게 false면 안 됨!
},
};
// 서버 사이드용 DRM 복호화 함수 (API 라우트 내부에 정의)
async function decryptBufferWithDRM(buffer: Buffer, originalFileName: string): Promise<Buffer> {
try {
// Buffer를 Blob으로 변환하여 FormData에 추가
const blob = new Blob([buffer]);
const file = new File([blob], originalFileName);
const formData = new FormData();
formData.append('file', file);
// 로컬 6543 포트에 drm-proxy 서버가 실행되고 있어야 함
const backendUrl = "http://localhost:6543/api/drm-proxy/decrypt";
console.log(`[DRM] 서버에서 파일 복호화 시도: ${originalFileName} (크기: ${buffer.length} bytes)`);
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] 서버에서 파일 복호화 성공: ${originalFileName} (결과 크기: ${decryptedBuffer.length} bytes)`);
return decryptedBuffer;
} catch (error) {
// 오류 발생시 로깅하며, 폴백으로 복호화되지 않은 원본 버퍼를 리턴
const errorMessage = error instanceof Error
? `${error.name}: ${error.message}`
: String(error);
console.error(`[DRM] 서버 복호화 오류: ${errorMessage}`, {
fileName: originalFileName,
fileSize: buffer.length,
remark: `
[정상 동작 안내]
DTS 개발 서버나 로컬 환경에서는 에러가 발생하는 것이 정상적인 동작입니다.
이 경우 원본 파일 버퍼가 그대로 반환됩니다.
[발생 가능한 에러 케이스]
1. DRM 백엔드 서버가 없는 경우 - CONNECTION_REJECTED 발생
2. DRM 중앙 서버와 통신 불가한 경우 - PARENT CERT 속성 추가 불가로 인한 백엔드측 500 에러
`,
error
});
return buffer; // 원본 버퍼 반환 (폴백)
}
}
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method !== "POST") {
return res.status(405).end();
}
try {
const form = formidable({ multiples: false });
form.parse(req, async (err, fields, files) => {
if (err) {
console.error(err);
return res.status(500).json({ error: "Error parsing form" });
}
try {
const fileName = fields?.customFileName?.[0] ?? "";
const reportDatas = JSON.parse(fields?.reportDatas?.[0] ?? "[]") as {
[key: string]: any;
}[];
const reportTempPath = fields?.reportTempPath?.[0] ?? "";
const reportCoverPage: FormidableFile | undefined = files?.file?.[0];
if (
!reportCoverPage ||
fileName.length === 0 ||
reportDatas.length === 0 ||
reportTempPath.length === 0
) {
return res.status(400).json({ error: "Invalid Report Data" });
}
// 원본 파일 읽기
const originalBuffer = await fs.readFile(reportCoverPage.filepath);
// DRM 복호화 처리
console.log(`[DRM] 파일 복호화 시작: ${reportCoverPage.originalFilename || 'unknown'}`);
const decryptedBuffer = await decryptBufferWithDRM(
originalBuffer,
reportCoverPage.originalFilename || 'document.docx'
);
// 복호화된 버퍼로 리포트 생성
const {
result,
buffer: pdfBuffer,
error,
} = await createReport(decryptedBuffer, reportTempPath, reportDatas);
if (result && pdfBuffer) {
res.setHeader("Content-Type", "application/pdf");
res.setHeader(
"Content-Disposition",
`attachment; filename="${fileName}"`
);
return res.send(Buffer.from(pdfBuffer));
}
return res.status(200).json({
success: false,
message: "Report 생성에 실패하였습니다.",
error,
});
} catch (e) {
console.log(e);
return res.status(400).json({ error: "Invalid additionalData" });
}
});
} catch (err) {
return res.status(401).end();
}
}
|