diff --git a/src/Signal/Group/group_cipher.ts b/src/Signal/Group/group_cipher.ts index b0839e0b..c9e0444f 100644 --- a/src/Signal/Group/group_cipher.ts +++ b/src/Signal/Group/group_cipher.ts @@ -1,4 +1,3 @@ -/* @ts-ignore */ import { decrypt, encrypt } from 'libsignal/src/crypto' import { SenderKeyMessage } from './sender-key-message' import { SenderKeyName } from './sender-key-name' diff --git a/src/Signal/Group/keyhelper.ts b/src/Signal/Group/keyhelper.ts index ea0b8a42..acf274c6 100644 --- a/src/Signal/Group/keyhelper.ts +++ b/src/Signal/Group/keyhelper.ts @@ -1,5 +1,4 @@ import * as nodeCrypto from 'crypto' -/* @ts-ignore */ import { generateKeyPair } from 'libsignal/src/curve' type KeyPairType = ReturnType diff --git a/src/Signal/Group/sender-chain-key.ts b/src/Signal/Group/sender-chain-key.ts index 18777a28..604c3aa8 100644 --- a/src/Signal/Group/sender-chain-key.ts +++ b/src/Signal/Group/sender-chain-key.ts @@ -1,4 +1,3 @@ -/* @ts-ignore */ import { calculateMAC } from 'libsignal/src/crypto' import { SenderMessageKey } from './sender-message-key' @@ -8,7 +7,7 @@ export class SenderChainKey { private readonly iteration: number private readonly chainKey: Buffer - constructor(iteration: number, chainKey: any) { + constructor(iteration: number, chainKey: Uint8Array | Buffer) { this.iteration = iteration if (Buffer.isBuffer(chainKey)) { // backported from @MartinSchere's PR diff --git a/src/Signal/Group/sender-key-message.ts b/src/Signal/Group/sender-key-message.ts index 878f2a91..8dc5b724 100644 --- a/src/Signal/Group/sender-key-message.ts +++ b/src/Signal/Group/sender-key-message.ts @@ -1,4 +1,3 @@ -/* @ts-ignore */ import { calculateSignature, verifySignature } from 'libsignal/src/curve' import { proto } from '../../../WAProto/index.js' import { CiphertextMessage } from './ciphertext-message' diff --git a/src/Signal/Group/sender-message-key.ts b/src/Signal/Group/sender-message-key.ts index c6fc2ca5..7336a6e0 100644 --- a/src/Signal/Group/sender-message-key.ts +++ b/src/Signal/Group/sender-message-key.ts @@ -1,4 +1,3 @@ -/* @ts-ignore */ import { deriveSecrets } from 'libsignal/src/crypto' export class SenderMessageKey { diff --git a/src/Signal/libsignal.ts b/src/Signal/libsignal.ts index 5ee09fa9..0678bdbe 100644 --- a/src/Signal/libsignal.ts +++ b/src/Signal/libsignal.ts @@ -1,6 +1,4 @@ -/* @ts-ignore */ import * as libsignal from 'libsignal' -/* @ts-ignore */ import { LRUCache } from 'lru-cache' import type { SignalAuthState, SignalKeyStoreWithTransaction } from '../Types' import type { SignalRepository } from '../Types/Signal' @@ -28,7 +26,7 @@ export function makeLibSignalRepository( const parsedKeys = auth.keys as SignalKeyStoreWithTransaction - function isLikelySyncMessage(addr: any): boolean { + function isLikelySyncMessage(addr: libsignal.ProtocolAddress): boolean { const key = addr.toString() // Only bypass for WhatsApp system addresses, not regular user contacts @@ -285,7 +283,7 @@ export function makeLibSignalRepository( return repository } -const jidToSignalProtocolAddress = (jid: string) => { +const jidToSignalProtocolAddress = (jid: string): libsignal.ProtocolAddress => { const decoded = jidDecode(jid)! const { user, device, server } = decoded @@ -303,7 +301,7 @@ const jidToSignalSenderKeyName = (group: string, user: string): SenderKeyName => function signalStorage( { creds, keys }: SignalAuthState, lidMapping: LIDMappingStore -): SenderKeyStore & Record { +): SenderKeyStore & libsignal.SignalStorage { return { loadSession: async (id: string) => { try { @@ -340,8 +338,7 @@ function signalStorage( return null }, - // TODO: Replace with libsignal.SessionRecord when type exports are added to libsignal - storeSession: async (id: string, session: any) => { + storeSession: async (id: string, session: libsignal.SessionRecord) => { await keys.set({ session: { [id]: session.serialize() } }) }, isTrustedIdentity: () => { @@ -384,7 +381,7 @@ function signalStorage( const { signedIdentityKey } = creds return { privKey: Buffer.from(signedIdentityKey.private), - pubKey: generateSignalPubKey(signedIdentityKey.public) + pubKey: Buffer.from(generateSignalPubKey(signedIdentityKey.public)) } } } diff --git a/src/Utils/crypto.ts b/src/Utils/crypto.ts index 6acd101f..0e0dc2a1 100644 --- a/src/Utils/crypto.ts +++ b/src/Utils/crypto.ts @@ -1,6 +1,5 @@ import { createCipheriv, createDecipheriv, createHash, createHmac, randomBytes } from 'crypto' -/* @ts-ignore */ -import * as libsignal from 'libsignal' +import * as curve from 'libsignal/src/curve' import { KEY_BUNDLE_TYPE } from '../Defaults' import type { KeyPair } from '../Types' @@ -13,21 +12,21 @@ export const generateSignalPubKey = (pubKey: Uint8Array | Buffer) => export const Curve = { generateKeyPair: (): KeyPair => { - const { pubKey, privKey } = libsignal.curve.generateKeyPair() + const { pubKey, privKey } = curve.generateKeyPair() return { private: Buffer.from(privKey), // remove version byte - public: Buffer.from((pubKey as Uint8Array).slice(1)) + public: Buffer.from(pubKey.slice(1)) } }, sharedKey: (privateKey: Uint8Array, publicKey: Uint8Array) => { - const shared = libsignal.curve.calculateAgreement(generateSignalPubKey(publicKey), privateKey) + const shared = curve.calculateAgreement(generateSignalPubKey(publicKey), privateKey) return Buffer.from(shared) }, - sign: (privateKey: Uint8Array, buf: Uint8Array) => libsignal.curve.calculateSignature(privateKey, buf), + sign: (privateKey: Uint8Array, buf: Uint8Array) => curve.calculateSignature(privateKey, buf), verify: (pubKey: Uint8Array, message: Uint8Array, signature: Uint8Array) => { try { - libsignal.curve.verifySignature(generateSignalPubKey(pubKey), message, signature) + curve.verifySignature(generateSignalPubKey(pubKey), message, signature) return true } catch (error) { return false @@ -129,15 +128,18 @@ export async function hkdf( expandedLength: number, info: { salt?: Buffer; info?: string } ): Promise { - // Ensure we have a Uint8Array for the key material - const inputKeyMaterial = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer) + // Normalize to a Uint8Array whose underlying buffer is a regular ArrayBuffer (not ArrayBufferLike) + // Cloning via new Uint8Array(...) guarantees the generic parameter is ArrayBuffer which satisfies WebCrypto types. + const inputKeyMaterial = new Uint8Array(buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer)) // Set default values if not provided const salt = info.salt ? new Uint8Array(info.salt) : new Uint8Array(0) const infoBytes = info.info ? new TextEncoder().encode(info.info) : new Uint8Array(0) - // Import the input key material - const importedKey = await subtle.importKey('raw', inputKeyMaterial, { name: 'HKDF' }, false, ['deriveBits']) + // Import the input key material (cast to BufferSource to appease TS DOM typings) + const importedKey = await subtle.importKey('raw', inputKeyMaterial as BufferSource, { name: 'HKDF' }, false, [ + 'deriveBits' + ]) // Derive bits using HKDF const derivedBits = await subtle.deriveBits( @@ -158,17 +160,19 @@ export async function derivePairingCodeKey(pairingCode: string, salt: Buffer): P // Convert inputs to formats Web Crypto API can work with const encoder = new TextEncoder() const pairingCodeBuffer = encoder.encode(pairingCode) - const saltBuffer = salt instanceof Uint8Array ? salt : new Uint8Array(salt) + const saltBuffer = new Uint8Array(salt instanceof Uint8Array ? salt : new Uint8Array(salt)) // Import the pairing code as key material - const keyMaterial = await subtle.importKey('raw', pairingCodeBuffer, { name: 'PBKDF2' }, false, ['deriveBits']) + const keyMaterial = await subtle.importKey('raw', pairingCodeBuffer as BufferSource, { name: 'PBKDF2' }, false, [ + 'deriveBits' + ]) // Derive bits using PBKDF2 with the same parameters // 2 << 16 = 131,072 iterations const derivedBits = await subtle.deriveBits( { name: 'PBKDF2', - salt: saltBuffer, + salt: saltBuffer as BufferSource, iterations: 2 << 16, hash: 'SHA-256' }, diff --git a/src/Utils/history.ts b/src/Utils/history.ts index b2cbe036..a60b0f79 100644 --- a/src/Utils/history.ts +++ b/src/Utils/history.ts @@ -17,7 +17,7 @@ export const downloadHistory = async (msg: proto.Message.IHistorySyncNotificatio bufferArray.push(chunk) } - let buffer = Buffer.concat(bufferArray) + let buffer: Buffer = Buffer.concat(bufferArray) // decompress buffer buffer = await inflatePromise(buffer) diff --git a/yarn.lock b/yarn.lock index 8c1dd43e..2edb9b2c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7339,11 +7339,11 @@ __metadata: "libsignal@git+https://github.com/whiskeysockets/libsignal-node": version: 2.0.1 - resolution: "libsignal@https://github.com/whiskeysockets/libsignal-node.git#commit=4d08331a833727c338c1a90041d17b870210dfae" + resolution: "libsignal@https://github.com/whiskeysockets/libsignal-node.git#commit=e81ecfc32eb74951d789ab37f7e341ab66d5fff1" dependencies: curve25519-js: "npm:^0.0.4" protobufjs: "npm:6.8.8" - checksum: 10c0/0c6bf1bb2255c3c4eb1e1c35f8a51b5a4b38b2c334178991add7f0e232ebc80c061d1571087348eaf57c34aa8db77d09bcf29eecbbe0c0a49b66aede546952ef + checksum: 10c0/d1ae7d8a5fadd6bb1c486d1b2ebc388967fee57c13f52b473127c1cbd9cd647b44545ff07c2b9cc49b3dea4e25ccfcfece31c526fdbdbf065837c85d189e97a0 languageName: node linkType: hard @@ -10557,22 +10557,22 @@ __metadata: linkType: hard "typescript@npm:^5.8.2": - version: 5.8.3 - resolution: "typescript@npm:5.8.3" + version: 5.9.2 + resolution: "typescript@npm:5.9.2" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10c0/5f8bb01196e542e64d44db3d16ee0e4063ce4f3e3966df6005f2588e86d91c03e1fb131c2581baf0fb65ee79669eea6e161cd448178986587e9f6844446dbb48 + checksum: 10c0/cd635d50f02d6cf98ed42de2f76289701c1ec587a363369255f01ed15aaf22be0813226bff3c53e99d971f9b540e0b3cc7583dbe05faded49b1b0bed2f638a18 languageName: node linkType: hard "typescript@patch:typescript@npm%3A^5.8.2#optional!builtin": - version: 5.8.3 - resolution: "typescript@patch:typescript@npm%3A5.8.3#optional!builtin::version=5.8.3&hash=5786d5" + version: 5.9.2 + resolution: "typescript@patch:typescript@npm%3A5.9.2#optional!builtin::version=5.9.2&hash=5786d5" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10c0/39117e346ff8ebd87ae1510b3a77d5d92dae5a89bde588c747d25da5c146603a99c8ee588c7ef80faaf123d89ed46f6dbd918d534d641083177d5fac38b8a1cb + checksum: 10c0/34d2a8e23eb8e0d1875072064d5e1d9c102e0bdce56a10a25c0b917b8aa9001a9cf5c225df12497e99da107dc379360bc138163c66b55b95f5b105b50578067e languageName: node linkType: hard