본문 바로가기

react

password protect zip file 생성기 in Next.js

💡 api 응답 값으로 zip file (+password protect)을 만들어 보자 !

 

요구 사항은

엑셀 파일을 생성해야 하는데, 이때 보안상의 이유로 비밀번호를 달아야 한다.

엑셀 파일에다가 비밀번호를 설정할수 있는 라이브러리가 리액트나 nodejs에 있을거라 생각했는데 찾아도 발견하지 못했다.

여기서 고난이 시작됨 !

 

결과 적으로 적용한 방법은 다음과 같다.

 

1. api 통해서 내용에 해당하는 값을 들고온다.

2. next.js api 단에서 1️⃣ 번 응답값을 가지고 엑셀 파일을 만든다. (xlsx라이브러리 사용)

3. 서버에 해당 파일을 저장한다.

4. 리눅스 zip 명령어를 사용하여 zip 파일을 만든다.  이때 비밀번호 옵션을 걸어서 비밀번호도 걸어준다

5. 서버에 저장된 zip 파일을 읽어온다.

6. 프론트로 전달한다. 이때 buffer 데이터로 전달했다.

7. 브라우저에서는 응답으로 받은 buffer 데이터를 다시 파일로 변환한뒤 다운로드 처리한다.

 

🔺 child_process.exec 를 통한 zip 파일 생성 및 await

child_process.exec 함수를 통해서 zip 명령어를 실행했다.

그런데 명령어의 실행 뒤에 다시 해당 파일을 읽어와야 하기 때문에 동기처리가 필요하다.

import { exec } from 'child_process';

const execShellCommand = (cmd: string) => {
  const response = new Promise((resolve, reject) => {
    exec(cmd, (error, stdout, stderr) => {
      if (error) reject(new Error());
      else resolve(stdout ? stdout : stderr);
    });
  }).catch((e) => false);

  return response;
};


const exec = await execShellCommand(`zip -jrm -P ${password} ${path}/${filename}.zip ${path}/${filename}.xlsx`);

이렇게 서버에서 해당 커맨드 실행이 완료 된후, 파일을 읽어와서 응답으로 줬다.

 

🔺서버에 저장된 파일을 브라우저에 전달하고 다운로드 처리

import * as fs from 'fs';

const data = fs.readFileSync(`${path}/${filename}.zip`);

fs.readFileSync 함수를 사용하면 파일내용을 buffer 형식으로 읽어온다.

브라우저에 해당 값 그대로 전달하자.

 

네트워크단에서 이렇게 확인할 수 있다.

 

이제 이 버퍼 데이터를 다시 파일로 변환 한 뒤, 다운로드 처리해보자

const downloadBlob = (bytes: Uint8Array) => {
    let binary = '';
    const len = bytes.byteLength;
    for (let i = 0; i < len; i++) binary += String.fromCharCode(bytes[i]);

    const file = window.btoa(binary);
    const mimType = 'application/zip';
    const url = `data:${mimType};base64,` + file;
    const a = document.createElement('a');
    a.href = url;
    a.download = '파일명.zip';
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    window.URL.revokeObjectURL(url);
  };

const data = api응답;
downloadBlob(Buffer.from(data));

버퍼 데이터를 결과 적으로 base64값으로 변환한뒤 URL.revokeObjectURL 함수로 읽어오게 했다.

버퍼데이터를 다운로드 하는 방법은 자료가 많아서 쉽게 적용할수 있었다.

반응형