网站搜索

keepass - 如何在 TypeScript 5.7 中将 “Buffer” 转换为 “ArrayBuffer”?


根据 TypeScript 5.7 的公告,我现在受到了 ES2024 对缓冲区(Buffers)的更改的影响。尤其是缓冲区泛型(Buffer Generics)的这一更改。

我正在使用一个 KeePass 文件。为此,我通过 npm 包 "kdbxweb" "^2.1.1" 加载并打开该文件。
环境:"typescript": "^5.7.3","@types/node": "^22.10.5"。(即当前最新版本)

import fs from 'fs';
import path from 'path';
import * as kdbxweb from 'kdbxweb';

async getClientSecret(): Promise<string> {

    const fileBuffer: Buffer<ArrayBufferLike> = fs.readFileSync(KeePassFilePath);
    const keePassFileBuffer: ArrayBufferLike = fileBuffer.buffer;
    const keePassDB: kdbxweb.Kdbx = await kdbxweb.Kdbx.load(keePassFileBuffer, new kdbxweb.Credentials(kdbxweb.ProtectedValue.fromString(myPW)));
    // ...
}

在升级到“ES2024”(通过“ESNext”)后,npx tsc 报错:

error TS2345: Argument of type 'ArrayBufferLike' is not assignable to parameter of type 'ArrayBuffer'.
      Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': resizable, resize, detached, transfer, transferToFixedLength

我不知道如何解决这个问题。库的 load 函数声明为:

static load(data: ArrayBuffer, credentials: KdbxCredentials, options?: {
        preserveXml?: boolean;
    }): Promise<Kdbx>;

当 fs.readFileSync() 返回一个 Buffer<ArrayBufferLike>(来自 "@types/node": "^22.10.5"),这会使 buffer 属性返回一个 ArrayBufferLike。

我如何才能将它们合并在一起(不期望出现 TS 错误或将其转换为 unknown 等)?也就是说,如何将 Buffer<ArrayBufferLike> 正确地转换为 ArrayBuffer?


盲目转换为

const fileBuffer = fs.readFileSync(KeePassFilePath) as Buffer<ArrayBuffer>;

确实可以消除错误,但我怎么知道正确的实际类型呢?想象其他供应商,他们并没有提供某种保证说这是一个真正的 ArrayBuffer。所以这对我来说不是一个可行的解决方案。

答案#1

在你的代码中,你直接使用了 KeePassFileBuffer.buffer,这可能会导致内容不匹配的潜在问题,因为这是内部的 ArrayBuffer,可能包含额外的数据。按照你使用的方式,这种情况不太可能发生,但最好确保提取相关部分。

这就是你如何将 Buffer<ArrayBufferLike> 转换为 ArrayBuffer:

import fs from 'fs/promises';
import path from 'path';
import * as kdbxweb from 'kdbxweb';
import {ProtectedValue} from "kdbxweb";

// Convert Node.js Buffer to ArrayBuffer
function bufferToArrayBuffer(buffer: Buffer): ArrayBuffer {
  return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength) as ArrayBuffer;
}

// And apply that to your code
class SomeClass {

  private keepassPassword: ProtectedValue = ProtectedValue.fromString('123');

  async getClientSecret(): Promise<string> {

    const KeePassFileBuffer = await fs.readFile(path.resolve('user.kdbx'));
    const keePassDB: kdbxweb.Kdbx = await kdbxweb.Kdbx.load(bufferToArrayBuffer(KeePassFileBuffer), new kdbxweb.Credentials(this.keepassPassword));
    // ....
    return '?';
  }
}

这不直接与你的问题相关,但请注意我切换到了异步的 Node.js API fs/promises,它更好地支持 promises。

答案#2

以下方法似乎可行并能满足类型检查器,但它可能不是最有效的方式,因为它涉及创建几个 Uint8Arrays。

const fileBuffer: ArrayBufferLike = new SharedArrayBuffer(16);
const ui8Array: Uint8Array<ArrayBufferLike> = new Uint8Array(fileBuffer);
const actualArrayBuffer: ArrayBuffer = new ArrayBuffer(ui8Array.length);
const actualArrayBufferView: Uint8Array<ArrayBuffer> = new Uint8Array(actualArrayBuffer);
actualArrayBufferView.set(ui8Array);

// actualArrayBuffer now holds the contents of fileBuffer, but is of type ArrayBuffer