diff options
| author | joonhoekim <26rote@gmail.com> | 2025-08-18 01:06:37 +0000 |
|---|---|---|
| committer | joonhoekim <26rote@gmail.com> | 2025-08-18 01:06:37 +0000 |
| commit | b36330c94400f39ec9baed64b82a73bae58edbf2 (patch) | |
| tree | eea344d39b3101289ed4f6b74e0c98b6b33ef460 /lib | |
| parent | 5adc1df95f80fbec7a0b5bbee15448b10d5aec3a (diff) | |
(김준회) 파일업로드시 바이너리검증부 주석처리, knex webpack 한계로 인한 빌드 로그 경고 무시, 환경변수 오류 처리, 벤더 로그인 폼 사업자번호를 000 으로 수정, 유저 phone number 사이즈 늘림, 도커 DB 예시 추가
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/file-stroage.ts | 38 | ||||
| -rw-r--r-- | lib/shi-api/shi-api-utils.ts | 68 |
2 files changed, 64 insertions, 42 deletions
diff --git a/lib/file-stroage.ts b/lib/file-stroage.ts index c347ffe3..7bc9ef1c 100644 --- a/lib/file-stroage.ts +++ b/lib/file-stroage.ts @@ -194,31 +194,31 @@ class FileSecurityValidator { return { valid: true }; } - // 파일 내용 기본 검증 (매직 넘버 체크 + XSS 패턴 검사) + // 파일 내용 기본 검증 (매직 넘버 체크(비활성화) + XSS 패턴 검사) static async validateFileContent(buffer: Buffer, fileName: string): Promise<{ valid: boolean; error?: string }> { try { const extension = path.extname(fileName).toLowerCase().substring(1); - // 파일 시그니처 (매직 넘버) 검증 - const fileSignatures: Record<string, Buffer[]> = { - 'pdf': [Buffer.from([0x25, 0x50, 0x44, 0x46])], // %PDF - 'jpg': [Buffer.from([0xFF, 0xD8, 0xFF])], - 'jpeg': [Buffer.from([0xFF, 0xD8, 0xFF])], - 'png': [Buffer.from([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A])], - 'gif': [Buffer.from([0x47, 0x49, 0x46, 0x38])], // GIF8 - 'zip': [Buffer.from([0x50, 0x4B, 0x03, 0x04]), Buffer.from([0x50, 0x4B, 0x05, 0x06])], - }; + // 파일 시그니처 (매직 넘버) 검증 << DRM 파일 처리 불가로 주석 처리 + // const fileSignatures: Record<string, Buffer[]> = { + // 'pdf': [Buffer.from([0x25, 0x50, 0x44, 0x46])], // %PDF + // 'jpg': [Buffer.from([0xFF, 0xD8, 0xFF])], + // 'jpeg': [Buffer.from([0xFF, 0xD8, 0xFF])], + // 'png': [Buffer.from([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A])], + // 'gif': [Buffer.from([0x47, 0x49, 0x46, 0x38])], // GIF8 + // 'zip': [Buffer.from([0x50, 0x4B, 0x03, 0x04]), Buffer.from([0x50, 0x4B, 0x05, 0x06])], + // }; - const expectedSignatures = fileSignatures[extension]; - if (expectedSignatures) { - const hasValidSignature = expectedSignatures.some(signature => - buffer.subarray(0, signature.length).equals(signature) - ); + // const expectedSignatures = fileSignatures[extension]; + // if (expectedSignatures) { + // const hasValidSignature = expectedSignatures.some(signature => + // buffer.subarray(0, signature.length).equals(signature) + // ); - if (!hasValidSignature) { - return { valid: false, error: `파일 내용이 확장자와 일치하지 않습니다: ${extension}` }; - } - } + // if (!hasValidSignature) { + // return { valid: false, error: `파일 내용이 확장자와 일치하지 않습니다: ${extension}` }; + // } + // } // 실행 파일 패턴 검색 const executablePatterns = [ diff --git a/lib/shi-api/shi-api-utils.ts b/lib/shi-api/shi-api-utils.ts index 280a2fcb..3906883a 100644 --- a/lib/shi-api/shi-api-utils.ts +++ b/lib/shi-api/shi-api-utils.ts @@ -65,8 +65,8 @@ export const getAllNonsapUser = async () => { name: u.USR_NM || undefined, email: u.EMAIL_ADR || undefined, epId: u.MYSNG_ID || undefined, - deptCode: u.CH_DEPTCD || undefined, - deptName: u.CH_DEPTNM || undefined, + deptCode: u.DEPTCD || undefined, + deptName: u.DEPTNM || undefined, phone: u.TELNO || undefined, isAbsent, isDeletedOnNonSap: isDeleted, @@ -80,27 +80,49 @@ export const getAllNonsapUser = async () => { const mappedUsers = mappedRaw as InsertUser[]; if (mappedUsers.length > 0) { - await db.insert(users) - .values(mappedUsers) - .onConflictDoUpdate({ - target: users.nonsapUserId, - set: { - name: users.name, - employeeNumber: users.employeeNumber, - knoxId: users.knoxId, - epId: users.epId, - deptCode: users.deptCode, - deptName: users.deptName, - phone: users.phone, - nonsapUserId: users.nonsapUserId, - isAbsent: users.isAbsent, - isDeletedOnNonSap: users.isDeletedOnNonSap, - isActive: users.isActive, - isRegularEmployee: users.isRegularEmployee, - updatedAt: sql`now()`, - }, - }); - debugSuccess(`[UPSERT] users upserted=${mappedUsers.length} using key=nonsapUserId`); + // 배치 처리: 500개씩 분할하여 처리 (콜스택 크기 문제 대응) + const BATCH_SIZE = 500; + let totalUpserted = 0; + + for (let i = 0; i < mappedUsers.length; i += BATCH_SIZE) { + const batch = mappedUsers.slice(i, i + BATCH_SIZE); + + try { + await db.insert(users) + .values(batch) + .onConflictDoUpdate({ + target: users.nonsapUserId, + set: { + name: users.name, + employeeNumber: users.employeeNumber, + knoxId: users.knoxId, + epId: users.epId, + deptCode: users.deptCode, + deptName: users.deptName, + phone: users.phone, + nonsapUserId: users.nonsapUserId, + isAbsent: users.isAbsent, + isDeletedOnNonSap: users.isDeletedOnNonSap, + isActive: users.isActive, + isRegularEmployee: users.isRegularEmployee, + updatedAt: sql`now()`, + }, + }); + + totalUpserted += batch.length; + debugLog(`[BATCH ${Math.floor(i/BATCH_SIZE) + 1}] Processed ${batch.length} users (${totalUpserted}/${mappedUsers.length})`); + + // 배치 간 잠시 대기하여 시스템 부하 방지 + if (i + BATCH_SIZE < mappedUsers.length) { + await new Promise(resolve => setTimeout(resolve, 100)); + } + } catch (batchError) { + debugError(`[BATCH ${Math.floor(i/BATCH_SIZE) + 1}] Failed to process batch ${i}-${i+batch.length}`, batchError); + throw batchError; + } + } + + debugSuccess(`[UPSERT] users upserted=${totalUpserted} using key=nonsapUserId (processed in ${Math.ceil(mappedUsers.length/BATCH_SIZE)} batches)`); } else { debugWarn('[UPSERT] No users mapped for upsert (missing name/email or invalid USR_ID)'); } |
