mirror of
https://github.com/FranP-code/Baileys.git
synced 2025-10-13 00:32:22 +00:00
chore: add linting
This commit is contained in:
@@ -3,214 +3,239 @@ import { BinaryNode } from '../types'
|
||||
import { DoubleByteTokens, SingleByteTokens, Tags } from './constants'
|
||||
|
||||
export const isLegacyBinaryNode = (buffer: Buffer) => {
|
||||
switch(buffer[0]) {
|
||||
case Tags.LIST_EMPTY:
|
||||
case Tags.LIST_8:
|
||||
case Tags.LIST_16:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
switch (buffer[0]) {
|
||||
case Tags.LIST_EMPTY:
|
||||
case Tags.LIST_8:
|
||||
case Tags.LIST_16:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function decode(buffer: Buffer, indexRef: { index: number }): BinaryNode {
|
||||
|
||||
const checkEOS = (length: number) => {
|
||||
if (indexRef.index + length > buffer.length) {
|
||||
throw new Error('end of stream')
|
||||
}
|
||||
}
|
||||
const next = () => {
|
||||
const value = buffer[indexRef.index]
|
||||
indexRef.index += 1
|
||||
return value
|
||||
}
|
||||
const readByte = () => {
|
||||
checkEOS(1)
|
||||
return next()
|
||||
}
|
||||
const readStringFromChars = (length: number) => {
|
||||
checkEOS(length)
|
||||
const value = buffer.slice(indexRef.index, indexRef.index + length)
|
||||
const checkEOS = (length: number) => {
|
||||
if(indexRef.index + length > buffer.length) {
|
||||
throw new Error('end of stream')
|
||||
}
|
||||
}
|
||||
|
||||
indexRef.index += length
|
||||
return value.toString('utf-8')
|
||||
}
|
||||
const readBytes = (n: number) => {
|
||||
checkEOS(n)
|
||||
const value = buffer.slice(indexRef.index, indexRef.index + n)
|
||||
indexRef.index += n
|
||||
return value
|
||||
}
|
||||
const readInt = (n: number, littleEndian = false) => {
|
||||
checkEOS(n)
|
||||
let val = 0
|
||||
for (let i = 0; i < n; i++) {
|
||||
const shift = littleEndian ? i : n - 1 - i
|
||||
val |= next() << (shift * 8)
|
||||
}
|
||||
return val
|
||||
}
|
||||
const readInt20 = () => {
|
||||
checkEOS(3)
|
||||
return ((next() & 15) << 16) + (next() << 8) + next()
|
||||
}
|
||||
const unpackHex = (value: number) => {
|
||||
if (value >= 0 && value < 16) {
|
||||
return value < 10 ? '0'.charCodeAt(0) + value : 'A'.charCodeAt(0) + value - 10
|
||||
}
|
||||
throw new Error('invalid hex: ' + value)
|
||||
}
|
||||
const unpackNibble = (value: number) => {
|
||||
if (value >= 0 && value <= 9) {
|
||||
return '0'.charCodeAt(0) + value
|
||||
}
|
||||
switch (value) {
|
||||
case 10:
|
||||
return '-'.charCodeAt(0)
|
||||
case 11:
|
||||
return '.'.charCodeAt(0)
|
||||
case 15:
|
||||
return '\0'.charCodeAt(0)
|
||||
default:
|
||||
throw new Error('invalid nibble: ' + value)
|
||||
}
|
||||
}
|
||||
const unpackByte = (tag: number, value: number) => {
|
||||
if (tag === Tags.NIBBLE_8) {
|
||||
return unpackNibble(value)
|
||||
} else if (tag === Tags.HEX_8) {
|
||||
return unpackHex(value)
|
||||
} else {
|
||||
throw new Error('unknown tag: ' + tag)
|
||||
}
|
||||
}
|
||||
const readPacked8 = (tag: number) => {
|
||||
const startByte = readByte()
|
||||
let value = ''
|
||||
const next = () => {
|
||||
const value = buffer[indexRef.index]
|
||||
indexRef.index += 1
|
||||
return value
|
||||
}
|
||||
|
||||
for (let i = 0; i < (startByte & 127); i++) {
|
||||
const curByte = readByte()
|
||||
value += String.fromCharCode(unpackByte(tag, (curByte & 0xf0) >> 4))
|
||||
value += String.fromCharCode(unpackByte(tag, curByte & 0x0f))
|
||||
}
|
||||
if (startByte >> 7 !== 0) {
|
||||
value = value.slice(0, -1)
|
||||
}
|
||||
return value
|
||||
}
|
||||
const isListTag = (tag: number) => {
|
||||
return tag === Tags.LIST_EMPTY || tag === Tags.LIST_8 || tag === Tags.LIST_16
|
||||
}
|
||||
const readListSize = (tag: number) => {
|
||||
switch (tag) {
|
||||
case Tags.LIST_EMPTY:
|
||||
return 0
|
||||
case Tags.LIST_8:
|
||||
return readByte()
|
||||
case Tags.LIST_16:
|
||||
return readInt(2)
|
||||
default:
|
||||
throw new Error('invalid tag for list size: ' + tag)
|
||||
}
|
||||
}
|
||||
const getToken = (index: number) => {
|
||||
if (index < 3 || index >= SingleByteTokens.length) {
|
||||
throw new Error('invalid token index: ' + index)
|
||||
}
|
||||
return SingleByteTokens[index]
|
||||
}
|
||||
const readString = (tag: number) => {
|
||||
if (tag >= 3 && tag <= 235) {
|
||||
const token = getToken(tag)
|
||||
return token// === 's.whatsapp.net' ? 'c.us' : token
|
||||
}
|
||||
const readByte = () => {
|
||||
checkEOS(1)
|
||||
return next()
|
||||
}
|
||||
|
||||
switch (tag) {
|
||||
case Tags.DICTIONARY_0:
|
||||
case Tags.DICTIONARY_1:
|
||||
case Tags.DICTIONARY_2:
|
||||
case Tags.DICTIONARY_3:
|
||||
return getTokenDouble(tag - Tags.DICTIONARY_0, readByte())
|
||||
case Tags.LIST_EMPTY:
|
||||
return null
|
||||
case Tags.BINARY_8:
|
||||
return readStringFromChars(readByte())
|
||||
case Tags.BINARY_20:
|
||||
return readStringFromChars(readInt20())
|
||||
case Tags.BINARY_32:
|
||||
return readStringFromChars(readInt(4))
|
||||
case Tags.JID_PAIR:
|
||||
const i = readString(readByte())
|
||||
const j = readString(readByte())
|
||||
if (typeof i === 'string' && j) {
|
||||
return i + '@' + j
|
||||
}
|
||||
throw new Error('invalid jid pair: ' + i + ', ' + j)
|
||||
case Tags.HEX_8:
|
||||
case Tags.NIBBLE_8:
|
||||
return readPacked8(tag)
|
||||
default:
|
||||
throw new Error('invalid string with tag: ' + tag)
|
||||
}
|
||||
}
|
||||
const readList = (tag: number) => (
|
||||
[...new Array(readListSize(tag))].map(() => decode(buffer, indexRef))
|
||||
)
|
||||
const getTokenDouble = (index1: number, index2: number) => {
|
||||
const n = 256 * index1 + index2
|
||||
if (n < 0 || n > DoubleByteTokens.length) {
|
||||
throw new Error('invalid double token index: ' + n)
|
||||
}
|
||||
return DoubleByteTokens[n]
|
||||
}
|
||||
const readStringFromChars = (length: number) => {
|
||||
checkEOS(length)
|
||||
const value = buffer.slice(indexRef.index, indexRef.index + length)
|
||||
|
||||
const listSize = readListSize(readByte())
|
||||
const descrTag = readByte()
|
||||
if (descrTag === Tags.STREAM_END) {
|
||||
throw new Error('unexpected stream end')
|
||||
}
|
||||
const header = readString(descrTag)
|
||||
indexRef.index += length
|
||||
return value.toString('utf-8')
|
||||
}
|
||||
|
||||
const readBytes = (n: number) => {
|
||||
checkEOS(n)
|
||||
const value = buffer.slice(indexRef.index, indexRef.index + n)
|
||||
indexRef.index += n
|
||||
return value
|
||||
}
|
||||
|
||||
const readInt = (n: number, littleEndian = false) => {
|
||||
checkEOS(n)
|
||||
let val = 0
|
||||
for(let i = 0; i < n; i++) {
|
||||
const shift = littleEndian ? i : n - 1 - i
|
||||
val |= next() << (shift * 8)
|
||||
}
|
||||
|
||||
return val
|
||||
}
|
||||
|
||||
const readInt20 = () => {
|
||||
checkEOS(3)
|
||||
return ((next() & 15) << 16) + (next() << 8) + next()
|
||||
}
|
||||
|
||||
const unpackHex = (value: number) => {
|
||||
if(value >= 0 && value < 16) {
|
||||
return value < 10 ? '0'.charCodeAt(0) + value : 'A'.charCodeAt(0) + value - 10
|
||||
}
|
||||
|
||||
throw new Error('invalid hex: ' + value)
|
||||
}
|
||||
|
||||
const unpackNibble = (value: number) => {
|
||||
if(value >= 0 && value <= 9) {
|
||||
return '0'.charCodeAt(0) + value
|
||||
}
|
||||
|
||||
switch (value) {
|
||||
case 10:
|
||||
return '-'.charCodeAt(0)
|
||||
case 11:
|
||||
return '.'.charCodeAt(0)
|
||||
case 15:
|
||||
return '\0'.charCodeAt(0)
|
||||
default:
|
||||
throw new Error('invalid nibble: ' + value)
|
||||
}
|
||||
}
|
||||
|
||||
const unpackByte = (tag: number, value: number) => {
|
||||
if(tag === Tags.NIBBLE_8) {
|
||||
return unpackNibble(value)
|
||||
} else if(tag === Tags.HEX_8) {
|
||||
return unpackHex(value)
|
||||
} else {
|
||||
throw new Error('unknown tag: ' + tag)
|
||||
}
|
||||
}
|
||||
|
||||
const readPacked8 = (tag: number) => {
|
||||
const startByte = readByte()
|
||||
let value = ''
|
||||
|
||||
for(let i = 0; i < (startByte & 127); i++) {
|
||||
const curByte = readByte()
|
||||
value += String.fromCharCode(unpackByte(tag, (curByte & 0xf0) >> 4))
|
||||
value += String.fromCharCode(unpackByte(tag, curByte & 0x0f))
|
||||
}
|
||||
|
||||
if(startByte >> 7 !== 0) {
|
||||
value = value.slice(0, -1)
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
const isListTag = (tag: number) => {
|
||||
return tag === Tags.LIST_EMPTY || tag === Tags.LIST_8 || tag === Tags.LIST_16
|
||||
}
|
||||
|
||||
const readListSize = (tag: number) => {
|
||||
switch (tag) {
|
||||
case Tags.LIST_EMPTY:
|
||||
return 0
|
||||
case Tags.LIST_8:
|
||||
return readByte()
|
||||
case Tags.LIST_16:
|
||||
return readInt(2)
|
||||
default:
|
||||
throw new Error('invalid tag for list size: ' + tag)
|
||||
}
|
||||
}
|
||||
|
||||
const getToken = (index: number) => {
|
||||
if(index < 3 || index >= SingleByteTokens.length) {
|
||||
throw new Error('invalid token index: ' + index)
|
||||
}
|
||||
|
||||
return SingleByteTokens[index]
|
||||
}
|
||||
|
||||
const readString = (tag: number) => {
|
||||
if(tag >= 3 && tag <= 235) {
|
||||
const token = getToken(tag)
|
||||
return token// === 's.whatsapp.net' ? 'c.us' : token
|
||||
}
|
||||
|
||||
switch (tag) {
|
||||
case Tags.DICTIONARY_0:
|
||||
case Tags.DICTIONARY_1:
|
||||
case Tags.DICTIONARY_2:
|
||||
case Tags.DICTIONARY_3:
|
||||
return getTokenDouble(tag - Tags.DICTIONARY_0, readByte())
|
||||
case Tags.LIST_EMPTY:
|
||||
return null
|
||||
case Tags.BINARY_8:
|
||||
return readStringFromChars(readByte())
|
||||
case Tags.BINARY_20:
|
||||
return readStringFromChars(readInt20())
|
||||
case Tags.BINARY_32:
|
||||
return readStringFromChars(readInt(4))
|
||||
case Tags.JID_PAIR:
|
||||
const i = readString(readByte())
|
||||
const j = readString(readByte())
|
||||
if(typeof i === 'string' && j) {
|
||||
return i + '@' + j
|
||||
}
|
||||
|
||||
throw new Error('invalid jid pair: ' + i + ', ' + j)
|
||||
case Tags.HEX_8:
|
||||
case Tags.NIBBLE_8:
|
||||
return readPacked8(tag)
|
||||
default:
|
||||
throw new Error('invalid string with tag: ' + tag)
|
||||
}
|
||||
}
|
||||
|
||||
const readList = (tag: number) => (
|
||||
[...new Array(readListSize(tag))].map(() => decode(buffer, indexRef))
|
||||
)
|
||||
const getTokenDouble = (index1: number, index2: number) => {
|
||||
const n = 256 * index1 + index2
|
||||
if(n < 0 || n > DoubleByteTokens.length) {
|
||||
throw new Error('invalid double token index: ' + n)
|
||||
}
|
||||
|
||||
return DoubleByteTokens[n]
|
||||
}
|
||||
|
||||
const listSize = readListSize(readByte())
|
||||
const descrTag = readByte()
|
||||
if(descrTag === Tags.STREAM_END) {
|
||||
throw new Error('unexpected stream end')
|
||||
}
|
||||
|
||||
const header = readString(descrTag)
|
||||
const attrs: BinaryNode['attrs'] = { }
|
||||
let data: BinaryNode['content']
|
||||
if (listSize === 0 || !header) {
|
||||
throw new Error('invalid node')
|
||||
}
|
||||
// read the attributes in
|
||||
if(listSize === 0 || !header) {
|
||||
throw new Error('invalid node')
|
||||
}
|
||||
// read the attributes in
|
||||
|
||||
const attributesLength = (listSize - 1) >> 1
|
||||
for (let i = 0; i < attributesLength; i++) {
|
||||
const key = readString(readByte())
|
||||
const b = readByte()
|
||||
const attributesLength = (listSize - 1) >> 1
|
||||
for(let i = 0; i < attributesLength; i++) {
|
||||
const key = readString(readByte())
|
||||
const b = readByte()
|
||||
|
||||
attrs[key] = readString(b)
|
||||
}
|
||||
attrs[key] = readString(b)
|
||||
}
|
||||
|
||||
if(listSize % 2 === 0) {
|
||||
const tag = readByte()
|
||||
if(isListTag(tag)) {
|
||||
data = readList(tag)
|
||||
} else {
|
||||
let decoded: Buffer | string
|
||||
switch (tag) {
|
||||
case Tags.BINARY_8:
|
||||
decoded = readBytes(readByte())
|
||||
break
|
||||
case Tags.BINARY_20:
|
||||
decoded = readBytes(readInt20())
|
||||
break
|
||||
case Tags.BINARY_32:
|
||||
decoded = readBytes(readInt(4))
|
||||
break
|
||||
default:
|
||||
decoded = readString(tag)
|
||||
break
|
||||
}
|
||||
|
||||
if (listSize % 2 === 0) {
|
||||
const tag = readByte()
|
||||
if (isListTag(tag)) {
|
||||
data = readList(tag)
|
||||
} else {
|
||||
let decoded: Buffer | string
|
||||
switch (tag) {
|
||||
case Tags.BINARY_8:
|
||||
decoded = readBytes(readByte())
|
||||
break
|
||||
case Tags.BINARY_20:
|
||||
decoded = readBytes(readInt20())
|
||||
break
|
||||
case Tags.BINARY_32:
|
||||
decoded = readBytes(readInt(4))
|
||||
break
|
||||
default:
|
||||
decoded = readString(tag)
|
||||
break
|
||||
}
|
||||
data = decoded
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
return {
|
||||
tag: header,
|
||||
attrs,
|
||||
content: data
|
||||
@@ -221,85 +246,97 @@ const encode = ({ tag, attrs, content }: BinaryNode, buffer: number[] = []) => {
|
||||
|
||||
const pushByte = (value: number) => buffer.push(value & 0xff)
|
||||
|
||||
const pushInt = (value: number, n: number, littleEndian=false) => {
|
||||
for (let i = 0; i < n; i++) {
|
||||
const curShift = littleEndian ? i : n - 1 - i
|
||||
buffer.push((value >> (curShift * 8)) & 0xff)
|
||||
}
|
||||
}
|
||||
const pushBytes = (bytes: Uint8Array | Buffer | number[]) => (
|
||||
const pushInt = (value: number, n: number, littleEndian=false) => {
|
||||
for(let i = 0; i < n; i++) {
|
||||
const curShift = littleEndian ? i : n - 1 - i
|
||||
buffer.push((value >> (curShift * 8)) & 0xff)
|
||||
}
|
||||
}
|
||||
|
||||
const pushBytes = (bytes: Uint8Array | Buffer | number[]) => (
|
||||
bytes.forEach (b => buffer.push(b))
|
||||
)
|
||||
const pushInt20 = (value: number) => (
|
||||
const pushInt20 = (value: number) => (
|
||||
pushBytes([(value >> 16) & 0x0f, (value >> 8) & 0xff, value & 0xff])
|
||||
)
|
||||
const writeByteLength = (length: number) => {
|
||||
if (length >= 4294967296) throw new Error('string too large to encode: ' + length)
|
||||
const writeByteLength = (length: number) => {
|
||||
if(length >= 4294967296) {
|
||||
throw new Error('string too large to encode: ' + length)
|
||||
}
|
||||
|
||||
if (length >= 1 << 20) {
|
||||
pushByte(Tags.BINARY_32)
|
||||
pushInt(length, 4) // 32 bit integer
|
||||
} else if (length >= 256) {
|
||||
pushByte(Tags.BINARY_20)
|
||||
pushInt20(length)
|
||||
} else {
|
||||
pushByte(Tags.BINARY_8)
|
||||
pushByte(length)
|
||||
}
|
||||
}
|
||||
const writeStringRaw = (str: string) => {
|
||||
const bytes = Buffer.from (str, 'utf-8')
|
||||
writeByteLength(bytes.length)
|
||||
pushBytes(bytes)
|
||||
}
|
||||
const writeToken = (token: number) => {
|
||||
if (token < 245) {
|
||||
pushByte(token)
|
||||
} else if (token <= 500) {
|
||||
throw new Error('invalid token')
|
||||
}
|
||||
}
|
||||
const writeString = (token: string, i?: boolean) => {
|
||||
if (token === 'c.us') token = 's.whatsapp.net'
|
||||
if(length >= 1 << 20) {
|
||||
pushByte(Tags.BINARY_32)
|
||||
pushInt(length, 4) // 32 bit integer
|
||||
} else if(length >= 256) {
|
||||
pushByte(Tags.BINARY_20)
|
||||
pushInt20(length)
|
||||
} else {
|
||||
pushByte(Tags.BINARY_8)
|
||||
pushByte(length)
|
||||
}
|
||||
}
|
||||
|
||||
const writeStringRaw = (str: string) => {
|
||||
const bytes = Buffer.from (str, 'utf-8')
|
||||
writeByteLength(bytes.length)
|
||||
pushBytes(bytes)
|
||||
}
|
||||
|
||||
const writeToken = (token: number) => {
|
||||
if(token < 245) {
|
||||
pushByte(token)
|
||||
} else if(token <= 500) {
|
||||
throw new Error('invalid token')
|
||||
}
|
||||
}
|
||||
|
||||
const writeString = (token: string, i?: boolean) => {
|
||||
if(token === 'c.us') {
|
||||
token = 's.whatsapp.net'
|
||||
}
|
||||
|
||||
const tokenIndex = SingleByteTokens.indexOf(token)
|
||||
if (!i && token === 's.whatsapp.net') {
|
||||
writeToken(tokenIndex)
|
||||
} else if (tokenIndex >= 0) {
|
||||
if (tokenIndex < Tags.SINGLE_BYTE_MAX) {
|
||||
writeToken(tokenIndex)
|
||||
} else {
|
||||
const overflow = tokenIndex - Tags.SINGLE_BYTE_MAX
|
||||
const dictionaryIndex = overflow >> 8
|
||||
if (dictionaryIndex < 0 || dictionaryIndex > 3) {
|
||||
throw new Error('double byte dict token out of range: ' + token + ', ' + tokenIndex)
|
||||
}
|
||||
writeToken(Tags.DICTIONARY_0 + dictionaryIndex)
|
||||
writeToken(overflow % 256)
|
||||
}
|
||||
} else if (token) {
|
||||
const jidSepIndex = token.indexOf('@')
|
||||
if (jidSepIndex <= 0) {
|
||||
writeStringRaw(token)
|
||||
} else {
|
||||
writeJid(token.slice(0, jidSepIndex), token.slice(jidSepIndex + 1, token.length))
|
||||
}
|
||||
}
|
||||
}
|
||||
const writeJid = (left: string, right: string) => {
|
||||
pushByte(Tags.JID_PAIR)
|
||||
left && left.length > 0 ? writeString(left) : writeToken(Tags.LIST_EMPTY)
|
||||
writeString(right)
|
||||
}
|
||||
const writeListStart = (listSize: number) => {
|
||||
if (listSize === 0) {
|
||||
pushByte(Tags.LIST_EMPTY)
|
||||
} else if (listSize < 256) {
|
||||
pushBytes([Tags.LIST_8, listSize])
|
||||
} else {
|
||||
pushBytes([Tags.LIST_16, listSize])
|
||||
}
|
||||
}
|
||||
const tokenIndex = SingleByteTokens.indexOf(token)
|
||||
if(!i && token === 's.whatsapp.net') {
|
||||
writeToken(tokenIndex)
|
||||
} else if(tokenIndex >= 0) {
|
||||
if(tokenIndex < Tags.SINGLE_BYTE_MAX) {
|
||||
writeToken(tokenIndex)
|
||||
} else {
|
||||
const overflow = tokenIndex - Tags.SINGLE_BYTE_MAX
|
||||
const dictionaryIndex = overflow >> 8
|
||||
if(dictionaryIndex < 0 || dictionaryIndex > 3) {
|
||||
throw new Error('double byte dict token out of range: ' + token + ', ' + tokenIndex)
|
||||
}
|
||||
|
||||
writeToken(Tags.DICTIONARY_0 + dictionaryIndex)
|
||||
writeToken(overflow % 256)
|
||||
}
|
||||
} else if(token) {
|
||||
const jidSepIndex = token.indexOf('@')
|
||||
if(jidSepIndex <= 0) {
|
||||
writeStringRaw(token)
|
||||
} else {
|
||||
writeJid(token.slice(0, jidSepIndex), token.slice(jidSepIndex + 1, token.length))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const writeJid = (left: string, right: string) => {
|
||||
pushByte(Tags.JID_PAIR)
|
||||
left && left.length > 0 ? writeString(left) : writeToken(Tags.LIST_EMPTY)
|
||||
writeString(right)
|
||||
}
|
||||
|
||||
const writeListStart = (listSize: number) => {
|
||||
if(listSize === 0) {
|
||||
pushByte(Tags.LIST_EMPTY)
|
||||
} else if(listSize < 256) {
|
||||
pushBytes([Tags.LIST_8, listSize])
|
||||
} else {
|
||||
pushBytes([Tags.LIST_16, listSize])
|
||||
}
|
||||
}
|
||||
|
||||
const validAttributes = Object.keys(attrs).filter(k => (
|
||||
typeof attrs[k] !== 'undefined' && attrs[k] !== null
|
||||
))
|
||||
@@ -308,25 +345,27 @@ const encode = ({ tag, attrs, content }: BinaryNode, buffer: number[] = []) => {
|
||||
writeString(tag)
|
||||
|
||||
validAttributes.forEach((key) => {
|
||||
if(typeof attrs[key] === 'string') {
|
||||
writeString(key)
|
||||
writeString(attrs[key])
|
||||
}
|
||||
if(typeof attrs[key] === 'string') {
|
||||
writeString(key)
|
||||
writeString(attrs[key])
|
||||
}
|
||||
})
|
||||
|
||||
if (typeof content === 'string') {
|
||||
if(typeof content === 'string') {
|
||||
writeString(content, true)
|
||||
} else if (Buffer.isBuffer(content)) {
|
||||
} else if(Buffer.isBuffer(content)) {
|
||||
writeByteLength(content.length)
|
||||
pushBytes(content)
|
||||
} else if (Array.isArray(content)) {
|
||||
} else if(Array.isArray(content)) {
|
||||
writeListStart(content.length)
|
||||
for(const item of content) {
|
||||
if(item) encode(item, buffer)
|
||||
if(item) {
|
||||
encode(item, buffer)
|
||||
}
|
||||
}
|
||||
} else if(typeof content === 'undefined' || content === null) {
|
||||
|
||||
} else {
|
||||
} else {
|
||||
throw new Error(`invalid children for header "${tag}": ${content} (${typeof content})`)
|
||||
}
|
||||
|
||||
|
||||
81
src/WABinary/generic-utils.ts
Normal file
81
src/WABinary/generic-utils.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import { Boom } from '@hapi/boom'
|
||||
import { proto } from '../../WAProto'
|
||||
import { BinaryNode } from './types'
|
||||
|
||||
// some extra useful utilities
|
||||
|
||||
export const getBinaryNodeChildren = ({ content }: BinaryNode, childTag: string) => {
|
||||
if(Array.isArray(content)) {
|
||||
return content.filter(item => item.tag === childTag)
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
|
||||
export const getAllBinaryNodeChildren = ({ content }: BinaryNode) => {
|
||||
if(Array.isArray(content)) {
|
||||
return content
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
|
||||
export const getBinaryNodeChild = ({ content }: BinaryNode, childTag: string) => {
|
||||
if(Array.isArray(content)) {
|
||||
return content.find(item => item.tag === childTag)
|
||||
}
|
||||
}
|
||||
|
||||
export const getBinaryNodeChildBuffer = (node: BinaryNode, childTag: string) => {
|
||||
const child = getBinaryNodeChild(node, childTag)?.content
|
||||
if(Buffer.isBuffer(child) || child instanceof Uint8Array) {
|
||||
return child
|
||||
}
|
||||
}
|
||||
|
||||
export const getBinaryNodeChildUInt = (node: BinaryNode, childTag: string, length: number) => {
|
||||
const buff = getBinaryNodeChildBuffer(node, childTag)
|
||||
if(buff) {
|
||||
return bufferToUInt(buff, length)
|
||||
}
|
||||
}
|
||||
|
||||
export const assertNodeErrorFree = (node: BinaryNode) => {
|
||||
const errNode = getBinaryNodeChild(node, 'error')
|
||||
if(errNode) {
|
||||
throw new Boom(errNode.attrs.text || 'Unknown error', { data: +errNode.attrs.code })
|
||||
}
|
||||
}
|
||||
|
||||
export const reduceBinaryNodeToDictionary = (node: BinaryNode, tag: string) => {
|
||||
const nodes = getBinaryNodeChildren(node, tag)
|
||||
const dict = nodes.reduce(
|
||||
(dict, { attrs }) => {
|
||||
dict[attrs.name || attrs.config_code] = attrs.value || attrs.config_value
|
||||
return dict
|
||||
}, { } as { [_: string]: string }
|
||||
)
|
||||
return dict
|
||||
}
|
||||
|
||||
export const getBinaryNodeMessages = ({ content }: BinaryNode) => {
|
||||
const msgs: proto.WebMessageInfo[] = []
|
||||
if(Array.isArray(content)) {
|
||||
for(const item of content) {
|
||||
if(item.tag === 'message') {
|
||||
msgs.push(proto.WebMessageInfo.decode(item.content as Buffer))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return msgs
|
||||
}
|
||||
|
||||
function bufferToUInt(e: Uint8Array | Buffer, t: number) {
|
||||
let a = 0
|
||||
for(let i = 0; i < t; i++) {
|
||||
a = 256 * a + e[i]
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
@@ -319,6 +319,7 @@ export const getBinaryNodeMessages = ({ content }: BinaryNode) => {
|
||||
return msgs
|
||||
}
|
||||
|
||||
export * from './generic-utils'
|
||||
export * from './jid-utils'
|
||||
export { Binary } from '../../WABinary/Binary'
|
||||
export * from './types'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export const S_WHATSAPP_NET = '@s.whatsapp.net'
|
||||
export const OFFICIAL_BIZ_JID = '16505361212@c.us'
|
||||
export const SERVER_JID = 'server@c.us'
|
||||
export const PSA_WID = '0@c.us';
|
||||
export const PSA_WID = '0@c.us'
|
||||
export const STORIES_JID = 'status@broadcast'
|
||||
|
||||
export type JidServer = 'c.us' | 'g.us' | 'broadcast' | 's.whatsapp.net' | 'call'
|
||||
@@ -12,30 +12,32 @@ export type JidWithDevice = {
|
||||
}
|
||||
|
||||
export const jidEncode = (user: string | number | null, server: JidServer, device?: number, agent?: number) => {
|
||||
return `${user || ''}${!!agent ? `_${agent}` : ''}${!!device ? `:${device}` : ''}@${server}`
|
||||
return `${user || ''}${!!agent ? `_${agent}` : ''}${!!device ? `:${device}` : ''}@${server}`
|
||||
}
|
||||
|
||||
export const jidDecode = (jid: string) => {
|
||||
let sepIdx = typeof jid === 'string' ? jid.indexOf('@') : -1
|
||||
if(sepIdx < 0) {
|
||||
return undefined
|
||||
}
|
||||
const server = jid.slice(sepIdx+1)
|
||||
const userCombined = jid.slice(0, sepIdx)
|
||||
const sepIdx = typeof jid === 'string' ? jid.indexOf('@') : -1
|
||||
if(sepIdx < 0) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const [userAgent, device] = userCombined.split(':')
|
||||
const [user, agent] = userAgent.split('_')
|
||||
const server = jid.slice(sepIdx+1)
|
||||
const userCombined = jid.slice(0, sepIdx)
|
||||
|
||||
return {
|
||||
server,
|
||||
user,
|
||||
agent: agent ? +agent : undefined,
|
||||
device: device ? +device : undefined
|
||||
}
|
||||
const [userAgent, device] = userCombined.split(':')
|
||||
const [user, agent] = userAgent.split('_')
|
||||
|
||||
return {
|
||||
server,
|
||||
user,
|
||||
agent: agent ? +agent : undefined,
|
||||
device: device ? +device : undefined
|
||||
}
|
||||
}
|
||||
|
||||
/** is the jid a user */
|
||||
export const areJidsSameUser = (jid1: string, jid2: string) => (
|
||||
jidDecode(jid1)?.user === jidDecode(jid2)?.user
|
||||
jidDecode(jid1)?.user === jidDecode(jid2)?.user
|
||||
)
|
||||
/** is the jid a user */
|
||||
export const isJidUser = (jid: string) => (jid?.endsWith('@s.whatsapp.net'))
|
||||
@@ -47,6 +49,6 @@ export const isJidGroup = (jid: string) => (jid?.endsWith('@g.us'))
|
||||
export const isJidStatusBroadcast = (jid: string) => jid === 'status@broadcast'
|
||||
|
||||
export const jidNormalizedUser = (jid: string) => {
|
||||
const { user, server } = jidDecode(jid)
|
||||
return jidEncode(user, server === 'c.us' ? 's.whatsapp.net' : server as JidServer)
|
||||
const { user, server } = jidDecode(jid)
|
||||
return jidEncode(user, server === 'c.us' ? 's.whatsapp.net' : server as JidServer)
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
* This is done for easy serialization, to prevent running into issues with prototypes &
|
||||
* to maintain functional code structure
|
||||
* */
|
||||
export type BinaryNode = {
|
||||
export type BinaryNode = {
|
||||
tag: string
|
||||
attrs: { [key: string]: string }
|
||||
content?: BinaryNode[] | string | Uint8Array
|
||||
|
||||
Reference in New Issue
Block a user