fix: handle invalid signatureKeyPublic types in sender-key-state AND fix handling chain key objects for skmsg group message decryption (#1760)
* fix: handle invalid signatureKeyPublic types in sender-key-state
- added extra check to ensure signatureKeyPublic is either a base64 string or a Buffer
- fallback to empty buffer when unexpected object type is received
- prevents ERR_INVALID_ARG_TYPE error in Buffer.from
* fix: lint
* adjusted based on @jlucaso1 recommmendation
* fix: handle chain key objects for skmsg group message decryption
previously, some sender chain keys were stored or retrieved as plain objects
(e.g. { '0': 85, '1': 100, ... }) instead of Buffers. this caused
"ERR_INVALID_ARG_TYPE" during initial decryption of skmsg group messages.
this fixes any chain key object is converted to a proper Buffer
before being passed to SenderChainKey.
* fix: add more robust checks and fallbacks
* hacky fix(sender-key-state): normalize signing pubkey as Buffer with 0x05 prefix
a little hacky fix that ensures getSigningKeyPublic always returns a proper Buffer to satisfy libsignal.
adds a fallback to prepend 0x05 when only a 32-byte key is present, avoiding
"Invalid public key" errors and TS type issues around Uint8Array vs Buffer.
This commit is contained in:
@@ -10,12 +10,14 @@ export class SenderChainKey {
|
|||||||
|
|
||||||
constructor(iteration: number, chainKey: any) {
|
constructor(iteration: number, chainKey: any) {
|
||||||
this.iteration = iteration
|
this.iteration = iteration
|
||||||
if (chainKey instanceof Buffer) {
|
if (Buffer.isBuffer(chainKey)) {
|
||||||
this.chainKey = chainKey
|
this.chainKey = chainKey
|
||||||
} else if (chainKey instanceof Uint8Array) {
|
} else if (chainKey instanceof Uint8Array) {
|
||||||
this.chainKey = Buffer.from(chainKey)
|
this.chainKey = Buffer.from(chainKey)
|
||||||
|
} else if (chainKey && typeof chainKey === 'object') {
|
||||||
|
this.chainKey = Buffer.from(Object.values(chainKey))
|
||||||
} else {
|
} else {
|
||||||
this.chainKey = Buffer.from(chainKey || [])
|
this.chainKey = Buffer.alloc(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,17 +30,25 @@ export class SenderKeyState {
|
|||||||
constructor(
|
constructor(
|
||||||
id?: number | null,
|
id?: number | null,
|
||||||
iteration?: number | null,
|
iteration?: number | null,
|
||||||
chainKey?: Uint8Array | null,
|
chainKey?: Uint8Array | null | string,
|
||||||
signatureKeyPair?: { public: Uint8Array; private: Uint8Array } | null,
|
signatureKeyPair?: { public: Uint8Array | string; private: Uint8Array | string } | null,
|
||||||
signatureKeyPublic?: Uint8Array | null,
|
signatureKeyPublic?: Uint8Array | string | null,
|
||||||
signatureKeyPrivate?: Uint8Array | null,
|
signatureKeyPrivate?: Uint8Array | string | null,
|
||||||
senderKeyStateStructure?: SenderKeyStateStructure | null
|
senderKeyStateStructure?: SenderKeyStateStructure | null
|
||||||
) {
|
) {
|
||||||
|
const toBuffer = (val: any) => {
|
||||||
|
if (!val) return Buffer.alloc(0)
|
||||||
|
if (typeof val === 'string') return Buffer.from(val, 'base64')
|
||||||
|
if (val instanceof Uint8Array || Array.isArray(val)) return Buffer.from(val)
|
||||||
|
return Buffer.alloc(0)
|
||||||
|
}
|
||||||
|
|
||||||
if (senderKeyStateStructure) {
|
if (senderKeyStateStructure) {
|
||||||
if (!Array.isArray(senderKeyStateStructure.senderMessageKeys)) {
|
this.senderKeyStateStructure = {
|
||||||
this.senderKeyStateStructure = { ...senderKeyStateStructure, senderMessageKeys: [] }
|
...senderKeyStateStructure,
|
||||||
} else {
|
senderMessageKeys: Array.isArray(senderKeyStateStructure.senderMessageKeys)
|
||||||
this.senderKeyStateStructure = senderKeyStateStructure
|
? senderKeyStateStructure.senderMessageKeys
|
||||||
|
: []
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (signatureKeyPair) {
|
if (signatureKeyPair) {
|
||||||
@@ -52,19 +60,12 @@ export class SenderKeyState {
|
|||||||
|
|
||||||
const senderChainKeyStructure: SenderChainKeyStructure = {
|
const senderChainKeyStructure: SenderChainKeyStructure = {
|
||||||
iteration: iteration || 0,
|
iteration: iteration || 0,
|
||||||
seed: chainKey || Buffer.alloc(0)
|
seed: chainKey ? toBuffer(chainKey) : Buffer.alloc(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
const signingKeyStructure: SenderSigningKeyStructure = {
|
const signingKeyStructure: SenderSigningKeyStructure = {
|
||||||
public:
|
public: toBuffer(signatureKeyPublic),
|
||||||
typeof signatureKeyPublic === 'string'
|
private: signatureKeyPrivate ? toBuffer(signatureKeyPrivate) : undefined
|
||||||
? Buffer.from(signatureKeyPublic, 'base64')
|
|
||||||
: signatureKeyPublic || Buffer.alloc(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (signatureKeyPrivate) {
|
|
||||||
signingKeyStructure.private =
|
|
||||||
typeof signatureKeyPrivate === 'string' ? Buffer.from(signatureKeyPrivate, 'base64') : signatureKeyPrivate
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.senderKeyStateStructure = {
|
this.senderKeyStateStructure = {
|
||||||
@@ -95,16 +96,29 @@ export class SenderKeyState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getSigningKeyPublic(): Buffer {
|
public getSigningKeyPublic(): Buffer {
|
||||||
const publicKey = this.senderKeyStateStructure.senderSigningKey.public
|
let key = this.senderKeyStateStructure.senderSigningKey.public
|
||||||
if (publicKey instanceof Buffer) {
|
|
||||||
return publicKey
|
// normalize into Buffer
|
||||||
} else if (publicKey instanceof Uint8Array) {
|
if (!(key instanceof Buffer)) {
|
||||||
return Buffer.from(publicKey)
|
if (key instanceof Uint8Array) {
|
||||||
} else if (typeof publicKey === 'string') {
|
key = Buffer.from(key)
|
||||||
return Buffer.from(publicKey, 'base64')
|
} else if (typeof key === 'string') {
|
||||||
|
key = Buffer.from(key, 'base64')
|
||||||
|
} else {
|
||||||
|
key = Buffer.from(key || [])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Buffer.from(publicKey || [])
|
const publicKey = key as Buffer
|
||||||
|
|
||||||
|
if (publicKey.length === 32) {
|
||||||
|
const fixed = Buffer.alloc(33)
|
||||||
|
fixed[0] = 0x05
|
||||||
|
publicKey.copy(fixed, 1)
|
||||||
|
return fixed
|
||||||
|
}
|
||||||
|
|
||||||
|
return publicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSigningKeyPrivate(): Buffer | undefined {
|
public getSigningKeyPrivate(): Buffer | undefined {
|
||||||
|
|||||||
@@ -1159,11 +1159,11 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
|
|||||||
const altServer = jidDecode(alt)?.server
|
const altServer = jidDecode(alt)?.server
|
||||||
const lidMapping = signalRepository.getLIDMappingStore()
|
const lidMapping = signalRepository.getLIDMappingStore()
|
||||||
if (altServer === 'lid') {
|
if (altServer === 'lid') {
|
||||||
if (typeof await lidMapping.getPNForLID(alt) == "string") {
|
if (typeof (await lidMapping.getPNForLID(alt)) === 'string') {
|
||||||
await lidMapping.storeLIDPNMapping(alt, msg.key.participant || msg.key.remoteJid!)
|
await lidMapping.storeLIDPNMapping(alt, msg.key.participant || msg.key.remoteJid!)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (typeof await lidMapping.getLIDForPN(alt) == "string") {
|
if (typeof (await lidMapping.getLIDForPN(alt)) === 'string') {
|
||||||
await lidMapping.storeLIDPNMapping(msg.key.participant || msg.key.remoteJid!, alt)
|
await lidMapping.storeLIDPNMapping(msg.key.participant || msg.key.remoteJid!, alt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user