101arrowz / fflate

High performance (de)compression in an 8kB package
https://101arrowz.github.io/fflate
MIT License
2.21k stars 77 forks source link

[client side] [encrypted] 🔒when extract zip file - check if the zip file is encrypted or protected by a password #157

Closed loclv closed 1 year ago

loclv commented 1 year ago

What can't you do right now?

Thank you for awesome work!

I want to check if the zip file is encrypted or protected by a password.

So, when I read that file, the error occurred. The error message should be exported from the library (fflate).

An optimal solution

import {
  unzipSync,
  ERR_ENCRYPTED,
  ERR_INVALID_PASSWORD,
  Unzipped,
} from 'fflate';

export const unzip = (
  file: Uint8Array,
  password?: string
): string | undefined | never | Unzipped => {
  let unzipFile: undefined | Unzipped;

  try {
    unzipFile = unzipSync(file, { password });
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
  } catch (error: any) {
    console.log('🚀 ~ error', error);

    if (
      error.message === ERR_ENCRYPTED ||
      error.message === ERR_INVALID_PASSWORD
    ) {
      return error.message;
    } else {
      throw error;
    }
  }

  return unzipFile;
};

(How) is this done by other libraries?

I searched for the solution and found this one: https://stackoverflow.com/questions/28063494/extract-password-protected-zip-file-using-javascript-client-side

import {
  ZipReader,
  BlobWriter,
  BlobReader,
  ERR_ENCRYPTED,
  ERR_INVALID_PASSWORD,
} from '@zip.js/zip.js';

/**
 * Verify that using password.
 *
 * @param file - File
 * @param password - optional password
 * @returns true if using password
 */
export const isZipFileUsingPassword = async (
  file: Blob,
  password?: string
): Promise<boolean> => {
  let reader: undefined | ZipReader<Blob>;

  try {
    reader = new ZipReader(new BlobReader(file), { password });
    const entries = await reader.getEntries();

    for (const entry of entries) {
      try {
        await entry.getData(new BlobWriter());
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
      } catch (error: any) {
        console.log('zip - reader:', error.message);

        if (
          error.message === ERR_ENCRYPTED ||
          error.message === ERR_INVALID_PASSWORD
        ) {
          return true;
        } else {
          throw error;
        }
      }
    }
  } finally {
    if (reader) await reader.close();
  }

  return false;
};
101arrowz commented 1 year ago

I don't plan to add support for encrypted archives but throwing errors when they're encountered should be possible. I'll look into it.

loclv commented 1 year ago

Thank you for your quick answer.