Added requestPairingCode method and handler

Fixed typo (trimUndefineds)
Added bytesToCrockford
Replaced advSecretKey with advKeyPair
Added pairingCode prop
Fixed formatting
Added pairing code example
This commit is contained in:
Alessandro Autiero
2023-07-16 18:35:46 +02:00
parent 0aaa0086f9
commit f498e1e56c
8 changed files with 293 additions and 30 deletions

View File

@@ -199,7 +199,7 @@ export const initAuthCreds = (): AuthenticationCreds => {
signedIdentityKey: identityKey,
signedPreKey: signedKeyPair(identityKey, 1),
registrationId: generateRegistrationId(),
advSecretKey: randomBytes(32).toString('base64'),
advKeyPair: Curve.generateKeyPair(),
processedHistoryMessages: [],
nextPreKeyId: 1,
firstUnuploadedPreKeyId: 1,
@@ -213,6 +213,7 @@ export const initAuthCreds = (): AuthenticationCreds => {
identityId: randomBytes(20),
registered: false,
backupToken: randomBytes(20),
registration: {} as never
registration: {} as never,
pairingCode: undefined
}
}

View File

@@ -2,7 +2,7 @@ import EventEmitter from 'events'
import { Logger } from 'pino'
import { proto } from '../../WAProto'
import { BaileysEvent, BaileysEventEmitter, BaileysEventMap, BufferedEventData, Chat, ChatUpdate, Contact, WAMessage, WAMessageStatus } from '../Types'
import { trimUndefineds } from './generics'
import { trimUndefined } from './generics'
import { updateMessageWithReaction, updateMessageWithReceipt } from './messages'
import { isRealMessage, shouldIncrementChatUnread } from './process-message'
@@ -209,7 +209,7 @@ function append<E extends BufferableEvent>(
for(const contact of eventData.contacts as Contact[]) {
const existingContact = data.historySets.contacts[contact.id]
if(existingContact) {
Object.assign(existingContact, trimUndefineds(contact))
Object.assign(existingContact, trimUndefined(contact))
} else {
const historyContactId = `c:${contact.id}`
const hasAnyName = contact.notify || contact.name || contact.verifiedName
@@ -321,14 +321,14 @@ function append<E extends BufferableEvent>(
}
if(upsert) {
upsert = Object.assign(upsert, trimUndefineds(contact))
upsert = Object.assign(upsert, trimUndefined(contact))
} else {
upsert = contact
data.contactUpserts[contact.id] = upsert
}
if(data.contactUpdates[contact.id]) {
upsert = Object.assign(data.contactUpdates[contact.id], trimUndefineds(contact))
upsert = Object.assign(data.contactUpdates[contact.id], trimUndefined(contact))
delete data.contactUpdates[contact.id]
}
}

View File

@@ -379,7 +379,7 @@ export const isWABusinessPlatform = (platform: string) => {
return platform === 'smbi' || platform === 'smba'
}
export function trimUndefineds(obj: any) {
export function trimUndefined(obj: any) {
for(const key in obj) {
if(typeof obj[key] === 'undefined') {
delete obj[key]
@@ -388,3 +388,54 @@ export function trimUndefineds(obj: any) {
return obj
}
const CROCKFORD_CHARACTERS = '123456789ABCDEFGHJKLMNPQRSTVWXYZ'
export function bytesToCrockford(buffer: Buffer): string {
let value = 0
let bitCount = 0
const crockford: string[] = []
for(let i = 0; i < buffer.length; i++) {
value = (value << 8) | (buffer[i] & 0xff)
bitCount += 8
while(bitCount >= 5) {
crockford.push(CROCKFORD_CHARACTERS.charAt((value >>> (bitCount - 5)) & 31))
bitCount -= 5
}
}
if(bitCount > 0) {
crockford.push(CROCKFORD_CHARACTERS.charAt((value << (5 - bitCount)) & 31))
}
return crockford.join('')
}
export async function derivePairingKey(pairingCode: string, salt: Buffer) {
const encoded = new TextEncoder().encode(pairingCode)
const cryptoKey = await crypto.subtle.importKey(
'raw',
encoded,
{
name: 'PBKDF2'
},
!1,
[
'deriveKey'
]
)
return await crypto.subtle.deriveKey({
name: 'PBKDF2',
hash: 'SHA-256',
salt: salt,
iterations: 2 << 16
}, cryptoKey, {
name: 'AES-CTR',
length: 256
}, false, [
'encrypt',
'decrypt'
])
}

View File

@@ -117,7 +117,7 @@ export const generateRegistrationNode = (
export const configureSuccessfulPairing = (
stanza: BinaryNode,
{ advSecretKey, signedIdentityKey, signalIdentities }: Pick<AuthenticationCreds, 'advSecretKey' | 'signedIdentityKey' | 'signalIdentities'>
{ advKeyPair, signedIdentityKey, signalIdentities }: Pick<AuthenticationCreds, 'advKeyPair' | 'signedIdentityKey' | 'signalIdentities'>
) => {
const msgId = stanza.attrs.id
@@ -137,7 +137,7 @@ export const configureSuccessfulPairing = (
const { details, hmac } = proto.ADVSignedDeviceIdentityHMAC.decode(deviceIdentityNode.content as Buffer)
// check HMAC matches
const advSign = hmacSign(details, Buffer.from(advSecretKey, 'base64'))
const advSign = hmacSign(details, advKeyPair.public)
if(Buffer.compare(hmac, advSign) !== 0) {
throw new Boom('Invalid account signature')
}