mirror of
https://github.com/FranP-code/Baileys.git
synced 2025-10-13 00:32:22 +00:00
WEB WAM IMPLEMENTATION!!!!! (#708)
* feat(WAM): initial commit * fix(wam-development): I made a whoopsie * Update Example/example.ts Co-authored-by: Javier Cuevas <javiercr@gmail.com> --------- Co-authored-by: Javier Cuevas <javiercr@gmail.com>
This commit is contained in:
@@ -547,6 +547,24 @@ export const makeSocket = (config: SocketConfig) => {
|
||||
return Buffer.concat([salt, randomIv, ciphered])
|
||||
}
|
||||
|
||||
const sendWAMBuffer = (wamBuffer: Buffer) => {
|
||||
return query({
|
||||
tag: 'iq',
|
||||
attrs: {
|
||||
to: S_WHATSAPP_NET,
|
||||
id: generateMessageTag(),
|
||||
xmlns: 'w:stats'
|
||||
},
|
||||
content: [
|
||||
{
|
||||
tag: 'add',
|
||||
attrs: {},
|
||||
content: wamBuffer
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
ws.on('message', onMessageRecieved)
|
||||
ws.on('open', async() => {
|
||||
try {
|
||||
@@ -723,6 +741,7 @@ export const makeSocket = (config: SocketConfig) => {
|
||||
requestPairingCode,
|
||||
/** Waits for the connection to WA to reach a state */
|
||||
waitForConnectionUpdate: bindWaitForConnectionUpdate(ev),
|
||||
sendWAMBuffer,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
12
src/WAM/BinaryInfo.ts
Normal file
12
src/WAM/BinaryInfo.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { EventInputType } from './constants'
|
||||
|
||||
export class BinaryInfo {
|
||||
protocolVersion = 5
|
||||
sequence = 0
|
||||
events = [] as EventInputType[]
|
||||
buffer: Buffer[] = []
|
||||
|
||||
constructor(options: Partial<BinaryInfo> = {}) {
|
||||
Object.assign(this, options)
|
||||
}
|
||||
}
|
||||
15382
src/WAM/constants.ts
Normal file
15382
src/WAM/constants.ts
Normal file
File diff suppressed because it is too large
Load Diff
174
src/WAM/encode.ts
Normal file
174
src/WAM/encode.ts
Normal file
@@ -0,0 +1,174 @@
|
||||
import { BinaryInfo } from './BinaryInfo'
|
||||
import { FLAG_BYTE, FLAG_EVENT, FLAG_EXTENDED, FLAG_FIELD, FLAG_GLOBAL, WEB_EVENTS, WEB_GLOBALS } from './constants'
|
||||
|
||||
const getHeaderBitLength = (key: number) => (key < 256 ? 2 : 3)
|
||||
type Value = number | null | string
|
||||
|
||||
|
||||
export const encodeWAM = (binaryInfo: BinaryInfo) => {
|
||||
binaryInfo.buffer = []
|
||||
|
||||
encodeWAMHeader(binaryInfo)
|
||||
encodeEvents(binaryInfo)
|
||||
|
||||
console.log(binaryInfo.buffer)
|
||||
const totalSize = binaryInfo.buffer
|
||||
.map((a) => a.length)
|
||||
.reduce((a, b) => a + b)
|
||||
const buffer = Buffer.alloc(totalSize)
|
||||
let offset = 0
|
||||
binaryInfo.buffer.forEach((buffer_) => {
|
||||
buffer_.copy(buffer, offset)
|
||||
offset += buffer_.length
|
||||
})
|
||||
|
||||
return buffer
|
||||
}
|
||||
|
||||
function encodeWAMHeader(binaryInfo: BinaryInfo) {
|
||||
const headerBuffer = Buffer.alloc(8) // starting buffer
|
||||
headerBuffer.write('WAM', 0, 'utf8')
|
||||
headerBuffer.writeUInt8(binaryInfo.protocolVersion, 3)
|
||||
headerBuffer.writeUInt8(1, 4) //random flag
|
||||
headerBuffer.writeUInt16BE(binaryInfo.sequence, 5)
|
||||
headerBuffer.writeUInt8(0, 7) // regular channel
|
||||
|
||||
binaryInfo.buffer.push(headerBuffer)
|
||||
}
|
||||
|
||||
function encodeGlobalAttributes(binaryInfo: BinaryInfo, globals: {[key: string]: Value}) {
|
||||
for(const [key, _value] of Object.entries(globals)) {
|
||||
const id = WEB_GLOBALS.find(a => a?.name === key)!.id
|
||||
let value = _value
|
||||
if(typeof value === 'boolean') {
|
||||
value = value ? 1 : 0
|
||||
}
|
||||
|
||||
binaryInfo.buffer.push(serializeData(id, value, FLAG_GLOBAL))
|
||||
}
|
||||
}
|
||||
|
||||
function encodeEvents(binaryInfo: BinaryInfo) {
|
||||
for(const [
|
||||
name,
|
||||
{ props, globals },
|
||||
] of binaryInfo.events.map((a) => Object.entries(a)[0])) {
|
||||
encodeGlobalAttributes(binaryInfo, globals)
|
||||
const event = WEB_EVENTS.find((a) => a.name === name)!
|
||||
|
||||
const props_ = Object.entries(props)
|
||||
|
||||
let extended = false
|
||||
|
||||
for(const [, value] of props_) {
|
||||
extended ||= value !== null
|
||||
}
|
||||
|
||||
const eventFlag = extended ? FLAG_EVENT : FLAG_EVENT | FLAG_EXTENDED
|
||||
binaryInfo.buffer.push(serializeData(event.id, -event.weight, eventFlag))
|
||||
|
||||
for(let i = 0; i < props_.length; i++) {
|
||||
const [key, _value] = props_[i]
|
||||
const id = (event.props)[key][0]
|
||||
extended = i < (props_.length - 1)
|
||||
let value = _value
|
||||
if(typeof value === 'boolean') {
|
||||
value = value ? 1 : 0
|
||||
}
|
||||
|
||||
const fieldFlag = extended ? FLAG_EVENT : FLAG_FIELD | FLAG_EXTENDED
|
||||
binaryInfo.buffer.push(serializeData(id, value as Value, fieldFlag))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function serializeData(key: number, value: Value, flag: number): Buffer {
|
||||
const bufferLength = getHeaderBitLength(key)
|
||||
let buffer: Buffer
|
||||
let offset = 0
|
||||
if(value === null) {
|
||||
if(flag === FLAG_GLOBAL) {
|
||||
buffer = Buffer.alloc(bufferLength)
|
||||
offset = serializeHeader(buffer, offset, key, flag)
|
||||
return buffer
|
||||
}
|
||||
} else if(typeof value === 'number' && Number.isInteger(value)) {
|
||||
// is number
|
||||
if(value === 0 || value === 1) {
|
||||
buffer = Buffer.alloc(bufferLength)
|
||||
offset = serializeHeader(buffer, offset, key, flag | ((value + 1) << 4))
|
||||
return buffer
|
||||
} else if(-128 <= value && value < 128) {
|
||||
buffer = Buffer.alloc(bufferLength + 1)
|
||||
offset = serializeHeader(buffer, offset, key, flag | (3 << 4))
|
||||
buffer.writeInt8(value, offset)
|
||||
return buffer
|
||||
} else if(-32768 <= value && value < 32768) {
|
||||
buffer = Buffer.alloc(bufferLength + 2)
|
||||
offset = serializeHeader(buffer, offset, key, flag | (4 << 4))
|
||||
buffer.writeInt16LE(value, offset)
|
||||
return buffer
|
||||
} else if(-2147483648 <= value && value < 2147483648) {
|
||||
buffer = Buffer.alloc(bufferLength + 4)
|
||||
offset = serializeHeader(buffer, offset, key, flag | (5 << 4))
|
||||
buffer.writeInt32LE(value, offset)
|
||||
return buffer
|
||||
} else {
|
||||
buffer = Buffer.alloc(bufferLength + 8)
|
||||
offset = serializeHeader(buffer, offset, key, flag | (7 << 4))
|
||||
buffer.writeDoubleLE(value, offset)
|
||||
return buffer
|
||||
}
|
||||
} else if(typeof value === 'number') {
|
||||
// is float
|
||||
buffer = Buffer.alloc(bufferLength + 8)
|
||||
offset = serializeHeader(buffer, offset, key, flag | (7 << 4))
|
||||
buffer.writeDoubleLE(value, offset)
|
||||
return buffer
|
||||
} else if(typeof value === 'string') {
|
||||
// is string
|
||||
const utf8Bytes = Buffer.byteLength(value, 'utf8')
|
||||
if(utf8Bytes < 256) {
|
||||
buffer = Buffer.alloc(bufferLength + 1 + utf8Bytes)
|
||||
offset = serializeHeader(buffer, offset, key, flag | (8 << 4))
|
||||
buffer.writeUint8(utf8Bytes, offset++)
|
||||
} else if(utf8Bytes < 65536) {
|
||||
buffer = Buffer.alloc(bufferLength + 2 + utf8Bytes)
|
||||
offset = serializeHeader(buffer, offset, key, flag | (9 << 4))
|
||||
buffer.writeUInt16LE(utf8Bytes, offset)
|
||||
offset += 2
|
||||
} else {
|
||||
buffer = Buffer.alloc(bufferLength + 4 + utf8Bytes)
|
||||
offset = serializeHeader(buffer, offset, key, flag | (10 << 4))
|
||||
buffer.writeUInt32LE(utf8Bytes, offset)
|
||||
offset += 4
|
||||
}
|
||||
|
||||
buffer.write(value, offset, 'utf8')
|
||||
return buffer
|
||||
}
|
||||
|
||||
throw 'missing'
|
||||
}
|
||||
|
||||
function serializeHeader(
|
||||
buffer: Buffer,
|
||||
offset: number,
|
||||
key: number,
|
||||
flag: number
|
||||
) {
|
||||
if(key < 256) {
|
||||
buffer.writeUInt8(flag, offset)
|
||||
offset += 1
|
||||
buffer.writeUInt8(key, offset)
|
||||
offset += 1
|
||||
} else {
|
||||
buffer.writeUInt8(flag | FLAG_BYTE, offset)
|
||||
offset += 1
|
||||
buffer.writeUInt16LE(key, offset)
|
||||
offset += 2
|
||||
}
|
||||
|
||||
return offset
|
||||
}
|
||||
3
src/WAM/index.ts
Normal file
3
src/WAM/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from './constants'
|
||||
export * from './encode'
|
||||
export * from './BinaryInfo'
|
||||
@@ -6,6 +6,7 @@ export * from './Types'
|
||||
export * from './Store'
|
||||
export * from './Defaults'
|
||||
export * from './WABinary'
|
||||
export * from './WAM'
|
||||
|
||||
export type WASocket = ReturnType<typeof makeWASocket>
|
||||
export { makeWASocket }
|
||||
|
||||
Reference in New Issue
Block a user