mirror of
https://github.com/FranP-code/Baileys.git
synced 2025-10-13 00:32:22 +00:00
added proxy support
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
||||
MessageLogLevel,
|
||||
WA_MESSAGE_STUB_TYPES,
|
||||
ReconnectMode,
|
||||
ProxyAgent,
|
||||
} from '../src/WAConnection/WAConnection'
|
||||
import * as fs from 'fs'
|
||||
|
||||
@@ -16,6 +17,7 @@ async function example() {
|
||||
conn.autoReconnect = ReconnectMode.onConnectionLost // only automatically reconnect when the connection breaks
|
||||
conn.logLevel = MessageLogLevel.info // set to unhandled to see what kind of stuff you can implement
|
||||
|
||||
|
||||
// loads the auth file credentials if present
|
||||
fs.existsSync('./auth_info.json') && conn.loadAuthInfo ('./auth_info.json')
|
||||
|
||||
@@ -23,6 +25,8 @@ async function example() {
|
||||
conn.connectOptions.timeoutMs = 60*1000
|
||||
// attempt to reconnect at most 10 times
|
||||
conn.connectOptions.maxRetries = 10
|
||||
// uncomment the following line to proxy the connection; some random proxy I got off of: https://proxyscrape.com/free-proxy-list
|
||||
//conn.connectOptions.agent = ProxyAgent ('http://1.0.180.120:8080')
|
||||
await conn.connect()
|
||||
|
||||
const unread = await conn.loadAllUnreadMessages ()
|
||||
|
||||
13
README.md
13
README.md
@@ -51,7 +51,6 @@ async function connectToWhatsApp () {
|
||||
const unread = await conn.loadAllUnreadMessages ()
|
||||
console.log ("you have " + unread.length + " unread messages")
|
||||
}
|
||||
|
||||
// run in main file
|
||||
connectToWhatsApp ()
|
||||
.catch (err => console.log("unexpected error: " + err) ) // catch any errors
|
||||
@@ -69,6 +68,18 @@ Do note, the `chats` object returned is now a [KeyedDB](https://github.com/adiwa
|
||||
- Most applications require pagination of chats (Use `chats.paginated()`)
|
||||
- Most applications require **O(1)** access to chats via the chat ID. (Use `chats.get(jid)` with `KeyedDB`)
|
||||
|
||||
## Connecting via an HTTPS proxy
|
||||
|
||||
``` ts
|
||||
import { WAConnection, ProxyAgent } from '@adiwajshing/baileys'
|
||||
|
||||
const conn = new WAConnecion ()
|
||||
conn.connectOptions.agent = ProxyAgent ('http://some-host:1234')
|
||||
|
||||
await conn.connect ()
|
||||
console.log ("oh hello " + conn.user.name + "! You connected via a proxy")
|
||||
```
|
||||
|
||||
## Saving & Restoring Sessions
|
||||
|
||||
You obviously don't want to keep scanning the QR code every time you want to connect.
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
"@adiwajshing/keyed-db": "^0.1.2",
|
||||
"curve25519-js": "^0.0.4",
|
||||
"futoin-hkdf": "^1.3.2",
|
||||
"https-proxy-agent": "^5.0.0",
|
||||
"jimp": "^0.16.1",
|
||||
"node-fetch": "^2.6.0",
|
||||
"protobufjs": "^6.10.1",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Presence, ChatModification, delay } from '../WAConnection/WAConnection'
|
||||
import { Presence, ChatModification, delay, DEFAULT_ORIGIN } from '../WAConnection/WAConnection'
|
||||
import { promises as fs } from 'fs'
|
||||
import * as assert from 'assert'
|
||||
import fetch from 'node-fetch'
|
||||
@@ -51,7 +51,7 @@ WAConnectionTest('Misc', (conn) => {
|
||||
await delay (5000)
|
||||
|
||||
const ppUrl = await conn.getProfilePicture(conn.user.jid)
|
||||
const fetched = await fetch(ppUrl, { headers: { Origin: 'https://web.whatsapp.com' } })
|
||||
const fetched = await fetch(ppUrl)
|
||||
const buff = await fetched.buffer ()
|
||||
|
||||
const newPP = await fs.readFile ('./Media/cat.jpeg')
|
||||
|
||||
@@ -3,6 +3,7 @@ import WS from 'ws'
|
||||
import * as Utils from './Utils'
|
||||
import Encoder from '../Binary/Encoder'
|
||||
import Decoder from '../Binary/Decoder'
|
||||
import fetch from 'node-fetch'
|
||||
import {
|
||||
AuthenticationCredentials,
|
||||
WAUser,
|
||||
@@ -21,6 +22,7 @@ import {
|
||||
ReconnectMode,
|
||||
WAConnectOptions,
|
||||
MediaConnInfo,
|
||||
DEFAULT_ORIGIN,
|
||||
} from './Constants'
|
||||
import { EventEmitter } from 'events'
|
||||
import KeyedDB from '@adiwajshing/keyed-db'
|
||||
@@ -340,6 +342,17 @@ export class WAConnection extends EventEmitter {
|
||||
}
|
||||
})
|
||||
}
|
||||
/**
|
||||
* Does a fetch request with the configuration of the connection
|
||||
*/
|
||||
protected fetchRequest = (endpoint: string, method: string = 'GET', body?: any) => (
|
||||
fetch(endpoint, {
|
||||
method,
|
||||
body,
|
||||
headers: { Origin: DEFAULT_ORIGIN },
|
||||
agent: this.connectOptions.agent
|
||||
})
|
||||
)
|
||||
generateMessageTag () {
|
||||
return `${Utils.unixTimestampSeconds(this.referenceDate)}.--${this.msgCount}`
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as Utils from './Utils'
|
||||
import { WAMessage, WAChat, MessageLogLevel, WANode, KEEP_ALIVE_INTERVAL_MS, BaileysError, WAConnectOptions, DisconnectReason, UNAUTHORIZED_CODES, WAContact, TimedOutError, CancelledError, WAOpenResult } from './Constants'
|
||||
import { WAMessage, WAChat, MessageLogLevel, WANode, KEEP_ALIVE_INTERVAL_MS, BaileysError, WAConnectOptions, DisconnectReason, UNAUTHORIZED_CODES, WAContact, TimedOutError, CancelledError, WAOpenResult, DEFAULT_ORIGIN, WS_URL } from './Constants'
|
||||
import {WAConnection as Base} from './1.Validation'
|
||||
import Decoder from '../Binary/Decoder'
|
||||
import WS from 'ws'
|
||||
@@ -73,7 +73,7 @@ export class WAConnection extends Base {
|
||||
|
||||
const reconnectID = shouldUseReconnect ? this.user.jid.replace ('@s.whatsapp.net', '@c.us') : null
|
||||
|
||||
this.conn = new WS('wss://web.whatsapp.com/ws', null, { origin: 'https://web.whatsapp.com', timeout: timeoutMs })
|
||||
this.conn = new WS(WS_URL, null, { origin: DEFAULT_ORIGIN, timeout: timeoutMs, agent: options.agent })
|
||||
this.conn.on('message', data => this.onMessageRecieved(data as any))
|
||||
|
||||
this.conn.on ('open', () => {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {WAConnection as Base} from './5.User'
|
||||
import fetch from 'node-fetch'
|
||||
import {promises as fs} from 'fs'
|
||||
import {
|
||||
MessageOptions,
|
||||
@@ -114,18 +113,14 @@ export class WAConnection extends Base {
|
||||
for (let host of json.hosts) {
|
||||
const hostname = `https://${host.hostname}${MediaPathMap[mediaType]}/${fileEncSha256B64}?auth=${auth}&token=${fileEncSha256B64}`
|
||||
try {
|
||||
const urlFetch = await fetch(hostname, {
|
||||
method: 'POST',
|
||||
body: body,
|
||||
headers: { Origin: 'https://web.whatsapp.com' },
|
||||
})
|
||||
const urlFetch = await this.fetchRequest(hostname, 'POST', body)
|
||||
mediaUrl = (await urlFetch.json())?.url
|
||||
|
||||
if (mediaUrl) break
|
||||
else throw new Error (`upload failed`)
|
||||
} catch (error) {
|
||||
const isLast = host.hostname === json.hosts[json.hosts.length-1].hostname
|
||||
this.log (`Error in uploading to ${host}${isLast ? '' : ', retrying...'}`, MessageLogLevel.info)
|
||||
this.log (`Error in uploading to ${host.hostname}${isLast ? '' : ', retrying...'}`, MessageLogLevel.info)
|
||||
}
|
||||
}
|
||||
if (!mediaUrl) throw new Error('Media upload failed on all hosts')
|
||||
@@ -212,15 +207,14 @@ export class WAConnection extends Base {
|
||||
* Renews the download url automatically, if necessary.
|
||||
*/
|
||||
async downloadMediaMessage (message: WAMessage) {
|
||||
const fetchHeaders = { }
|
||||
try {
|
||||
const buff = await decodeMediaMessageBuffer (message.message, fetchHeaders)
|
||||
const buff = await decodeMediaMessageBuffer (message.message, this.fetchRequest)
|
||||
return buff
|
||||
} catch (error) {
|
||||
if (error instanceof BaileysError && error.status === 404) { // media needs to be updated
|
||||
this.log (`updating media of message: ${message.key.id}`, MessageLogLevel.info)
|
||||
await this.updateMediaMessage (message)
|
||||
const buff = await decodeMediaMessageBuffer (message.message, fetchHeaders)
|
||||
const buff = await decodeMediaMessageBuffer (message.message, this.fetchRequest)
|
||||
return buff
|
||||
}
|
||||
throw error
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import { WA } from '../Binary/Constants'
|
||||
import { proto } from '../../WAMessage/WAMessage'
|
||||
import { Agent } from 'https'
|
||||
|
||||
export const WS_URL = 'wss://web.whatsapp.com/ws'
|
||||
export const DEFAULT_ORIGIN = 'https://web.whatsapp.com'
|
||||
|
||||
export const KEEP_ALIVE_INTERVAL_MS = 20*1000
|
||||
|
||||
|
||||
// export the WAMessage Prototypes
|
||||
export { proto as WAMessageProto }
|
||||
export type WANode = WA.Node
|
||||
@@ -15,6 +20,7 @@ export type WAContextInfo = proto.IContextInfo
|
||||
export import WA_MESSAGE_STUB_TYPE = proto.WebMessageInfo.WEB_MESSAGE_INFO_STUBTYPE
|
||||
export import WA_MESSAGE_STATUS_TYPE = proto.WebMessageInfo.WEB_MESSAGE_INFO_STATUS
|
||||
|
||||
|
||||
export interface WALocationMessage {
|
||||
degreesLatitude: number
|
||||
degreesLongitude: number
|
||||
@@ -67,6 +73,8 @@ export type WAConnectOptions = {
|
||||
waitForChats?: boolean
|
||||
|
||||
connectCooldownMs?: number
|
||||
/** agent which can be used for proxying connections */
|
||||
agent?: Agent
|
||||
}
|
||||
|
||||
export type WAConnectionState = 'open' | 'connecting' | 'close'
|
||||
|
||||
@@ -2,12 +2,14 @@ import * as Crypto from 'crypto'
|
||||
import HKDF from 'futoin-hkdf'
|
||||
import Jimp from 'jimp'
|
||||
import {promises as fs} from 'fs'
|
||||
import fetch from 'node-fetch'
|
||||
import { exec } from 'child_process'
|
||||
import {platform, release} from 'os'
|
||||
import HttpsProxyAgent from 'https-proxy-agent'
|
||||
import { URL } from 'url'
|
||||
import { Agent } from 'https'
|
||||
|
||||
import Decoder from '../Binary/Decoder'
|
||||
import { MessageType, HKDFInfoKeys, MessageOptions, WAChat, WAMessageContent, BaileysError, WAMessageProto, TimedOutError, CancelledError } from './Constants'
|
||||
import { MessageType, HKDFInfoKeys, MessageOptions, WAChat, WAMessageContent, BaileysError, WAMessageProto, TimedOutError, CancelledError, DEFAULT_ORIGIN } from './Constants'
|
||||
|
||||
const platformMap = {
|
||||
'aix': 'AIX',
|
||||
@@ -220,6 +222,8 @@ export const generateProfilePicture = async (buffer: Buffer) => {
|
||||
preview: await cropped.resize(96, 96).getBufferAsync (Jimp.MIME_JPEG)
|
||||
}
|
||||
}
|
||||
export const ProxyAgent = (host: string | URL) => HttpsProxyAgent(host) as any as Agent
|
||||
|
||||
/** generates a thumbnail for a given media, if required */
|
||||
export async function generateThumbnail(buffer: Buffer, mediaType: MessageType, info: MessageOptions) {
|
||||
if (info.thumbnail === null || info.thumbnail) {
|
||||
@@ -249,7 +253,7 @@ export async function generateThumbnail(buffer: Buffer, mediaType: MessageType,
|
||||
* Decode a media message (video, image, document, audio) & return decrypted buffer
|
||||
* @param message the media message you want to decode
|
||||
*/
|
||||
export async function decodeMediaMessageBuffer(message: WAMessageContent, fetchHeaders: {[k: string]: string} = {}) {
|
||||
export async function decodeMediaMessageBuffer(message: WAMessageContent, fetchRequest: (host: string, method: string) => any) {
|
||||
/*
|
||||
One can infer media type from the key in the message
|
||||
it is usually written as [mediaType]Message. Eg. imageMessage, audioMessage etc.
|
||||
@@ -274,8 +278,7 @@ export async function decodeMediaMessageBuffer(message: WAMessageContent, fetchH
|
||||
}
|
||||
|
||||
// download the message
|
||||
const headers = { Origin: 'https://web.whatsapp.com' }
|
||||
const fetched = await fetch(messageContent.url, { headers })
|
||||
const fetched = await fetchRequest(messageContent.url, 'GET')
|
||||
const buffer = await fetched.buffer()
|
||||
|
||||
if (buffer.length <= 10) {
|
||||
|
||||
17
yarn.lock
17
yarn.lock
@@ -399,6 +399,13 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
agent-base@6:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.1.tgz#808007e4e5867decb0ab6ab2f928fbdb5a596db4"
|
||||
integrity sha512-01q25QQDwLSsyfhrKbn8yuur+JNw0H+0Y4JiGIKd3z9aYk/w/2kxD/Upc+t2ZBBSUNff50VjPsSW2YxM8QYKVg==
|
||||
dependencies:
|
||||
debug "4"
|
||||
|
||||
ansi-colors@4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
|
||||
@@ -653,7 +660,7 @@ dateformat@~1.0.4-1.2.3:
|
||||
get-stdin "^4.0.1"
|
||||
meow "^3.3.0"
|
||||
|
||||
debug@4.1.1:
|
||||
debug@4, debug@4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
|
||||
integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
|
||||
@@ -946,6 +953,14 @@ hosted-git-info@^2.1.4:
|
||||
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488"
|
||||
integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==
|
||||
|
||||
https-proxy-agent@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2"
|
||||
integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==
|
||||
dependencies:
|
||||
agent-base "6"
|
||||
debug "4"
|
||||
|
||||
ieee754@^1.1.4:
|
||||
version "1.1.13"
|
||||
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84"
|
||||
|
||||
Reference in New Issue
Block a user