diff --git a/Example/example.ts b/Example/example.ts index 5b59de8..8ff6f04 100644 --- a/Example/example.ts +++ b/Example/example.ts @@ -3,6 +3,8 @@ import NodeCache from 'node-cache' import readline from 'readline' import makeWASocket, { AnyMessageContent, delay, DisconnectReason, fetchLatestBaileysVersion, getAggregateVotesInPollMessage, makeCacheableSignalKeyStore, makeInMemoryStore, PHONENUMBER_MCC, proto, useMultiFileAuthState, WAMessageContent, WAMessageKey } from '../src' import MAIN_LOGGER from '../src/Utils/logger' +import open from 'open' +import fs from 'fs' const logger = MAIN_LOGGER.child({}) logger.level = 'trace' @@ -105,21 +107,38 @@ const startSock = async() => { } } + async function enterCaptcha() { + const response = await sock.requestRegistrationCode({ ...registration, method: 'captcha' }) + const path = __dirname + '/captcha.png' + fs.writeFileSync(path, Buffer.from(response.image_blob!, 'base64')) + + open(path) + const code = await question('Please enter the captcha code:\n') + fs.unlinkSync(path) + registration.captcha = code.replace(/["']/g, '').trim().toLowerCase() + } + async function askForOTP() { - let code = await question('How would you like to receive the one time code for registration? "sms" or "voice"\n') - code = code.replace(/["']/g, '').trim().toLowerCase() + if (!registration.method) { + let code = await question('How would you like to receive the one time code for registration? "sms" or "voice"\n') + code = code.replace(/["']/g, '').trim().toLowerCase() + if(code !== 'sms' && code !== 'voice') { + return await askForOTP() + } - if(code !== 'sms' && code !== 'voice') { - return await askForOTP() + registration.method = code } - registration.method = code - try { await sock.requestRegistrationCode(registration) await enterCode() } catch(error) { console.error('Failed to request registration code. Please try again.\n', error) + + if(error?.reason === 'code_checkpoint') { + await enterCaptcha() + } + await askForOTP() } } diff --git a/package.json b/package.json index bd91bf5..eeadcfd 100644 --- a/package.json +++ b/package.json @@ -69,6 +69,7 @@ "jest": "^27.0.6", "jimp": "^0.16.1", "link-preview-js": "^3.0.0", + "open": "^8.4.2", "qrcode-terminal": "^0.12.0", "release-it": "^15.10.3", "sharp": "^0.30.5", diff --git a/src/Defaults/index.ts b/src/Defaults/index.ts index c331089..2eec34a 100644 --- a/src/Defaults/index.ts +++ b/src/Defaults/index.ts @@ -19,6 +19,7 @@ export const PHONE_CONNECTION_CB = 'CB:Pong' export const WA_DEFAULT_EPHEMERAL = 7 * 24 * 60 * 60 + export const MOBILE_TOKEN = Buffer.from('0a1mLfGUIBVrMKF1RdvLI5lkRBvof6vn0fD2QRSM3d3683e76445591c0591bc3c034c3bca') export const MOBILE_REGISTRATION_ENDPOINT = 'https://v.whatsapp.net/v2' export const MOBILE_USERAGENT = 'WhatsApp/2.23.13.82 iOS/15.3.1 Device/Apple-iPhone_7' diff --git a/src/Signal/libsignal.ts b/src/Signal/libsignal.ts index 1375050..367cdb8 100644 --- a/src/Signal/libsignal.ts +++ b/src/Signal/libsignal.ts @@ -3,6 +3,7 @@ import { GroupCipher, GroupSessionBuilder, SenderKeyDistributionMessage, SenderK import { SignalAuthState } from '../Types' import { SignalRepository } from '../Types/Signal' import { generateSignalPubKey } from '../Utils' +import { jidDecode } from '../WABinary' export function makeLibSignalRepository(auth: SignalAuthState): SignalRepository { const storage = signalStorage(auth) @@ -76,10 +77,9 @@ export function makeLibSignalRepository(auth: SignalAuthState): SignalRepository } } -const jidToSignalAddress = (jid: string) => jid.split('@')[0] - const jidToSignalProtocolAddress = (jid: string) => { - return new libsignal.ProtocolAddress(jidToSignalAddress(jid), 0) + const { user, device } = jidDecode(jid)! + return new libsignal.ProtocolAddress(user, device || 0) } const jidToSignalSenderKeyName = (group: string, user: string): string => { diff --git a/src/Socket/registration.ts b/src/Socket/registration.ts index 3909152..6562855 100644 --- a/src/Socket/registration.ts +++ b/src/Socket/registration.ts @@ -86,7 +86,11 @@ export interface RegistrationOptions { /** * How to send the one time code */ - method?: 'sms' | 'voice' + method?: 'sms' | 'voice' | 'captcha' + /** + * The captcha code if it was requested + */ + captcha?: string } export type RegistrationParams = RegistrationData & RegistrationOptions @@ -136,6 +140,7 @@ export function registrationParams(params: RegistrationParams) { id: convertBufferToUrlHex(params.identityId), backup_token: convertBufferToUrlHex(params.backupToken), token: md5(Buffer.concat([MOBILE_TOKEN, Buffer.from(params.phoneNumberNationalNumber)])).toString('hex'), + fraud_checkpoint_code: params.captcha, } } @@ -196,13 +201,11 @@ export async function mobileRegisterFetch(path: string, opts: AxiosRequestConfig const parameter = [] as string[] for(const param in opts.params) { - parameter.push(param + '=' + urlencode(opts.params[param])) + if(opts.params[param] !== null && opts.params[param] !== undefined) { + parameter.push(param + '=' + urlencode(opts.params[param])) + } } - console.log('parameter', opts.params, parameter) - - // const params = urlencode(mobileRegisterEncrypt(parameter.join('&'))) - // url += `?ENC=${params}` url += `?${parameter.join('&')}` delete opts.params } @@ -230,16 +233,18 @@ export async function mobileRegisterFetch(path: string, opts: AxiosRequestConfig export interface ExistsResponse { - status: 'fail' + status: 'fail' | 'sent' voice_length?: number voice_wait?: number sms_length?: number sms_wait?: number - reason?: 'incorrect' | 'missing_param' + reason?: 'incorrect' | 'missing_param' | 'code_checkpoint' login?: string flash_type?: number ab_hash?: string ab_key?: string exp_cfg?: string lid?: string + image_blob?: string + audio_blob?: string }