7e88ddb858
Files fixed: - messages-recv.ts: 58 assertions → null guards, meId extraction, optional chaining - process-message.ts: 38 assertions → remoteJid/participant guards, proto field checks - chat-utils.ts: 31 assertions → proto field validation with Boom errors - messages-send.ts: 20 assertions → meId extraction, participant guards - chats.ts: 15 assertions → me guard, firstChild guard, jid guards - messages.ts: 14 assertions → originalFilePath guard, key guards - groups.ts: 12 assertions → attrs fallbacks with ?? - validate-connection.ts: 9 assertions → grouped proto field validation - generics.ts: 1 assertion → versionLine guard - history.ts: 2 assertions → key guards - libsignal.ts: 1 assertion → deviceId guard - sender-key-message.ts: 3 assertions → proto guards - UsyncBotProfileProtocol.ts: 2 assertions → attrs guards - example.ts: 3 assertions → optional chaining https://claude.ai/code/session_01E2cfX1N3sJgCJBTvzGazSG
101 lines
3.1 KiB
TypeScript
101 lines
3.1 KiB
TypeScript
import { calculateSignature, verifySignature } from 'libsignal/src/curve'
|
|
import { proto } from '../../../WAProto/index.js'
|
|
import { CiphertextMessage } from './ciphertext-message'
|
|
|
|
interface SenderKeyMessageStructure {
|
|
id: number
|
|
iteration: number
|
|
ciphertext: string | Buffer
|
|
}
|
|
|
|
export class SenderKeyMessage extends CiphertextMessage {
|
|
private readonly SIGNATURE_LENGTH = 64
|
|
private readonly messageVersion: number
|
|
private readonly keyId: number
|
|
private readonly iteration: number
|
|
private readonly ciphertext: Uint8Array
|
|
private readonly signature: Uint8Array
|
|
private readonly serialized: Uint8Array
|
|
|
|
constructor(
|
|
keyId?: number | null,
|
|
iteration?: number | null,
|
|
ciphertext?: Uint8Array | null,
|
|
signatureKey?: Uint8Array | null,
|
|
serialized?: Uint8Array | null
|
|
) {
|
|
super()
|
|
|
|
if (serialized) {
|
|
const version = serialized[0] ?? 0
|
|
const message = serialized.slice(1, serialized.length - this.SIGNATURE_LENGTH)
|
|
const signature = serialized.slice(-1 * this.SIGNATURE_LENGTH)
|
|
const senderKeyMessage = proto.SenderKeyMessage.decode(message).toJSON() as SenderKeyMessageStructure
|
|
|
|
this.serialized = serialized
|
|
this.messageVersion = (version & 0xff) >> 4
|
|
this.keyId = senderKeyMessage.id
|
|
this.iteration = senderKeyMessage.iteration
|
|
this.ciphertext =
|
|
typeof senderKeyMessage.ciphertext === 'string'
|
|
? Buffer.from(senderKeyMessage.ciphertext, 'base64')
|
|
: senderKeyMessage.ciphertext
|
|
this.signature = signature
|
|
} else {
|
|
if (ciphertext == null || keyId == null || iteration == null || signatureKey == null) {
|
|
throw new Error('Missing required parameters for SenderKeyMessage construction')
|
|
}
|
|
|
|
const version = (((this.CURRENT_VERSION << 4) | this.CURRENT_VERSION) & 0xff) % 256
|
|
const ciphertextBuffer = Buffer.from(ciphertext)
|
|
const message = proto.SenderKeyMessage.encode(
|
|
proto.SenderKeyMessage.create({
|
|
id: keyId,
|
|
iteration: iteration,
|
|
ciphertext: ciphertextBuffer
|
|
})
|
|
).finish()
|
|
|
|
const signature = this.getSignature(signatureKey, Buffer.concat([Buffer.from([version]), message]))
|
|
|
|
this.serialized = Buffer.concat([Buffer.from([version]), message, Buffer.from(signature)])
|
|
this.messageVersion = this.CURRENT_VERSION
|
|
this.keyId = keyId
|
|
this.iteration = iteration
|
|
this.ciphertext = ciphertextBuffer
|
|
this.signature = signature
|
|
}
|
|
}
|
|
|
|
public getKeyId(): number {
|
|
return this.keyId
|
|
}
|
|
|
|
public getIteration(): number {
|
|
return this.iteration
|
|
}
|
|
|
|
public getCipherText(): Uint8Array {
|
|
return this.ciphertext
|
|
}
|
|
|
|
public verifySignature(signatureKey: Uint8Array): void {
|
|
const part1 = this.serialized.slice(0, this.serialized.length - this.SIGNATURE_LENGTH)
|
|
const part2 = this.serialized.slice(-1 * this.SIGNATURE_LENGTH)
|
|
const res = verifySignature(signatureKey, part1, part2)
|
|
if (!res) throw new Error('Invalid signature!')
|
|
}
|
|
|
|
private getSignature(signatureKey: Uint8Array, serialized: Uint8Array): Uint8Array {
|
|
return Buffer.from(calculateSignature(signatureKey, serialized))
|
|
}
|
|
|
|
public serialize(): Uint8Array {
|
|
return this.serialized
|
|
}
|
|
|
|
public getType(): number {
|
|
return 4
|
|
}
|
|
}
|