summaryrefslogtreecommitdiff
path: root/components/drm/drmUtils.ts
blob: 00cc83b28eeece413a884b4be3e394b62778f483 (plain)
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
/**
 * drmUtils.ts
 * 1. 복호화 엔드포인트 (/api/drm/decrypt)를 사용하는 함수
 * 2. 복호화 서버액션을 제공한다.
 * 
 * decryptWithServerAction(file): 서버액션을 사용하여 복호화한 파일을 응답하는 함수
 * isDRMFile(file): 파일이 DRM 암호화되어 있는지 검출하는 함수
 * 
 */

'use server';

// 서버 액션을 사용하여 복호화하는 함수
export async function decryptWithServerAction(file: File): Promise<ArrayBuffer> {
  try {
    const formData = new FormData();
    formData.append('file', file);

    // 로컬 6543 포트에 drm-proxy 서버가 실행되고 있어야 함
    const backendUrl = "http://localhost:6543/api/drm-proxy/decrypt";
    
    // 로깅은 스프링 자체적으로도 진행하지만(log 파일), 필요시 db 액션을 호출해 eVCP 데이터베이스에 저장
    console.log(`[DRM] 파일 복호화 시도: ${file.name} (크기: ${file.size} bytes, 타입: ${file.type})`);
    
    // 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로 받아서 리턴함
    const data = await response.arrayBuffer();
    console.log(`[DRM] 파일 복호화 성공: ${file.name} (결과 크기: ${data.byteLength} bytes)`);
    
    return data;
  } catch (error) {
    
    // 오류 발생시 로깅하며, 폴백으로 복호화되지 않은 파일을 리턴
    const errorMessage = error instanceof Error 
      ? `${error.name}: ${error.message}` 
      : String(error);
    
    console.error(`[DRM] 복호화 오류: ${errorMessage}`, {
      fileName: file.name,
      fileSize: file.size,
      fileType: file.type,
      remark: `
        [정상 동작 안내]
        DTS 개발 서버나 로컬 환경에서는 에러가 발생하는 것이 정상적인 동작입니다.
        이 경우 원본 파일의 arrayBuffer가 그대로 반환됩니다.

        [발생 가능한 에러 케이스]
        1. DRM 백엔드 서버가 없는 경우 - CONNECTION_REJECTED 발생
        2. DRM 중앙 서버와 통신 불가한 경우 - PARENT CERT 속성 추가 불가로 인한 백엔드측 500 에러
      `,
      error
    });
    
    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;
  }
}

/**
 * 파일이 DRM 암호화되어 있는지 검출하는 함수
 * DRM 복호화 시도를 통해 DRM 여부를 판단합니다.
 * 
 * @param file - 검출할 파일
 * @returns DRM 파일이면 true, 일반 파일이면 false
 */
export async function isDRMFile(file: File): Promise<boolean> {
  try {
    const formData = new FormData();
    formData.append('file', file);

    const backendUrl = "http://localhost:6543/api/drm-proxy/decrypt";
    
    console.log(`[DRM Check] 파일 DRM 검출 시도: ${file.name} (크기: ${file.size} bytes)`);
    
    // DRM 복호화 시도
    const response = await fetch(backendUrl, {
      method: "POST",
      body: formData,
    });

    // 응답이 성공적이면 DRM 파일로 판단
    if (response.ok) {
      const decryptedData = await response.arrayBuffer();
      
      // 복호화된 데이터 크기가 원본과 다르거나, 복호화 성공 로그가 있으면 DRM 파일
      const isDrmFile = decryptedData.byteLength !== file.size || 
                       decryptedData.byteLength > 0;
      
      console.log(`[DRM Check] DRM 파일로 판정: ${file.name} (원본: ${file.size} bytes, 복호화: ${decryptedData.byteLength} bytes)`);
      
      return isDrmFile;
    } else {
      // 응답이 실패하면 일반 파일로 판단
      const errorText = await response.text().catch(() => '응답 텍스트를 가져올 수 없음');
      console.log(`[DRM Check] 일반 파일로 판정: ${file.name} (응답 상태: ${response.status}, 오류: ${errorText})`);
      return false;
    }
  } catch (error) {
    // 네트워크 오류나 서버 연결 실패 시 일반 파일로 판단
    const errorMessage = error instanceof Error 
      ? `${error.name}: ${error.message}` 
      : String(error);
    
    console.log(`[DRM Check] 일반 파일로 판정 (오류 발생): ${file.name}`, {
      error: errorMessage,
      remark: `
        [DRM 검출 실패 케이스]
        1. DRM 백엔드 서버가 없는 경우 - 일반 파일로 판정
        2. DRM 중앙 서버와 통신 불가한 경우 - 일반 파일로 판정
        3. 네트워크 오류 - 일반 파일로 판정
      `
    });
    
    return false;
  }
}