diff --git a/src/Socket/socket.ts b/src/Socket/socket.ts index b13775d..a923b29 100644 --- a/src/Socket/socket.ts +++ b/src/Socket/socket.ts @@ -5,8 +5,8 @@ import WebSocket from 'ws' import { proto } from '../../WAProto' import { DEF_CALLBACK_PREFIX, DEF_TAG_PREFIX, DEFAULT_ORIGIN, INITIAL_PREKEY_COUNT, MIN_PREKEY_COUNT } from '../Defaults' import { AuthenticationCreds, BaileysEventEmitter, BaileysEventMap, DisconnectReason, SocketConfig } from '../Types' -import { addTransactionCapability, bindWaitForConnectionUpdate, BufferJSON, configureSuccessfulPairing, Curve, generateLoginNode, generateMdTagPrefix, generateRegistrationNode, getNextPreKeysNode, makeNoiseHandler, printQRIfNecessaryListener, promiseTimeout, useSingleFileAuthState } from '../Utils' -import { assertNodeErrorFree, BinaryNode, encodeBinaryNode, getBinaryNodeChild, S_WHATSAPP_NET } from '../WABinary' +import { addTransactionCapability, bindWaitForConnectionUpdate, configureSuccessfulPairing, Curve, generateLoginNode, generateMdTagPrefix, generateRegistrationNode, getNextPreKeysNode, makeNoiseHandler, printQRIfNecessaryListener, promiseTimeout, useSingleFileAuthState } from '../Utils' +import { assertNodeErrorFree, BinaryNode, encodeBinaryNode, getBinaryNodeChild, getBinaryNodeChildren, S_WHATSAPP_NET } from '../WABinary' /** * Connects to WA servers and performs: @@ -200,8 +200,8 @@ export const makeSocket = ({ await sendRawMessage( proto.HandshakeMessage.encode({ clientFinish: { - static: new Uint8Array(keyEnc), - payload: new Uint8Array(payloadEnc), + static: keyEnc, + payload: payloadEnc, }, }).finish() ) @@ -442,7 +442,8 @@ export const makeSocket = ({ } await sendNode(iq) - const refs = ((stanza.content[0] as BinaryNode).content as BinaryNode[]).map(n => n.content as string) + const pairDeviceNode = getBinaryNodeChild(stanza, 'pair-device') + const refNodes = getBinaryNodeChildren(pairDeviceNode, 'ref') const noiseKeyB64 = Buffer.from(creds.noiseKey.public).toString('base64') const identityKeyB64 = Buffer.from(creds.signedIdentityKey.public).toString('base64') const advB64 = creds.advSecretKey @@ -453,12 +454,13 @@ export const makeSocket = ({ return } - const ref = refs.shift() - if(!ref) { + const refNode = refNodes.shift() + if(!refNode) { end(new Boom('QR refs attempts ended', { statusCode: DisconnectReason.timedOut })) return } + const ref = (refNode.content as Buffer).toString('utf-8') const qr = [ref, noiseKeyB64, identityKeyB64, advB64].join(',') ev.emit('connection.update', { qr }) diff --git a/src/Utils/noise-handler.ts b/src/Utils/noise-handler.ts index 0251b08..e3ef6f8 100644 --- a/src/Utils/noise-handler.ts +++ b/src/Utils/noise-handler.ts @@ -112,7 +112,7 @@ export const makeNoiseHandler = ({ public: publicKey, private: privateKey }: Key mixIntoKey(Curve.sharedKey(privateKey, decStaticContent)) const certDecoded = decrypt(serverHello!.payload!) - const { details: certDetails, signature: certSignature } = proto.NoiseCertificate.decode(certDecoded) + const { details: certDetails } = proto.NoiseCertificate.decode(certDecoded) const { key: certKey } = proto.NoiseCertificateDetails.decode(certDetails) diff --git a/src/Utils/validate-connection.ts b/src/Utils/validate-connection.ts index fd17be4..67c4c0a 100644 --- a/src/Utils/validate-connection.ts +++ b/src/Utils/validate-connection.ts @@ -10,7 +10,7 @@ import { createSignalIdentity } from './signal' type ClientPayloadConfig = Pick -const getUserAgent = ({ version }: Pick): proto.IUserAgent => ({ +const getUserAgent = ({ version, browser }: ClientPayloadConfig): proto.IUserAgent => ({ appVersion: { primary: version[0], secondary: version[1], @@ -20,10 +20,10 @@ const getUserAgent = ({ version }: Pick): proto.IUserAg releaseChannel: proto.UserAgent.UserAgentReleaseChannel.RELEASE, mcc: '000', mnc: '000', - osVersion: '0.1.0', + osVersion: browser[2], manufacturer: '', device: 'Desktop', - osBuildNumber: '0.1.0', + osBuildNumber: browser[2], localeLanguageIso6391: 'en', localeCountryIso31661Alpha2: 'en', }) @@ -32,9 +32,8 @@ const getWebInfo = (): proto.IWebInfo => ({ webSubPlatform: proto.WebInfo.WebInfoWebSubPlatform.WEB_BROWSER }) -const getClientPayload = (config: ClientPayloadConfig, passive: boolean): proto.IClientPayload => { +const getClientPayload = (config: ClientPayloadConfig): proto.IClientPayload => { return { - passive, connectType: proto.ClientPayload.ClientPayloadConnectType.WIFI_UNKNOWN, connectReason: proto.ClientPayload.ClientPayloadConnectReason.USER_ACTIVATED, userAgent: getUserAgent(config), @@ -45,7 +44,8 @@ const getClientPayload = (config: ClientPayloadConfig, passive: boolean): proto. export const generateLoginNode = (userJid: string, config: ClientPayloadConfig): proto.IClientPayload => { const { user, device } = jidDecode(userJid) const payload: proto.IClientPayload = { - ...getClientPayload(config, true), + ...getClientPayload(config), + passive: true, username: +user, device: device, } @@ -77,7 +77,8 @@ export const generateRegistrationNode = ( const companionProto = proto.CompanionProps.encode(companion).finish() const registerPayload: proto.IClientPayload = { - ...getClientPayload(config, false), + ...getClientPayload(config), + passive: false, regData: { buildHash: appVersionBuf, companionProps: companionProto, @@ -114,40 +115,31 @@ export const configureSuccessfulPairing = ( const jid = deviceNode.attrs.jid const { details, hmac } = proto.ADVSignedDeviceIdentityHMAC.decode(deviceIdentityNode.content as Buffer) - + // check HMAC matches const advSign = hmacSign(details, Buffer.from(advSecretKey, 'base64')) - if(Buffer.compare(hmac, advSign) !== 0) { throw new Boom('Invalid account signature') } const account = proto.ADVSignedDeviceIdentity.decode(details) - const { accountSignatureKey, accountSignature } = account - - const accountMsg = Buffer.concat([ - Buffer.from([6, 0]), - account.details, - signedIdentityKey.public - ]) + const { accountSignatureKey, accountSignature, details: deviceDetails } = account + // verify the device signature matches + const accountMsg = Buffer.concat([ Buffer.from([6, 0]), deviceDetails, signedIdentityKey.public ]) if(!Curve.verify(accountSignatureKey, accountMsg, accountSignature)) { throw new Boom('Failed to verify account signature') } - const deviceMsg = Buffer.concat([ - new Uint8Array([6, 1]), - account.details, - signedIdentityKey.public, - account.accountSignatureKey - ]) + // sign the details with our identity key + const deviceMsg = Buffer.concat([ Buffer.from([6, 1]), deviceDetails, signedIdentityKey.public, accountSignatureKey ]) account.deviceSignature = Curve.sign(signedIdentityKey.private, deviceMsg) + // do not provide the "accountSignatureKey" back + account.accountSignatureKey = null const identity = createSignalIdentity(jid, accountSignatureKey) + const accountEnc = proto.ADVSignedDeviceIdentity.encode(account).finish() const deviceIdentity = proto.ADVDeviceIdentity.decode(account.details) - delete account.accountSignatureKey - const accountEnc = proto.ADVSignedDeviceIdentity.encode(account).finish() - const reply: BinaryNode = { tag: 'iq', attrs: {