diff options
| author | joonhoekim <26rote@gmail.com> | 2025-10-21 18:37:46 +0900 |
|---|---|---|
| committer | joonhoekim <26rote@gmail.com> | 2025-10-21 18:37:46 +0900 |
| commit | 9d0f0304b744f17c2c346ba5a52ee6745a9f51af (patch) | |
| tree | eba24f5df071d77af5c88a8879f0f0ad9ff5c26d | |
| parent | cf77558c0ccc5c0c1bc3cdd6edd9a0475e1970c8 (diff) | |
(김준회) fix: EDP 보고서 관리: 템플릿 파일 못찾는 문제 처리
| -rw-r--r-- | lib/pdftron/serverSDK/createReport.ts | 30 | ||||
| -rw-r--r-- | pages/api/pdftron/createVendorDataReports.ts | 15 |
2 files changed, 42 insertions, 3 deletions
diff --git a/lib/pdftron/serverSDK/createReport.ts b/lib/pdftron/serverSDK/createReport.ts index 412ada87..afcec7a2 100644 --- a/lib/pdftron/serverSDK/createReport.ts +++ b/lib/pdftron/serverSDK/createReport.ts @@ -1,4 +1,5 @@ const { PDFNet } = require("@pdftron/pdfnet-node"); +const path = require("path"); type CreateReport = ( coverPage: Buffer, @@ -12,6 +13,26 @@ type CreateReport = ( error?: any; }>; +// 웹 경로를 실제 파일 시스템 경로로 변환 +function convertWebPathToFilePath(webPath: string): string { + const isProduction = process.env.NODE_ENV === "production"; + const nasPath = process.env.NAS_PATH || "/evcp_nas"; + + // /api/files/vendorFormData/xxx.docx → vendorFormData/xxx.docx + // /vendorFormData/xxx.docx → vendorFormData/xxx.docx + let relativePath = webPath + .replace(/^\/api\/files\//, '') // 운영 환경 경로 제거 + .replace(/^\//, ''); // 개발 환경 슬래시 제거 + + if (isProduction) { + // 운영: /evcp_nas/vendorFormData/xxx.docx + return path.join(nasPath, relativePath); + } else { + // 개발: public/vendorFormData/xxx.docx + return path.join(process.cwd(), "public", relativePath); + } +} + export const createReport: CreateReport = async ( coverPage, reportTempPath, @@ -37,8 +58,15 @@ export const createReport: CreateReport = async ( for (const reportData of reportDatas) { const resportDataJson = JSON.stringify(reportData); + // 웹 경로를 실제 파일 시스템 경로로 변환 + const actualFilePath = convertWebPathToFilePath(reportTempPath); + + console.log(`📄 템플릿 파일 경로 변환:`); + console.log(` - 웹 경로: ${reportTempPath}`); + console.log(` - 실제 경로: ${actualFilePath}`); + const templateDoc = await PDFNet.Convert.createOfficeTemplateWithPath( - "public" + reportTempPath, + actualFilePath, options ); diff --git a/pages/api/pdftron/createVendorDataReports.ts b/pages/api/pdftron/createVendorDataReports.ts index e145b5d5..f873bd50 100644 --- a/pages/api/pdftron/createVendorDataReports.ts +++ b/pages/api/pdftron/createVendorDataReports.ts @@ -90,12 +90,23 @@ function validateFileSize(size: number): { valid: boolean; error?: string } { function validateDirectory(directory: string): { valid: boolean; error?: string } { const normalizedDir = path.normalize(directory).replace(/^\/+/, ''); + // 경로 탐색 공격 방지 if (normalizedDir.includes('..') || normalizedDir.includes('//')) { return { valid: false, error: "안전하지 않은 디렉터리 경로입니다" }; } - if (path.isAbsolute(directory)) { - return { valid: false, error: "절대 경로는 사용할 수 없습니다" }; + // 절대 경로 검증 (단, 허용된 웹 경로 패턴은 제외) + const allowedPatterns = [ + /^\/api\/files\//, // 운영 환경: /api/files/vendorFormData/... + /^\/vendorFormData\//, // 개발 환경: /vendorFormData/... + /^\/[\w-]+\//, // 기타 상대 웹 경로: /directory/... + ]; + + const isAllowedWebPath = allowedPatterns.some(pattern => pattern.test(directory)); + + // Windows 절대 경로(C:\...) 또는 허용되지 않은 Unix 절대 경로 차단 + if (path.isAbsolute(directory) && !isAllowedWebPath) { + return { valid: false, error: "절대 파일 시스템 경로는 사용할 수 없습니다" }; } return { valid: true }; |
