Files
InfiniteAPI/src/Signal/Group/sender-key-message.ts
T
Claude 7e88ddb858 fix(types): remove non-null assertions across 14 files
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
2026-02-09 00:05:13 +00:00

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
}
}