Nodejs crypto.getHashes() returns 一个空数组

Nodejs crypto.getHashes() returns an empty array

我在使用 exceljs' sheet protection 功能时遇到错误 – Error: Hash algorithm 'sha512' not supported!。查看它的源文件后,我发现了错误的原因:crypto.getHashes() 正在返回一个空数组。我似乎找不到解决方案,也找不到空数组的原因,有什么想法吗?

节点 v11.2.0

ExcelJS v3.6.0

src/routes/export-excel/customer.ts

import ExcelJS from "exceljs";

const workbook = new ExcelJS.Workbook();

// workbook config

workbook.eachSheet(async (worksheet, sheetId) => {
  worksheet.eachRow((row, rowNumber) => {
    row.eachCell((cell, colNumber) => {
      switch (exportCols.getCodes()[colNumber - 1]) {
         // other case statements
         case "date_created":
         case "date_modified":
           cell.protection = { locked: false }; // locks the cells under the date created & modified columns
           break;
      }
    })
    await worksheet.protect("passWord123", {
        selectLockedCells: false,
        formatCells: true,
        insertRows: true,
        // other config props 
      });
  })
})

exceljs lib - 保护方法的定义

node_modules/exceljs/lib/utils/worksheet.js Worksheet.protect

// Worksheet Protection
  protect(password, options) {
    // TODO: make this function truly async
    // perhaps marshal to worker thread or something
    return new Promise(resolve => {
      this.sheetProtection = {
        sheet: true,
      };
      if (password) {
        this.sheetProtection.algorithmName = 'SHA-512';
        this.sheetProtection.saltValue = Encryptor.randomBytes(16).toString('base64');
        this.sheetProtection.spinCount = 100000;
        this.sheetProtection.hashValue = Encryptor.convertPasswordToHash(password, 'SHA512', this.sheetProtection.saltValue, this.sheetProtection.spinCount);
      }
      if (options) {
        this.sheetProtection = Object.assign(this.sheetProtection, options);
      }
      resolve();
    });
  }

exceljs 库 - convertPasswordToHash 方法的定义

node_modules/exceljs/lib/utils/encryptor.js Encryptor.convertPasswordToHash

convertPasswordToHash(password, hashAlgorithm, saltValue, spinCount) {
    hashAlgorithm = hashAlgorithm.toLowerCase();
    const hashes = crypto.getHashes();
    console.log("supported hashes", hashes) // <== hashes was empty w/c caused the 'Hash algorithm '${hashAlgorithm}' not supported!' error to be thrown
    if (hashes.indexOf(hashAlgorithm) < 0) {
      throw new Error(`Hash algorithm '${hashAlgorithm}' not supported!`);
    }

    // Password must be in unicode buffer
    const passwordBuffer = Buffer.from(password, 'utf16le');
    // Generate the initial hash
    let key = this.hash(
      hashAlgorithm,
      Buffer.from(saltValue, 'base64'),
      passwordBuffer
    );
    // Now regenerate until spin count
    for (let i = 0; i < spinCount; i++) {
      const iterator = Buffer.alloc(4);
      // this is the 'special' element of Excel password hashing
      // that stops us from using crypto.pbkdf2()
      iterator.writeUInt32LE(i, 0);
      key = this.hash(hashAlgorithm, key, iterator);
    }
    return key.toString('base64');
  }

如果有人需要更多说明,请不要犹豫,在下方发表评论。

如有任何帮助,我们将不胜感激。

有个bug on an unrelated project that suggests crypto.getHashes can return an empty array if the array prototype has been modified. In the bug report, it was due to the use of collections.js.

通过您自己的代码或在 crypto 模块之前导入的第三方模块修改数组原型,可能导致 crypto.getHashes 到 return 一个空数组。