mirror of
https://github.com/FranP-code/Baileys.git
synced 2025-10-13 00:32:22 +00:00
feat: add "strictNullChecks"
This commit is contained in:
@@ -25,7 +25,7 @@ export const WA_CERT_DETAILS = {
|
|||||||
SERIAL: 0,
|
SERIAL: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
const BASE_CONNECTION_CONFIG: CommonSocketConfig<any> = {
|
const BASE_CONNECTION_CONFIG: CommonSocketConfig = {
|
||||||
version: version as any,
|
version: version as any,
|
||||||
browser: Browsers.baileys('Chrome'),
|
browser: Browsers.baileys('Chrome'),
|
||||||
|
|
||||||
@@ -42,6 +42,7 @@ const BASE_CONNECTION_CONFIG: CommonSocketConfig<any> = {
|
|||||||
|
|
||||||
export const DEFAULT_CONNECTION_CONFIG: SocketConfig = {
|
export const DEFAULT_CONNECTION_CONFIG: SocketConfig = {
|
||||||
...BASE_CONNECTION_CONFIG,
|
...BASE_CONNECTION_CONFIG,
|
||||||
|
auth: undefined as any,
|
||||||
downloadHistory: true,
|
downloadHistory: true,
|
||||||
markOnlineOnConnect: true,
|
markOnlineOnConnect: true,
|
||||||
linkPreviewImageThumbnailWidth: 192,
|
linkPreviewImageThumbnailWidth: 192,
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ const makeAuthSocket = (config: LegacySocketConfig) => {
|
|||||||
const socket = makeSocket(config)
|
const socket = makeSocket(config)
|
||||||
const { ws } = socket
|
const { ws } = socket
|
||||||
let curveKeys: CurveKeyPair
|
let curveKeys: CurveKeyPair
|
||||||
let initTimeout: NodeJS.Timeout
|
let initTimeout: NodeJS.Timeout | undefined
|
||||||
|
|
||||||
ws.on('phone-connection', ({ value: phoneConnected }) => {
|
ws.on('phone-connection', ({ value: phoneConnected }) => {
|
||||||
updateState({ legacy: { ...state.legacy, phoneConnected } })
|
updateState({ legacy: { ...state.legacy, phoneConnected } })
|
||||||
@@ -133,7 +133,7 @@ const makeAuthSocket = (config: LegacySocketConfig) => {
|
|||||||
generateKeysForAuth(ref, ttl)
|
generateKeysForAuth(ref, ttl)
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
let loginTag: string
|
let loginTag: string | undefined
|
||||||
if(canDoLogin) {
|
if(canDoLogin) {
|
||||||
updateEncKeys()
|
updateEncKeys()
|
||||||
// if we have the info to restore a closed session
|
// if we have the info to restore a closed session
|
||||||
|
|||||||
@@ -114,9 +114,9 @@ const makeChatsSocket = (config: LegacySocketConfig) => {
|
|||||||
{
|
{
|
||||||
tag: 'read',
|
tag: 'read',
|
||||||
attrs: {
|
attrs: {
|
||||||
jid: fromMessage.remoteJid,
|
jid: fromMessage.remoteJid!,
|
||||||
count: count.toString(),
|
count: count.toString(),
|
||||||
index: fromMessage.id,
|
index: fromMessage.id!,
|
||||||
owner: fromMessage.fromMe ? 'true' : 'false'
|
owner: fromMessage.fromMe ? 'true' : 'false'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -124,7 +124,7 @@ const makeChatsSocket = (config: LegacySocketConfig) => {
|
|||||||
[ WAMetric.read, WAFlag.ignore ]
|
[ WAMetric.read, WAFlag.ignore ]
|
||||||
)
|
)
|
||||||
if(config.emitOwnEvents) {
|
if(config.emitOwnEvents) {
|
||||||
ev.emit('chats.update', [{ id: fromMessage.remoteJid, unreadCount: count < 0 ? -1 : 0 }])
|
ev.emit('chats.update', [{ id: fromMessage.remoteJid!, unreadCount: count < 0 ? -1 : 0 }])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,10 +225,11 @@ const makeChatsSocket = (config: LegacySocketConfig) => {
|
|||||||
})
|
})
|
||||||
// User Profile Name Updates
|
// User Profile Name Updates
|
||||||
socketEvents.on('CB:Conn,pushname', json => {
|
socketEvents.on('CB:Conn,pushname', json => {
|
||||||
const { legacy: { user }, connection } = state
|
const { legacy, connection } = state
|
||||||
if(connection === 'open' && json[1].pushname !== user.name) {
|
const { user } = legacy!
|
||||||
user.name = json[1].pushname
|
if(connection === 'open' && json[1].pushname !== user!.name) {
|
||||||
ev.emit('connection.update', { legacy: { ...state.legacy, user } })
|
user!.name = json[1].pushname
|
||||||
|
ev.emit('connection.update', { legacy: { ...legacy!, user } })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// read updates
|
// read updates
|
||||||
@@ -354,7 +355,7 @@ const makeChatsSocket = (config: LegacySocketConfig) => {
|
|||||||
}
|
}
|
||||||
))
|
))
|
||||||
} else if('markRead' in modification) {
|
} else if('markRead' in modification) {
|
||||||
const indexKey = getIndexKey(modification.lastMessages)
|
const indexKey = getIndexKey(modification.lastMessages)!
|
||||||
return chatRead(indexKey, modification.markRead ? 0 : -1)
|
return chatRead(indexKey, modification.markRead ? 0 : -1)
|
||||||
} else if('delete' in modification) {
|
} else if('delete' in modification) {
|
||||||
chatAttrs.type = 'delete'
|
chatAttrs.type = 'delete'
|
||||||
@@ -363,7 +364,7 @@ const makeChatsSocket = (config: LegacySocketConfig) => {
|
|||||||
if('lastMessages' in modification) {
|
if('lastMessages' in modification) {
|
||||||
const indexKey = getIndexKey(modification.lastMessages)
|
const indexKey = getIndexKey(modification.lastMessages)
|
||||||
if(indexKey) {
|
if(indexKey) {
|
||||||
chatAttrs.index = indexKey.id
|
chatAttrs.index = indexKey.id!
|
||||||
chatAttrs.owner = indexKey.fromMe ? 'true' : 'false'
|
chatAttrs.owner = indexKey.fromMe ? 'true' : 'false'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -409,7 +410,7 @@ const makeChatsSocket = (config: LegacySocketConfig) => {
|
|||||||
content: [
|
content: [
|
||||||
{
|
{
|
||||||
tag: 'presence',
|
tag: 'presence',
|
||||||
attrs: { type: type, to: toJid }
|
attrs: { type: type, to: toJid! }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -463,7 +464,7 @@ const makeChatsSocket = (config: LegacySocketConfig) => {
|
|||||||
if(config.emitOwnEvents) {
|
if(config.emitOwnEvents) {
|
||||||
const user = { ...state.legacy!.user!, name }
|
const user = { ...state.legacy!.user!, name }
|
||||||
ev.emit('connection.update', { legacy: {
|
ev.emit('connection.update', { legacy: {
|
||||||
...state.legacy, user
|
...state.legacy!, user
|
||||||
} })
|
} })
|
||||||
ev.emit('contacts.update', [{ id: user.id, name }])
|
ev.emit('contacts.update', [{ id: user.id, name }])
|
||||||
}
|
}
|
||||||
@@ -493,11 +494,11 @@ const makeChatsSocket = (config: LegacySocketConfig) => {
|
|||||||
const { eurl } = await this.setQuery ([query], [WAMetric.picture, 136], tag) as { eurl: string, status: number }
|
const { eurl } = await this.setQuery ([query], [WAMetric.picture, 136], tag) as { eurl: string, status: number }
|
||||||
|
|
||||||
if(config.emitOwnEvents) {
|
if(config.emitOwnEvents) {
|
||||||
if(jid === user.id) {
|
if(jid === user?.id) {
|
||||||
user.imgUrl = eurl
|
user.imgUrl = eurl
|
||||||
ev.emit('connection.update', {
|
ev.emit('connection.update', {
|
||||||
legacy: {
|
legacy: {
|
||||||
...state.legacy,
|
...state.legacy!,
|
||||||
user
|
user
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -23,11 +23,11 @@ const makeGroupsSocket = (config: LegacySocketConfig) => {
|
|||||||
{
|
{
|
||||||
tag: 'group',
|
tag: 'group',
|
||||||
attrs: {
|
attrs: {
|
||||||
author: state.legacy?.user?.id,
|
author: state.legacy?.user?.id!,
|
||||||
id: tag,
|
id: tag,
|
||||||
type: type,
|
type: type,
|
||||||
jid: jid,
|
jid: jid!,
|
||||||
subject: subject,
|
subject: subject!,
|
||||||
},
|
},
|
||||||
content: participants ?
|
content: participants ?
|
||||||
participants.map(jid => (
|
participants.map(jid => (
|
||||||
@@ -96,7 +96,7 @@ const makeGroupsSocket = (config: LegacySocketConfig) => {
|
|||||||
id: jid,
|
id: jid,
|
||||||
owner: attrs?.creator,
|
owner: attrs?.creator,
|
||||||
creation: +attrs?.create,
|
creation: +attrs?.create,
|
||||||
subject: null,
|
subject: '',
|
||||||
desc,
|
desc,
|
||||||
participants
|
participants
|
||||||
}
|
}
|
||||||
@@ -146,8 +146,8 @@ const makeGroupsSocket = (config: LegacySocketConfig) => {
|
|||||||
* @param participants people to include in the group
|
* @param participants people to include in the group
|
||||||
*/
|
*/
|
||||||
groupCreate: async(title: string, participants: string[]) => {
|
groupCreate: async(title: string, participants: string[]) => {
|
||||||
const response = await groupQuery('create', null, title, participants) as WAGroupCreateResponse
|
const response = await groupQuery('create', undefined, title, participants) as WAGroupCreateResponse
|
||||||
const gid = response.gid
|
const gid = response.gid!
|
||||||
let metadata: GroupMetadata
|
let metadata: GroupMetadata
|
||||||
try {
|
try {
|
||||||
metadata = await groupMetadataFull(gid)
|
metadata = await groupMetadataFull(gid)
|
||||||
@@ -199,11 +199,11 @@ const makeGroupsSocket = (config: LegacySocketConfig) => {
|
|||||||
const metadata = await groupMetadataFull(jid)
|
const metadata = await groupMetadataFull(jid)
|
||||||
const node: BinaryNode = {
|
const node: BinaryNode = {
|
||||||
tag: 'description',
|
tag: 'description',
|
||||||
attrs: { id: generateMessageID(), prev: metadata?.descId },
|
attrs: { id: generateMessageID(), prev: metadata?.descId! },
|
||||||
content: Buffer.from(description, 'utf-8')
|
content: Buffer.from(description, 'utf-8')
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await groupQuery ('description', jid, null, null, [node])
|
const response = await groupQuery('description', jid, undefined, undefined, [node])
|
||||||
ev.emit('groups.update', [ { id: jid, desc: description } ])
|
ev.emit('groups.update', [ { id: jid, desc: description } ])
|
||||||
return response
|
return response
|
||||||
},
|
},
|
||||||
@@ -213,7 +213,7 @@ const makeGroupsSocket = (config: LegacySocketConfig) => {
|
|||||||
* @param participants the people to add
|
* @param participants the people to add
|
||||||
*/
|
*/
|
||||||
groupParticipantsUpdate: async(id: string, participants: string[], action: ParticipantAction) => {
|
groupParticipantsUpdate: async(id: string, participants: string[], action: ParticipantAction) => {
|
||||||
const result: GroupModificationResponse = await groupQuery(action, id, null, participants)
|
const result: GroupModificationResponse = await groupQuery(action, id, undefined, participants)
|
||||||
const jids = Object.keys(result.participants || {})
|
const jids = Object.keys(result.participants || {})
|
||||||
ev.emit('group-participants.update', { id, participants: jids, action })
|
ev.emit('group-participants.update', { id, participants: jids, action })
|
||||||
return Object.keys(result.participants || {}).map(
|
return Object.keys(result.participants || {}).map(
|
||||||
@@ -237,7 +237,6 @@ const makeGroupsSocket = (config: LegacySocketConfig) => {
|
|||||||
const metadata: GroupMetadata = {
|
const metadata: GroupMetadata = {
|
||||||
subject: result.name,
|
subject: result.name,
|
||||||
id: jid,
|
id: jid,
|
||||||
creation: undefined,
|
|
||||||
owner: state.legacy?.user?.id,
|
owner: state.legacy?.user?.id,
|
||||||
participants: result.recipients!.map(({ id }) => (
|
participants: result.recipients!.map(({ id }) => (
|
||||||
{ id: jidNormalizedUser(id), isAdmin: false, isSuperAdmin: false }
|
{ id: jidNormalizedUser(id), isAdmin: false, isSuperAdmin: false }
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ const makeMessagesSocket = (config: LegacySocketConfig) => {
|
|||||||
count: number,
|
count: number,
|
||||||
cursor?: WAMessageCursor
|
cursor?: WAMessageCursor
|
||||||
) => {
|
) => {
|
||||||
let key: WAMessageKey
|
let key: WAMessageKey | undefined
|
||||||
if(cursor) {
|
if(cursor) {
|
||||||
key = 'before' in cursor ? cursor.before : cursor.after
|
key = 'before' in cursor ? cursor.before : cursor.after
|
||||||
}
|
}
|
||||||
@@ -61,7 +61,7 @@ const makeMessagesSocket = (config: LegacySocketConfig) => {
|
|||||||
jid: jid,
|
jid: jid,
|
||||||
kind: !cursor || 'before' in cursor ? 'before' : 'after',
|
kind: !cursor || 'before' in cursor ? 'before' : 'after',
|
||||||
count: count.toString(),
|
count: count.toString(),
|
||||||
index: key?.id,
|
index: key?.id!,
|
||||||
owner: key?.fromMe === false ? 'false' : 'true',
|
owner: key?.fromMe === false ? 'false' : 'true',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -84,9 +84,9 @@ const makeMessagesSocket = (config: LegacySocketConfig) => {
|
|||||||
tag: 'query',
|
tag: 'query',
|
||||||
attrs: {
|
attrs: {
|
||||||
type: 'media',
|
type: 'media',
|
||||||
index: message.key.id,
|
index: message.key.id!,
|
||||||
owner: message.key.fromMe ? 'true' : 'false',
|
owner: message.key.fromMe ? 'true' : 'false',
|
||||||
jid: message.key.remoteJid,
|
jid: message.key.remoteJid!,
|
||||||
epoch: currentEpoch().toString()
|
epoch: currentEpoch().toString()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -158,7 +158,7 @@ const makeMessagesSocket = (config: LegacySocketConfig) => {
|
|||||||
{
|
{
|
||||||
// the key of the deleted message is updated
|
// the key of the deleted message is updated
|
||||||
update: { message: null, key: message.key, messageStubType },
|
update: { message: null, key: message.key, messageStubType },
|
||||||
key
|
key: key!
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
return
|
return
|
||||||
@@ -167,7 +167,7 @@ const makeMessagesSocket = (config: LegacySocketConfig) => {
|
|||||||
chatUpdate.ephemeralExpiration = protocolMessage.ephemeralExpiration
|
chatUpdate.ephemeralExpiration = protocolMessage.ephemeralExpiration
|
||||||
|
|
||||||
if(isJidGroup(jid)) {
|
if(isJidGroup(jid)) {
|
||||||
emitGroupUpdate({ ephemeralDuration: protocolMessage.ephemeralExpiration || null })
|
emitGroupUpdate({ ephemeralDuration: protocolMessage.ephemeralExpiration || 0 })
|
||||||
}
|
}
|
||||||
|
|
||||||
break
|
break
|
||||||
@@ -188,18 +188,18 @@ const makeMessagesSocket = (config: LegacySocketConfig) => {
|
|||||||
switch (message.messageStubType) {
|
switch (message.messageStubType) {
|
||||||
case WAMessageStubType.CHANGE_EPHEMERAL_SETTING:
|
case WAMessageStubType.CHANGE_EPHEMERAL_SETTING:
|
||||||
chatUpdate.ephemeralSettingTimestamp = message.messageTimestamp
|
chatUpdate.ephemeralSettingTimestamp = message.messageTimestamp
|
||||||
chatUpdate.ephemeralExpiration = +message.messageStubParameters[0]
|
chatUpdate.ephemeralExpiration = +message.messageStubParameters![0]
|
||||||
if(isJidGroup(jid)) {
|
if(isJidGroup(jid)) {
|
||||||
emitGroupUpdate({ ephemeralDuration: +message.messageStubParameters[0] || null })
|
emitGroupUpdate({ ephemeralDuration: +(message.messageStubParameters?.[0] || 0) })
|
||||||
}
|
}
|
||||||
|
|
||||||
break
|
break
|
||||||
case WAMessageStubType.GROUP_PARTICIPANT_LEAVE:
|
case WAMessageStubType.GROUP_PARTICIPANT_LEAVE:
|
||||||
case WAMessageStubType.GROUP_PARTICIPANT_REMOVE:
|
case WAMessageStubType.GROUP_PARTICIPANT_REMOVE:
|
||||||
participants = message.messageStubParameters.map (jidNormalizedUser)
|
participants = message.messageStubParameters!.map (jidNormalizedUser)
|
||||||
emitParticipantsUpdate('remove')
|
emitParticipantsUpdate('remove')
|
||||||
// mark the chat read only if you left the group
|
// mark the chat read only if you left the group
|
||||||
if(participants.includes(user.id)) {
|
if(participants.includes(user!.id)) {
|
||||||
chatUpdate.readOnly = true
|
chatUpdate.readOnly = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,24 +207,24 @@ const makeMessagesSocket = (config: LegacySocketConfig) => {
|
|||||||
case WAMessageStubType.GROUP_PARTICIPANT_ADD:
|
case WAMessageStubType.GROUP_PARTICIPANT_ADD:
|
||||||
case WAMessageStubType.GROUP_PARTICIPANT_INVITE:
|
case WAMessageStubType.GROUP_PARTICIPANT_INVITE:
|
||||||
case WAMessageStubType.GROUP_PARTICIPANT_ADD_REQUEST_JOIN:
|
case WAMessageStubType.GROUP_PARTICIPANT_ADD_REQUEST_JOIN:
|
||||||
participants = message.messageStubParameters.map (jidNormalizedUser)
|
participants = message.messageStubParameters!.map (jidNormalizedUser)
|
||||||
if(participants.includes(user.id)) {
|
if(participants.includes(user!.id)) {
|
||||||
chatUpdate.readOnly = null
|
chatUpdate.readOnly = null
|
||||||
}
|
}
|
||||||
|
|
||||||
emitParticipantsUpdate('add')
|
emitParticipantsUpdate('add')
|
||||||
break
|
break
|
||||||
case WAMessageStubType.GROUP_CHANGE_ANNOUNCE:
|
case WAMessageStubType.GROUP_CHANGE_ANNOUNCE:
|
||||||
const announce = message.messageStubParameters[0] === 'on'
|
const announce = message.messageStubParameters?.[0] === 'on'
|
||||||
emitGroupUpdate({ announce })
|
emitGroupUpdate({ announce })
|
||||||
break
|
break
|
||||||
case WAMessageStubType.GROUP_CHANGE_RESTRICT:
|
case WAMessageStubType.GROUP_CHANGE_RESTRICT:
|
||||||
const restrict = message.messageStubParameters[0] === 'on'
|
const restrict = message.messageStubParameters?.[0] === 'on'
|
||||||
emitGroupUpdate({ restrict })
|
emitGroupUpdate({ restrict })
|
||||||
break
|
break
|
||||||
case WAMessageStubType.GROUP_CHANGE_SUBJECT:
|
case WAMessageStubType.GROUP_CHANGE_SUBJECT:
|
||||||
case WAMessageStubType.GROUP_CREATE:
|
case WAMessageStubType.GROUP_CREATE:
|
||||||
chatUpdate.name = message.messageStubParameters[0]
|
chatUpdate.name = message.messageStubParameters?.[0]
|
||||||
emitGroupUpdate({ subject: chatUpdate.name })
|
emitGroupUpdate({ subject: chatUpdate.name })
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -275,9 +275,9 @@ const makeMessagesSocket = (config: LegacySocketConfig) => {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
const isMsgToMe = areJidsSameUser(message.key.remoteJid, state.legacy.user?.id || '')
|
const isMsgToMe = areJidsSameUser(message.key.remoteJid!, state.legacy?.user?.id || '')
|
||||||
const flag = isMsgToMe ? WAFlag.acknowledge : WAFlag.ignore // acknowledge when sending message to oneself
|
const flag = isMsgToMe ? WAFlag.acknowledge : WAFlag.ignore // acknowledge when sending message to oneself
|
||||||
const mID = message.key.id
|
const mID = message.key.id!
|
||||||
const finalState = isMsgToMe ? WAMessageStatus.READ : WAMessageStatus.SERVER_ACK
|
const finalState = isMsgToMe ? WAMessageStatus.READ : WAMessageStatus.SERVER_ACK
|
||||||
|
|
||||||
message.status = WAMessageStatus.PENDING
|
message.status = WAMessageStatus.PENDING
|
||||||
@@ -498,7 +498,7 @@ const makeMessagesSocket = (config: LegacySocketConfig) => {
|
|||||||
search: txt,
|
search: txt,
|
||||||
count: count.toString(),
|
count: count.toString(),
|
||||||
page: page.toString(),
|
page: page.toString(),
|
||||||
jid: inJid
|
jid: inJid!
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
binaryTag: [24, WAFlag.ignore],
|
binaryTag: [24, WAFlag.ignore],
|
||||||
@@ -515,7 +515,7 @@ const makeMessagesSocket = (config: LegacySocketConfig) => {
|
|||||||
content: AnyMessageContent,
|
content: AnyMessageContent,
|
||||||
options: MiscMessageGenerationOptions & { waitForAck?: boolean } = { waitForAck: true }
|
options: MiscMessageGenerationOptions & { waitForAck?: boolean } = { waitForAck: true }
|
||||||
) => {
|
) => {
|
||||||
const userJid = state.legacy.user?.id
|
const userJid = state.legacy?.user?.id
|
||||||
if(
|
if(
|
||||||
typeof content === 'object' &&
|
typeof content === 'object' &&
|
||||||
'disappearingMessagesInChat' in content &&
|
'disappearingMessagesInChat' in content &&
|
||||||
@@ -530,7 +530,7 @@ const makeMessagesSocket = (config: LegacySocketConfig) => {
|
|||||||
await setQuery([
|
await setQuery([
|
||||||
{
|
{
|
||||||
tag: 'group',
|
tag: 'group',
|
||||||
attrs: { id: tag, jid, type: 'prop', author: userJid },
|
attrs: { id: tag, jid, type: 'prop', author: userJid! },
|
||||||
content: [
|
content: [
|
||||||
{ tag: 'ephemeral', attrs: { value: value.toString() } }
|
{ tag: 'ephemeral', attrs: { value: value.toString() } }
|
||||||
]
|
]
|
||||||
@@ -542,7 +542,7 @@ const makeMessagesSocket = (config: LegacySocketConfig) => {
|
|||||||
content,
|
content,
|
||||||
{
|
{
|
||||||
logger,
|
logger,
|
||||||
userJid: userJid,
|
userJid: userJid!,
|
||||||
getUrlInfo: generateUrlInfo,
|
getUrlInfo: generateUrlInfo,
|
||||||
upload: waUploadToServer,
|
upload: waUploadToServer,
|
||||||
mediaCache: config.mediaCache,
|
mediaCache: config.mediaCache,
|
||||||
@@ -550,7 +550,7 @@ const makeMessagesSocket = (config: LegacySocketConfig) => {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
await relayMessage(msg, { waitForAck: options.waitForAck })
|
await relayMessage(msg, { waitForAck: !!options.waitForAck })
|
||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ export const makeSocket = ({
|
|||||||
let authInfo: { encKey: Buffer, macKey: Buffer }
|
let authInfo: { encKey: Buffer, macKey: Buffer }
|
||||||
let keepAliveReq: NodeJS.Timeout
|
let keepAliveReq: NodeJS.Timeout
|
||||||
|
|
||||||
let phoneCheckInterval: NodeJS.Timeout
|
let phoneCheckInterval: NodeJS.Timeout | undefined
|
||||||
let phoneCheckListeners = 0
|
let phoneCheckListeners = 0
|
||||||
|
|
||||||
const phoneConnectionChanged = (value: boolean) => {
|
const phoneConnectionChanged = (value: boolean) => {
|
||||||
@@ -267,10 +267,10 @@ export const makeSocket = ({
|
|||||||
return result as any
|
return result as any
|
||||||
} finally {
|
} finally {
|
||||||
requiresPhoneConnection && clearPhoneCheckInterval()
|
requiresPhoneConnection && clearPhoneCheckInterval()
|
||||||
cancelPhoneChecker && cancelPhoneChecker()
|
cancelPhoneChecker! && cancelPhoneChecker!()
|
||||||
|
|
||||||
ws.off(`TAG:${tag}`, onRecv)
|
ws.off(`TAG:${tag}`, onRecv!)
|
||||||
ws.off('ws-close', onErr) // if the socket closes, you'll never receive the message
|
ws.off('ws-close', onErr!) // if the socket closes, you'll never receive the message
|
||||||
}
|
}
|
||||||
})(),
|
})(),
|
||||||
cancelToken: () => {
|
cancelToken: () => {
|
||||||
@@ -290,7 +290,7 @@ export const makeSocket = ({
|
|||||||
{ json, timeoutMs, expect200, tag, longTag, binaryTag, requiresPhoneConnection }: SocketQueryOptions
|
{ json, timeoutMs, expect200, tag, longTag, binaryTag, requiresPhoneConnection }: SocketQueryOptions
|
||||||
) => {
|
) => {
|
||||||
tag = tag || generateMessageTag(longTag)
|
tag = tag || generateMessageTag(longTag)
|
||||||
const { promise, cancelToken } = waitForMessage(tag, requiresPhoneConnection, timeoutMs)
|
const { promise, cancelToken } = waitForMessage(tag, !!requiresPhoneConnection, timeoutMs)
|
||||||
try {
|
try {
|
||||||
await sendNode({ json, tag, binaryTag })
|
await sendNode({ json, tag, binaryTag })
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ export const makeBusinessSocket = (config: SocketConfig) => {
|
|||||||
} = sock
|
} = sock
|
||||||
|
|
||||||
const getCatalog = async(jid?: string, limit = 10) => {
|
const getCatalog = async(jid?: string, limit = 10) => {
|
||||||
jid = jidNormalizedUser(jid || authState.creds.me?.id)
|
jid = jid || authState.creds.me?.id
|
||||||
|
jid = jidNormalizedUser(jid!)
|
||||||
const result = await query({
|
const result = await query({
|
||||||
tag: 'iq',
|
tag: 'iq',
|
||||||
attrs: {
|
attrs: {
|
||||||
@@ -52,7 +53,8 @@ export const makeBusinessSocket = (config: SocketConfig) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getCollections = async(jid?: string, limit = 51) => {
|
const getCollections = async(jid?: string, limit = 51) => {
|
||||||
jid = jidNormalizedUser(jid || authState.creds.me?.id)
|
jid = jid || authState.creds.me?.id
|
||||||
|
jid = jidNormalizedUser(jid!)
|
||||||
const result = await query({
|
const result = await query({
|
||||||
tag: 'iq',
|
tag: 'iq',
|
||||||
attrs: {
|
attrs: {
|
||||||
@@ -165,7 +167,7 @@ export const makeBusinessSocket = (config: SocketConfig) => {
|
|||||||
const productCatalogEditNode = getBinaryNodeChild(result, 'product_catalog_edit')
|
const productCatalogEditNode = getBinaryNodeChild(result, 'product_catalog_edit')
|
||||||
const productNode = getBinaryNodeChild(productCatalogEditNode, 'product')
|
const productNode = getBinaryNodeChild(productCatalogEditNode, 'product')
|
||||||
|
|
||||||
return parseProductNode(productNode)
|
return parseProductNode(productNode!)
|
||||||
}
|
}
|
||||||
|
|
||||||
const productCreate = async(create: ProductCreate) => {
|
const productCreate = async(create: ProductCreate) => {
|
||||||
@@ -191,7 +193,7 @@ export const makeBusinessSocket = (config: SocketConfig) => {
|
|||||||
const productCatalogAddNode = getBinaryNodeChild(result, 'product_catalog_add')
|
const productCatalogAddNode = getBinaryNodeChild(result, 'product_catalog_add')
|
||||||
const productNode = getBinaryNodeChild(productCatalogAddNode, 'product')
|
const productNode = getBinaryNodeChild(productCatalogAddNode, 'product')
|
||||||
|
|
||||||
return parseProductNode(productNode)
|
return parseProductNode(productNode!)
|
||||||
}
|
}
|
||||||
|
|
||||||
const productDelete = async(productIds: string[]) => {
|
const productDelete = async(productIds: string[]) => {
|
||||||
@@ -225,7 +227,7 @@ export const makeBusinessSocket = (config: SocketConfig) => {
|
|||||||
|
|
||||||
const productCatalogDelNode = getBinaryNodeChild(result, 'product_catalog_delete')
|
const productCatalogDelNode = getBinaryNodeChild(result, 'product_catalog_delete')
|
||||||
return {
|
return {
|
||||||
deleted: +productCatalogDelNode.attrs.deleted_count
|
deleted: +(productCatalogDelNode?.attrs.deleted_count || 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
|
|||||||
{ tag: 'privacy', attrs: { } }
|
{ tag: 'privacy', attrs: { } }
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
privacySettings = reduceBinaryNodeToDictionary(content[0] as BinaryNode, 'category')
|
privacySettings = reduceBinaryNodeToDictionary(content?.[0] as BinaryNode, 'category')
|
||||||
}
|
}
|
||||||
|
|
||||||
return privacySettings
|
return privacySettings
|
||||||
@@ -135,7 +135,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
|
|||||||
|
|
||||||
return results.map(user => {
|
return results.map(user => {
|
||||||
const contact = getBinaryNodeChild(user, 'contact')
|
const contact = getBinaryNodeChild(user, 'contact')
|
||||||
return { exists: contact.attrs.type === 'in', jid: user.attrs.jid }
|
return { exists: contact?.attrs.type === 'in', jid: user.attrs.jid }
|
||||||
}).filter(item => item.exists)
|
}).filter(item => item.exists)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,8 +147,8 @@ export const makeChatsSocket = (config: SocketConfig) => {
|
|||||||
if(result) {
|
if(result) {
|
||||||
const status = getBinaryNodeChild(result, 'status')
|
const status = getBinaryNodeChild(result, 'status')
|
||||||
return {
|
return {
|
||||||
status: status.content!.toString(),
|
status: status?.content!.toString(),
|
||||||
setAt: new Date(+status.attrs.t * 1000)
|
setAt: new Date(+(status?.attrs.t || 0) * 1000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -253,18 +253,19 @@ export const makeChatsSocket = (config: SocketConfig) => {
|
|||||||
const category = getBinaryNodeChild(getBinaryNodeChild(profiles, 'categories'), 'category')
|
const category = getBinaryNodeChild(getBinaryNodeChild(profiles, 'categories'), 'category')
|
||||||
const business_hours = getBinaryNodeChild(profiles, 'business_hours')
|
const business_hours = getBinaryNodeChild(profiles, 'business_hours')
|
||||||
const business_hours_config = business_hours && getBinaryNodeChildren(business_hours, 'business_hours_config')
|
const business_hours_config = business_hours && getBinaryNodeChildren(business_hours, 'business_hours_config')
|
||||||
|
const websiteStr = website?.content?.toString()
|
||||||
return {
|
return {
|
||||||
wid: profiles.attrs?.jid,
|
wid: profiles.attrs?.jid,
|
||||||
address: address?.content.toString(),
|
address: address?.content?.toString(),
|
||||||
description: description?.content.toString(),
|
description: description?.content?.toString() || '',
|
||||||
website: [website?.content.toString()],
|
website: websiteStr ? [websiteStr] : [],
|
||||||
email: email?.content.toString(),
|
email: email?.content?.toString(),
|
||||||
category: category?.content.toString(),
|
category: category?.content?.toString(),
|
||||||
business_hours: {
|
business_hours: {
|
||||||
timezone: business_hours?.attrs?.timezone,
|
timezone: business_hours?.attrs?.timezone,
|
||||||
business_config: business_hours_config?.map(({ attrs }) => attrs as unknown as WABusinessHoursConfig)
|
business_config: business_hours_config?.map(({ attrs }) => attrs as unknown as WABusinessHoursConfig)
|
||||||
}
|
}
|
||||||
} as unknown as WABusinessProfile
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,7 +297,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
|
|||||||
processSyncAction(
|
processSyncAction(
|
||||||
mutation,
|
mutation,
|
||||||
ev,
|
ev,
|
||||||
authState.creds.me,
|
authState.creds.me!,
|
||||||
recvChats ? { recvChats, accountSettings: authState.creds.accountSettings } : undefined,
|
recvChats ? { recvChats, accountSettings: authState.creds.accountSettings } : undefined,
|
||||||
logger
|
logger
|
||||||
)
|
)
|
||||||
@@ -402,7 +403,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
|
|||||||
} catch(error) {
|
} catch(error) {
|
||||||
// if retry attempts overshoot
|
// if retry attempts overshoot
|
||||||
// or key not found
|
// or key not found
|
||||||
const isIrrecoverableError = attemptsMap[name] >= MAX_SYNC_ATTEMPTS || error.output?.statusCode === 404
|
const isIrrecoverableError = attemptsMap[name]! >= MAX_SYNC_ATTEMPTS || error.output?.statusCode === 404
|
||||||
logger.info({ name, error: error.stack }, `failed to sync state from version${isIrrecoverableError ? '' : ', removing and trying from scratch'}`)
|
logger.info({ name, error: error.stack }, `failed to sync state from version${isIrrecoverableError ? '' : ', removing and trying from scratch'}`)
|
||||||
await authState.keys.set({ 'app-state-sync-version': { [name]: null } })
|
await authState.keys.set({ 'app-state-sync-version': { [name]: null } })
|
||||||
// increment number of retries
|
// increment number of retries
|
||||||
@@ -468,7 +469,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
|
|||||||
tag: 'chatstate',
|
tag: 'chatstate',
|
||||||
attrs: {
|
attrs: {
|
||||||
from: me!.id!,
|
from: me!.id!,
|
||||||
to: toJid,
|
to: toJid!,
|
||||||
},
|
},
|
||||||
content: [
|
content: [
|
||||||
{
|
{
|
||||||
@@ -492,7 +493,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const handlePresenceUpdate = ({ tag, attrs, content }: BinaryNode) => {
|
const handlePresenceUpdate = ({ tag, attrs, content }: BinaryNode) => {
|
||||||
let presence: PresenceData
|
let presence: PresenceData | undefined
|
||||||
const jid = attrs.from
|
const jid = attrs.from
|
||||||
const participant = attrs.participant || attrs.from
|
const participant = attrs.participant || attrs.from
|
||||||
if(tag === 'presence') {
|
if(tag === 'presence') {
|
||||||
@@ -606,8 +607,8 @@ export const makeChatsSocket = (config: SocketConfig) => {
|
|||||||
const { onMutation } = newAppStateChunkHandler(undefined)
|
const { onMutation } = newAppStateChunkHandler(undefined)
|
||||||
await decodePatches(
|
await decodePatches(
|
||||||
name,
|
name,
|
||||||
[{ ...encodeResult.patch, version: { version: encodeResult.state.version }, }],
|
[{ ...encodeResult!.patch, version: { version: encodeResult!.state.version }, }],
|
||||||
initial,
|
initial!,
|
||||||
getAppStateSyncKey,
|
getAppStateSyncKey,
|
||||||
onMutation,
|
onMutation,
|
||||||
undefined,
|
undefined,
|
||||||
@@ -698,10 +699,10 @@ export const makeChatsSocket = (config: SocketConfig) => {
|
|||||||
|
|
||||||
if(!!msg.pushName) {
|
if(!!msg.pushName) {
|
||||||
let jid = msg.key.fromMe ? authState.creds.me!.id : (msg.key.participant || msg.key.remoteJid)
|
let jid = msg.key.fromMe ? authState.creds.me!.id : (msg.key.participant || msg.key.remoteJid)
|
||||||
jid = jidNormalizedUser(jid)
|
jid = jidNormalizedUser(jid!)
|
||||||
|
|
||||||
if(!msg.key.fromMe) {
|
if(!msg.key.fromMe) {
|
||||||
ev.emit('contacts.update', [{ id: jid, notify: msg.pushName, verifiedName: msg.verifiedBizName }])
|
ev.emit('contacts.update', [{ id: jid, notify: msg.pushName, verifiedName: msg.verifiedBizName! }])
|
||||||
}
|
}
|
||||||
|
|
||||||
// update our pushname too
|
// update our pushname too
|
||||||
@@ -724,7 +725,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const isAnyHistoryMsg = isHistoryMsg(msg.message)
|
const isAnyHistoryMsg = isHistoryMsg(msg.message!)
|
||||||
if(isAnyHistoryMsg) {
|
if(isAnyHistoryMsg) {
|
||||||
// we only want to sync app state once we've all the history
|
// we only want to sync app state once we've all the history
|
||||||
// restart the app state sync timeout
|
// restart the app state sync timeout
|
||||||
@@ -741,7 +742,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
|
|||||||
ws.on('CB:chatstate', handlePresenceUpdate)
|
ws.on('CB:chatstate', handlePresenceUpdate)
|
||||||
|
|
||||||
ws.on('CB:ib,,dirty', async(node: BinaryNode) => {
|
ws.on('CB:ib,,dirty', async(node: BinaryNode) => {
|
||||||
const { attrs } = getBinaryNodeChild(node, 'dirty')
|
const { attrs } = getBinaryNodeChild(node, 'dirty')!
|
||||||
const type = attrs.type
|
const type = attrs.type
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'account_sync':
|
case 'account_sync':
|
||||||
|
|||||||
@@ -120,7 +120,9 @@ export const makeGroupsSocket = (config: SocketConfig) => {
|
|||||||
...(description ? { id: generateMessageID() } : { delete: 'true' }),
|
...(description ? { id: generateMessageID() } : { delete: 'true' }),
|
||||||
...(prev ? { prev } : {})
|
...(prev ? { prev } : {})
|
||||||
},
|
},
|
||||||
content: description ? [{ tag: 'body', attrs: {}, content: Buffer.from(description, 'utf-8') }] : null
|
content: description ? [
|
||||||
|
{ tag: 'body', attrs: {}, content: Buffer.from(description, 'utf-8') }
|
||||||
|
] : undefined
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@@ -128,17 +130,17 @@ export const makeGroupsSocket = (config: SocketConfig) => {
|
|||||||
groupInviteCode: async(jid: string) => {
|
groupInviteCode: async(jid: string) => {
|
||||||
const result = await groupQuery(jid, 'get', [{ tag: 'invite', attrs: {} }])
|
const result = await groupQuery(jid, 'get', [{ tag: 'invite', attrs: {} }])
|
||||||
const inviteNode = getBinaryNodeChild(result, 'invite')
|
const inviteNode = getBinaryNodeChild(result, 'invite')
|
||||||
return inviteNode.attrs.code
|
return inviteNode?.attrs.code
|
||||||
},
|
},
|
||||||
groupRevokeInvite: async(jid: string) => {
|
groupRevokeInvite: async(jid: string) => {
|
||||||
const result = await groupQuery(jid, 'set', [{ tag: 'invite', attrs: {} }])
|
const result = await groupQuery(jid, 'set', [{ tag: 'invite', attrs: {} }])
|
||||||
const inviteNode = getBinaryNodeChild(result, 'invite')
|
const inviteNode = getBinaryNodeChild(result, 'invite')
|
||||||
return inviteNode.attrs.code
|
return inviteNode?.attrs.code
|
||||||
},
|
},
|
||||||
groupAcceptInvite: async(code: string) => {
|
groupAcceptInvite: async(code: string) => {
|
||||||
const results = await groupQuery('@g.us', 'set', [{ tag: 'invite', attrs: { code } }])
|
const results = await groupQuery('@g.us', 'set', [{ tag: 'invite', attrs: { code } }])
|
||||||
const result = getBinaryNodeChild(results, 'group')
|
const result = getBinaryNodeChild(results, 'group')
|
||||||
return result.attrs.jid
|
return result?.attrs.jid
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* accept a GroupInviteMessage
|
* accept a GroupInviteMessage
|
||||||
@@ -147,11 +149,11 @@ export const makeGroupsSocket = (config: SocketConfig) => {
|
|||||||
*/
|
*/
|
||||||
groupAcceptInviteV4: async(key: string | WAMessageKey, inviteMessage: proto.IGroupInviteMessage) => {
|
groupAcceptInviteV4: async(key: string | WAMessageKey, inviteMessage: proto.IGroupInviteMessage) => {
|
||||||
key = typeof key === 'string' ? { remoteJid: key } : key
|
key = typeof key === 'string' ? { remoteJid: key } : key
|
||||||
const results = await groupQuery(inviteMessage.groupJid, 'set', [{
|
const results = await groupQuery(inviteMessage.groupJid!, 'set', [{
|
||||||
tag: 'accept',
|
tag: 'accept',
|
||||||
attrs: {
|
attrs: {
|
||||||
code: inviteMessage.inviteCode,
|
code: inviteMessage.inviteCode!,
|
||||||
expiration: inviteMessage.inviteExpiration.toString(),
|
expiration: inviteMessage.inviteExpiration!.toString(),
|
||||||
admin: key.remoteJid!
|
admin: key.remoteJid!
|
||||||
}
|
}
|
||||||
}])
|
}])
|
||||||
@@ -254,7 +256,7 @@ export const makeGroupsSocket = (config: SocketConfig) => {
|
|||||||
|
|
||||||
|
|
||||||
export const extractGroupMetadata = (result: BinaryNode) => {
|
export const extractGroupMetadata = (result: BinaryNode) => {
|
||||||
const group = getBinaryNodeChild(result, 'group')
|
const group = getBinaryNodeChild(result, 'group')!
|
||||||
const descChild = getBinaryNodeChild(group, 'description')
|
const descChild = getBinaryNodeChild(group, 'description')
|
||||||
let desc: string | undefined
|
let desc: string | undefined
|
||||||
let descId: string | undefined
|
let descId: string | undefined
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
|
|||||||
const isGroup = !!node.attrs.participant
|
const isGroup = !!node.attrs.participant
|
||||||
const { account, signedPreKey, signedIdentityKey: identityKey } = authState.creds
|
const { account, signedPreKey, signedIdentityKey: identityKey } = authState.creds
|
||||||
|
|
||||||
const deviceIdentity = proto.ADVSignedDeviceIdentity.encode(account).finish()
|
const deviceIdentity = proto.ADVSignedDeviceIdentity.encode(account!).finish()
|
||||||
await authState.keys.transaction(
|
await authState.keys.transaction(
|
||||||
async() => {
|
async() => {
|
||||||
const { update, preKeys } = await getNextPreKeys(authState, 1)
|
const { update, preKeys } = await getNextPreKeys(authState, 1)
|
||||||
@@ -147,7 +147,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
|
|||||||
const from = node.attrs.from
|
const from = node.attrs.from
|
||||||
if(from === S_WHATSAPP_NET) {
|
if(from === S_WHATSAPP_NET) {
|
||||||
const countChild = getBinaryNodeChild(node, 'count')
|
const countChild = getBinaryNodeChild(node, 'count')
|
||||||
const count = +countChild.attrs.value
|
const count = +countChild!.attrs.value
|
||||||
const shouldUploadMorePreKeys = count < MIN_PREKEY_COUNT
|
const shouldUploadMorePreKeys = count < MIN_PREKEY_COUNT
|
||||||
|
|
||||||
logger.debug({ count, shouldUploadMorePreKeys }, 'recv pre-key count')
|
logger.debug({ count, shouldUploadMorePreKeys }, 'recv pre-key count')
|
||||||
@@ -270,22 +270,23 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
|
|||||||
|
|
||||||
const sendMessagesAgain = async(key: proto.IMessageKey, ids: string[]) => {
|
const sendMessagesAgain = async(key: proto.IMessageKey, ids: string[]) => {
|
||||||
const msgs = await Promise.all(ids.map(id => getMessage({ ...key, id })))
|
const msgs = await Promise.all(ids.map(id => getMessage({ ...key, id })))
|
||||||
|
const remoteJid = key.remoteJid!
|
||||||
const participant = key.participant || key.remoteJid
|
const participant = key.participant || remoteJid
|
||||||
// if it's the primary jid sending the request
|
// if it's the primary jid sending the request
|
||||||
// just re-send the message to everyone
|
// just re-send the message to everyone
|
||||||
// prevents the first message decryption failure
|
// prevents the first message decryption failure
|
||||||
const sendToAll = !jidDecode(participant).device
|
const sendToAll = !jidDecode(participant)?.device
|
||||||
await assertSessions([participant], true)
|
await assertSessions([participant], true)
|
||||||
|
|
||||||
if(isJidGroup(key.remoteJid)) {
|
if(isJidGroup(remoteJid)) {
|
||||||
await authState.keys.set({ 'sender-key-memory': { [key.remoteJid]: null } })
|
await authState.keys.set({ 'sender-key-memory': { [remoteJid]: null } })
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug({ participant, sendToAll }, 'forced new session for retry recp')
|
logger.debug({ participant, sendToAll }, 'forced new session for retry recp')
|
||||||
|
|
||||||
for(let i = 0; i < msgs.length;i++) {
|
for(let i = 0; i < msgs.length;i++) {
|
||||||
if(msgs[i]) {
|
const msg = msgs[i]
|
||||||
|
if(msg) {
|
||||||
updateSendMessageAgainCount(ids[i], participant)
|
updateSendMessageAgainCount(ids[i], participant)
|
||||||
const msgRelayOpts: MessageRelayOptions = { messageId: ids[i] }
|
const msgRelayOpts: MessageRelayOptions = { messageId: ids[i] }
|
||||||
|
|
||||||
@@ -295,7 +296,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
|
|||||||
msgRelayOpts.participant = participant
|
msgRelayOpts.participant = participant
|
||||||
}
|
}
|
||||||
|
|
||||||
await relayMessage(key.remoteJid, msgs[i], msgRelayOpts)
|
await relayMessage(key.remoteJid!, msg, msgRelayOpts)
|
||||||
} else {
|
} else {
|
||||||
logger.debug({ jid: key.remoteJid, id: ids[i] }, 'recv retry request, but message not available')
|
logger.debug({ jid: key.remoteJid, id: ids[i] }, 'recv retry request, but message not available')
|
||||||
}
|
}
|
||||||
@@ -443,21 +444,21 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
|
|||||||
} else if(msg.key.fromMe) { // message was sent by us from a different device
|
} else if(msg.key.fromMe) { // message was sent by us from a different device
|
||||||
type = 'sender'
|
type = 'sender'
|
||||||
// need to specially handle this case
|
// need to specially handle this case
|
||||||
if(isJidUser(msg.key.remoteJid)) {
|
if(isJidUser(msg.key.remoteJid!)) {
|
||||||
participant = author
|
participant = author
|
||||||
}
|
}
|
||||||
} else if(!sendActiveReceipts) {
|
} else if(!sendActiveReceipts) {
|
||||||
type = 'inactive'
|
type = 'inactive'
|
||||||
}
|
}
|
||||||
|
|
||||||
await sendReceipt(msg.key.remoteJid!, participant, [msg.key.id!], type)
|
await sendReceipt(msg.key.remoteJid!, participant!, [msg.key.id!], type)
|
||||||
|
|
||||||
|
|
||||||
// send ack for history message
|
// send ack for history message
|
||||||
const isAnyHistoryMsg = isHistoryMsg(msg.message)
|
const isAnyHistoryMsg = isHistoryMsg(msg.message!)
|
||||||
if(isAnyHistoryMsg) {
|
if(isAnyHistoryMsg) {
|
||||||
const jid = jidEncode(jidDecode(msg.key.remoteJid!).user, 'c.us')
|
const jid = jidNormalizedUser(msg.key.remoteJid!)
|
||||||
await sendReceipt(jid, undefined, [msg.key.id], 'hist_sync')
|
await sendReceipt(jid, undefined, [msg.key.id!], 'hist_sync')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -516,7 +517,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
|
|||||||
const key: WAMessageKey = { remoteJid: attrs.from, fromMe: true, id: attrs.id }
|
const key: WAMessageKey = { remoteJid: attrs.from, fromMe: true, id: attrs.id }
|
||||||
const msg = await getMessage(key)
|
const msg = await getMessage(key)
|
||||||
if(msg) {
|
if(msg) {
|
||||||
await relayMessage(key.remoteJid, msg, { messageId: key.id, useUserDevicesCache: false })
|
await relayMessage(key.remoteJid!, msg, { messageId: key.id!, useUserDevicesCache: false })
|
||||||
} else {
|
} else {
|
||||||
logger.warn({ attrs }, 'could not send message again, as it was not found')
|
logger.warn({ attrs }, 'could not send message again, as it was not found')
|
||||||
}
|
}
|
||||||
@@ -539,7 +540,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
|
|||||||
// called when all offline notifs are handled
|
// called when all offline notifs are handled
|
||||||
ws.on('CB:ib,,offline', async(node: BinaryNode) => {
|
ws.on('CB:ib,,offline', async(node: BinaryNode) => {
|
||||||
const child = getBinaryNodeChild(node, 'offline')
|
const child = getBinaryNodeChild(node, 'offline')
|
||||||
const offlineNotifs = +child.attrs.count
|
const offlineNotifs = +(child?.attrs.count || 0)
|
||||||
|
|
||||||
logger.info(`handled ${offlineNotifs} offline messages/notifications`)
|
logger.info(`handled ${offlineNotifs} offline messages/notifications`)
|
||||||
await ev.flush()
|
await ev.flush()
|
||||||
|
|||||||
@@ -48,8 +48,8 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
|||||||
hosts: getBinaryNodeChildren(mediaConnNode, 'host').map(
|
hosts: getBinaryNodeChildren(mediaConnNode, 'host').map(
|
||||||
item => item.attrs as any
|
item => item.attrs as any
|
||||||
),
|
),
|
||||||
auth: mediaConnNode.attrs.auth,
|
auth: mediaConnNode!.attrs.auth,
|
||||||
ttl: +mediaConnNode.attrs.ttl,
|
ttl: +mediaConnNode!.attrs.ttl,
|
||||||
fetchDate: new Date()
|
fetchDate: new Date()
|
||||||
}
|
}
|
||||||
logger.debug('fetched media conn')
|
logger.debug('fetched media conn')
|
||||||
@@ -78,7 +78,7 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
|||||||
|
|
||||||
if(type === 'sender' && isJidUser(jid)) {
|
if(type === 'sender' && isJidUser(jid)) {
|
||||||
node.attrs.recipient = jid
|
node.attrs.recipient = jid
|
||||||
node.attrs.to = participant
|
node.attrs.to = participant!
|
||||||
} else {
|
} else {
|
||||||
node.attrs.to = jid
|
node.attrs.to = jid
|
||||||
if(participant) {
|
if(participant) {
|
||||||
@@ -134,10 +134,10 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
|||||||
const users: BinaryNode[] = []
|
const users: BinaryNode[] = []
|
||||||
jids = Array.from(new Set(jids))
|
jids = Array.from(new Set(jids))
|
||||||
for(let jid of jids) {
|
for(let jid of jids) {
|
||||||
const user = jidDecode(jid).user
|
const user = jidDecode(jid)?.user
|
||||||
jid = jidNormalizedUser(jid)
|
jid = jidNormalizedUser(jid)
|
||||||
if(userDevicesCache.has(user) && useCache) {
|
if(userDevicesCache.has(user!) && useCache) {
|
||||||
const devices: JidWithDevice[] = userDevicesCache.get(user)
|
const devices = userDevicesCache.get<JidWithDevice[]>(user!)!
|
||||||
deviceResults.push(...devices)
|
deviceResults.push(...devices)
|
||||||
|
|
||||||
logger.trace({ user }, 'using cache for devices')
|
logger.trace({ user }, 'using cache for devices')
|
||||||
@@ -278,7 +278,7 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
|||||||
|
|
||||||
let shouldIncludeDeviceIdentity = false
|
let shouldIncludeDeviceIdentity = false
|
||||||
|
|
||||||
const { user, server } = jidDecode(jid)
|
const { user, server } = jidDecode(jid)!
|
||||||
const isGroup = server === 'g.us'
|
const isGroup = server === 'g.us'
|
||||||
msgId = msgId || generateMessageID()
|
msgId = msgId || generateMessageID()
|
||||||
useUserDevicesCache = useUserDevicesCache !== false
|
useUserDevicesCache = useUserDevicesCache !== false
|
||||||
@@ -299,7 +299,7 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
|||||||
additionalAttributes = { ...additionalAttributes, device_fanout: 'false' }
|
additionalAttributes = { ...additionalAttributes, device_fanout: 'false' }
|
||||||
}
|
}
|
||||||
|
|
||||||
const { user, device } = jidDecode(participant)
|
const { user, device } = jidDecode(participant)!
|
||||||
devices.push({ user, device })
|
devices.push({ user, device })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,7 +333,7 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
|||||||
|
|
||||||
if(!participant) {
|
if(!participant) {
|
||||||
const participantsList = groupData.participants.map(p => p.id)
|
const participantsList = groupData.participants.map(p => p.id)
|
||||||
const additionalDevices = await getUSyncDevices(participantsList, useUserDevicesCache, false)
|
const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false)
|
||||||
devices.push(...additionalDevices)
|
devices.push(...additionalDevices)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,7 +376,7 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
|||||||
|
|
||||||
await authState.keys.set({ 'sender-key-memory': { [jid]: senderKeyMap } })
|
await authState.keys.set({ 'sender-key-memory': { [jid]: senderKeyMap } })
|
||||||
} else {
|
} else {
|
||||||
const { user: meUser } = jidDecode(meId)
|
const { user: meUser } = jidDecode(meId)!
|
||||||
|
|
||||||
const encodedMeMsg = encodeWAMessage({
|
const encodedMeMsg = encodeWAMessage({
|
||||||
deviceSentMessage: {
|
deviceSentMessage: {
|
||||||
@@ -389,7 +389,7 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
|||||||
devices.push({ user })
|
devices.push({ user })
|
||||||
devices.push({ user: meUser })
|
devices.push({ user: meUser })
|
||||||
|
|
||||||
const additionalDevices = await getUSyncDevices([ meId, jid ], useUserDevicesCache, true)
|
const additionalDevices = await getUSyncDevices([ meId, jid ], !!useUserDevicesCache, true)
|
||||||
devices.push(...additionalDevices)
|
devices.push(...additionalDevices)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,7 +434,7 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
|||||||
const stanza: BinaryNode = {
|
const stanza: BinaryNode = {
|
||||||
tag: 'message',
|
tag: 'message',
|
||||||
attrs: {
|
attrs: {
|
||||||
id: msgId,
|
id: msgId!,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
...(additionalAttributes || {})
|
...(additionalAttributes || {})
|
||||||
},
|
},
|
||||||
@@ -461,7 +461,7 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
|||||||
(stanza.content as BinaryNode[]).push({
|
(stanza.content as BinaryNode[]).push({
|
||||||
tag: 'device-identity',
|
tag: 'device-identity',
|
||||||
attrs: { },
|
attrs: { },
|
||||||
content: proto.ADVSignedDeviceIdentity.encode(authState.creds.account).finish()
|
content: proto.ADVSignedDeviceIdentity.encode(authState.creds.account!).finish()
|
||||||
})
|
})
|
||||||
|
|
||||||
logger.debug({ jid }, 'adding device identity')
|
logger.debug({ jid }, 'adding device identity')
|
||||||
@@ -538,7 +538,7 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
|||||||
error = result.error
|
error = result.error
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
const media = decryptMediaRetryData(result.media!, mediaKey, result.key.id)
|
const media = decryptMediaRetryData(result.media!, mediaKey, result.key.id!)
|
||||||
if(media.result !== proto.MediaRetryNotification.MediaRetryNotificationResultType.SUCCESS) {
|
if(media.result !== proto.MediaRetryNotification.MediaRetryNotificationResultType.SUCCESS) {
|
||||||
const resultStr = proto.MediaRetryNotification.MediaRetryNotificationResultType[media.result]
|
const resultStr = proto.MediaRetryNotification.MediaRetryNotificationResultType[media.result]
|
||||||
throw new Boom(
|
throw new Boom(
|
||||||
@@ -612,7 +612,7 @@ export const makeMessagesSocket = (config: SocketConfig) => {
|
|||||||
additionalAttributes.edit = '7'
|
additionalAttributes.edit = '7'
|
||||||
}
|
}
|
||||||
|
|
||||||
await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id!, cachedGroupMetadata: options.cachedGroupMetadata, additionalAttributes })
|
await relayMessage(jid, fullMsg.message!, { messageId: fullMsg.key.id!, cachedGroupMetadata: options.cachedGroupMetadata, additionalAttributes })
|
||||||
if(config.emitOwnEvents) {
|
if(config.emitOwnEvents) {
|
||||||
process.nextTick(() => {
|
process.nextTick(() => {
|
||||||
upsertMessage(fullMsg, 'append')
|
upsertMessage(fullMsg, 'append')
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ export const makeSocket = ({
|
|||||||
})
|
})
|
||||||
|
|
||||||
if(sendMsg) {
|
if(sendMsg) {
|
||||||
sendRawMessage(sendMsg).catch(onClose)
|
sendRawMessage(sendMsg).catch(onClose!)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
@@ -134,9 +134,9 @@ export const makeSocket = ({
|
|||||||
)
|
)
|
||||||
return result as any
|
return result as any
|
||||||
} finally {
|
} finally {
|
||||||
ws.off(`TAG:${msgId}`, onRecv)
|
ws.off(`TAG:${msgId}`, onRecv!)
|
||||||
ws.off('close', onErr) // if the socket closes, you'll never receive the message
|
ws.off('close', onErr!) // if the socket closes, you'll never receive the message
|
||||||
ws.off('error', onErr)
|
ws.off('error', onErr!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,7 +215,7 @@ export const makeSocket = ({
|
|||||||
]
|
]
|
||||||
})
|
})
|
||||||
const countChild = getBinaryNodeChild(result, 'count')
|
const countChild = getBinaryNodeChild(result, 'count')
|
||||||
return +countChild.attrs.value
|
return +countChild!.attrs.value
|
||||||
}
|
}
|
||||||
|
|
||||||
/** generates and uploads a set of pre-keys to the server */
|
/** generates and uploads a set of pre-keys to the server */
|
||||||
@@ -525,7 +525,7 @@ export const makeSocket = ({
|
|||||||
logger.info({ name }, 'updated pushName')
|
logger.info({ name }, 'updated pushName')
|
||||||
sendNode({
|
sendNode({
|
||||||
tag: 'presence',
|
tag: 'presence',
|
||||||
attrs: { name }
|
attrs: { name: name! }
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
logger.warn({ trace: err.stack }, 'error in sending presence update on name change')
|
logger.warn({ trace: err.stack }, 'error in sending presence update on name change')
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export const waChatKey = (pin: boolean) => ({
|
|||||||
compare: (k1: string, k2: string) => k2.localeCompare (k1)
|
compare: (k1: string, k2: string) => k2.localeCompare (k1)
|
||||||
})
|
})
|
||||||
|
|
||||||
export const waMessageID = (m: WAMessage) => m.key.id
|
export const waMessageID = (m: WAMessage) => m.key.id || ''
|
||||||
|
|
||||||
export type BaileysInMemoryStoreConfig = {
|
export type BaileysInMemoryStoreConfig = {
|
||||||
chatKey?: Comparable<Chat, string>
|
chatKey?: Comparable<Chat, string>
|
||||||
@@ -28,9 +28,9 @@ export type BaileysInMemoryStoreConfig = {
|
|||||||
const makeMessagesDictionary = () => makeOrderedDictionary(waMessageID)
|
const makeMessagesDictionary = () => makeOrderedDictionary(waMessageID)
|
||||||
|
|
||||||
export default (
|
export default (
|
||||||
{ logger, chatKey }: BaileysInMemoryStoreConfig
|
{ logger: _logger, chatKey }: BaileysInMemoryStoreConfig
|
||||||
) => {
|
) => {
|
||||||
logger = logger || DEFAULT_CONNECTION_CONFIG.logger.child({ stream: 'in-mem-store' })
|
const logger = _logger || DEFAULT_CONNECTION_CONFIG.logger.child({ stream: 'in-mem-store' })
|
||||||
chatKey = chatKey || waChatKey(true)
|
chatKey = chatKey || waChatKey(true)
|
||||||
const KeyedDB = require('@adiwajshing/keyed-db').default as new (...args: any[]) => KeyedDB<Chat, string>
|
const KeyedDB = require('@adiwajshing/keyed-db').default as new (...args: any[]) => KeyedDB<Chat, string>
|
||||||
|
|
||||||
@@ -118,9 +118,9 @@ export default (
|
|||||||
ev.on('chats.update', updates => {
|
ev.on('chats.update', updates => {
|
||||||
for(let update of updates) {
|
for(let update of updates) {
|
||||||
const result = chats.update(update.id!, chat => {
|
const result = chats.update(update.id!, chat => {
|
||||||
if(update.unreadCount > 0) {
|
if(update.unreadCount! > 0) {
|
||||||
update = { ...update }
|
update = { ...update }
|
||||||
update.unreadCount = chat.unreadCount + update.unreadCount
|
update.unreadCount = (chat.unreadCount || 0) + update.unreadCount!
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.assign(chat, update)
|
Object.assign(chat, update)
|
||||||
@@ -166,8 +166,8 @@ export default (
|
|||||||
})
|
})
|
||||||
ev.on('messages.update', updates => {
|
ev.on('messages.update', updates => {
|
||||||
for(const { update, key } of updates) {
|
for(const { update, key } of updates) {
|
||||||
const list = assertMessageList(key.remoteJid)
|
const list = assertMessageList(key.remoteJid!)
|
||||||
const result = list.updateAssign(key.id, update)
|
const result = list.updateAssign(key.id!, update)
|
||||||
if(!result) {
|
if(!result) {
|
||||||
logger.debug({ update }, 'got update for non-existent message')
|
logger.debug({ update }, 'got update for non-existent message')
|
||||||
}
|
}
|
||||||
@@ -178,7 +178,7 @@ export default (
|
|||||||
const list = messages[item.jid]
|
const list = messages[item.jid]
|
||||||
list?.clear()
|
list?.clear()
|
||||||
} else {
|
} else {
|
||||||
const jid = item.keys[0].remoteJid
|
const jid = item.keys[0].remoteJid!
|
||||||
const list = messages[jid]
|
const list = messages[jid]
|
||||||
if(list) {
|
if(list) {
|
||||||
const idSet = new Set(item.keys.map(k => k.id))
|
const idSet = new Set(item.keys.map(k => k.id))
|
||||||
@@ -189,8 +189,9 @@ export default (
|
|||||||
|
|
||||||
ev.on('groups.update', updates => {
|
ev.on('groups.update', updates => {
|
||||||
for(const update of updates) {
|
for(const update of updates) {
|
||||||
if(groupMetadata[update.id]) {
|
const id = update.id!
|
||||||
Object.assign(groupMetadata[update.id!], update)
|
if(groupMetadata[id]) {
|
||||||
|
Object.assign(groupMetadata[id], update)
|
||||||
} else {
|
} else {
|
||||||
logger.debug({ update }, 'got update for non-existant group metadata')
|
logger.debug({ update }, 'got update for non-existant group metadata')
|
||||||
}
|
}
|
||||||
@@ -223,7 +224,7 @@ export default (
|
|||||||
ev.on('message-receipt.update', updates => {
|
ev.on('message-receipt.update', updates => {
|
||||||
for(const { key, receipt } of updates) {
|
for(const { key, receipt } of updates) {
|
||||||
const obj = messages[key.remoteJid!]
|
const obj = messages[key.remoteJid!]
|
||||||
const msg = obj?.get(key.id)
|
const msg = obj?.get(key.id!)
|
||||||
if(msg) {
|
if(msg) {
|
||||||
updateMessageWithReceipt(msg, receipt)
|
updateMessageWithReceipt(msg, receipt)
|
||||||
}
|
}
|
||||||
@@ -267,12 +268,12 @@ export default (
|
|||||||
|
|
||||||
const mode = !cursor || 'before' in cursor ? 'before' : 'after'
|
const mode = !cursor || 'before' in cursor ? 'before' : 'after'
|
||||||
const cursorKey = !!cursor ? ('before' in cursor ? cursor.before : cursor.after) : undefined
|
const cursorKey = !!cursor ? ('before' in cursor ? cursor.before : cursor.after) : undefined
|
||||||
const cursorValue = cursorKey ? list.get(cursorKey.id) : undefined
|
const cursorValue = cursorKey ? list.get(cursorKey.id!) : undefined
|
||||||
|
|
||||||
let messages: WAMessage[]
|
let messages: WAMessage[]
|
||||||
if(list && mode === 'before' && (!cursorKey || cursorValue)) {
|
if(list && mode === 'before' && (!cursorKey || cursorValue)) {
|
||||||
if(cursorValue) {
|
if(cursorValue) {
|
||||||
const msgIdx = list.array.findIndex(m => m.key.id === cursorKey.id)
|
const msgIdx = list.array.findIndex(m => m.key.id === cursorKey?.id)
|
||||||
messages = list.array.slice(0, msgIdx)
|
messages = list.array.slice(0, msgIdx)
|
||||||
} else {
|
} else {
|
||||||
messages = list.array
|
messages = list.array
|
||||||
@@ -307,10 +308,10 @@ export default (
|
|||||||
return message
|
return message
|
||||||
},
|
},
|
||||||
mostRecentMessage: async(jid: string, sock: LegacyWASocket | undefined) => {
|
mostRecentMessage: async(jid: string, sock: LegacyWASocket | undefined) => {
|
||||||
let message = messages[jid]?.array.slice(-1)[0]
|
let message: WAMessage | undefined = messages[jid]?.array.slice(-1)[0]
|
||||||
if(!message) {
|
if(!message) {
|
||||||
const [result] = await sock?.fetchMessagesFromWA(jid, 1, undefined)
|
const items = await sock?.fetchMessagesFromWA(jid, 1, undefined)
|
||||||
message = result
|
message = items?.[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
return message
|
return message
|
||||||
@@ -329,24 +330,30 @@ export default (
|
|||||||
},
|
},
|
||||||
fetchGroupMetadata: async(jid: string, sock: AnyWASocket | undefined) => {
|
fetchGroupMetadata: async(jid: string, sock: AnyWASocket | undefined) => {
|
||||||
if(!groupMetadata[jid]) {
|
if(!groupMetadata[jid]) {
|
||||||
groupMetadata[jid] = await sock?.groupMetadata(jid)
|
const metadata = await sock?.groupMetadata(jid)
|
||||||
|
if(metadata) {
|
||||||
|
groupMetadata[jid] = metadata
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return groupMetadata[jid]
|
return groupMetadata[jid]
|
||||||
},
|
},
|
||||||
fetchBroadcastListInfo: async(jid: string, sock: LegacyWASocket | undefined) => {
|
fetchBroadcastListInfo: async(jid: string, sock: LegacyWASocket | undefined) => {
|
||||||
if(!groupMetadata[jid]) {
|
if(!groupMetadata[jid]) {
|
||||||
groupMetadata[jid] = await sock?.getBroadcastListInfo(jid)
|
const metadata = await sock?.getBroadcastListInfo(jid)
|
||||||
|
if(metadata) {
|
||||||
|
groupMetadata[jid] = metadata
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return groupMetadata[jid]
|
return groupMetadata[jid]
|
||||||
},
|
},
|
||||||
fetchMessageReceipts: async({ remoteJid, id }: WAMessageKey, sock: LegacyWASocket | undefined) => {
|
fetchMessageReceipts: async({ remoteJid, id }: WAMessageKey, sock: LegacyWASocket | undefined) => {
|
||||||
const list = messages[remoteJid]
|
const list = messages[remoteJid!]
|
||||||
const msg = list?.get(id)
|
const msg = list?.get(id!)
|
||||||
let receipts = msg.userReceipt
|
let receipts = msg?.userReceipt
|
||||||
if(!receipts) {
|
if(!receipts) {
|
||||||
receipts = await sock?.messageInfo(remoteJid, id)
|
receipts = await sock?.messageInfo(remoteJid!, id!)
|
||||||
if(msg) {
|
if(msg) {
|
||||||
msg.userReceipt = receipts
|
msg.userReceipt = receipts
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ function makeOrderedDictionary<T>(idGetter: (item: T) => string) {
|
|||||||
const array: T[] = []
|
const array: T[] = []
|
||||||
const dict: { [_: string]: T } = { }
|
const dict: { [_: string]: T } = { }
|
||||||
|
|
||||||
const get = (id: string) => dict[id]
|
const get = (id: string): T | undefined => dict[id]
|
||||||
|
|
||||||
const update = (item: T) => {
|
const update = (item: T) => {
|
||||||
const id = idGetter(item)
|
const id = idGetter(item)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export interface GroupMetadata {
|
|||||||
subjectOwner?: string
|
subjectOwner?: string
|
||||||
/** group subject modification date */
|
/** group subject modification date */
|
||||||
subjectTime?: number
|
subjectTime?: number
|
||||||
creation: number
|
creation?: number
|
||||||
desc?: string
|
desc?: string
|
||||||
descOwner?: string
|
descOwner?: string
|
||||||
descId?: string
|
descId?: string
|
||||||
|
|||||||
@@ -71,7 +71,8 @@ export type SocketQueryOptions = SocketSendMessageOptions & {
|
|||||||
requiresPhoneConnection?: boolean
|
requiresPhoneConnection?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LegacySocketConfig = CommonSocketConfig<LegacyAuthenticationCreds> & {
|
export type LegacySocketConfig = CommonSocketConfig & {
|
||||||
|
auth?: LegacyAuthenticationCreds
|
||||||
/** max time for the phone to respond to a connectivity test */
|
/** max time for the phone to respond to a connectivity test */
|
||||||
phoneResponseTimeMs: number
|
phoneResponseTimeMs: number
|
||||||
/** max time for WA server to respond before error with 422 */
|
/** max time for WA server to respond before error with 422 */
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export type WAMediaUpload = Buffer | { url: URL | string } | { stream: Readable
|
|||||||
/** Set of message types that are supported by the library */
|
/** Set of message types that are supported by the library */
|
||||||
export type MessageType = keyof proto.Message
|
export type MessageType = keyof proto.Message
|
||||||
|
|
||||||
export type DownloadableMessage = { mediaKey?: Uint8Array, directPath?: string, url?: string }
|
export type DownloadableMessage = { mediaKey?: Uint8Array | null, directPath?: string | null, url?: string | null }
|
||||||
|
|
||||||
export type MessageReceiptType = 'read' | 'read-self' | 'hist_sync' | 'peer_msg' | 'sender' | 'inactive' | undefined
|
export type MessageReceiptType = 'read' | 'read-self' | 'hist_sync' | 'peer_msg' | 'sender' | 'inactive' | undefined
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ export interface WAUrlInfo {
|
|||||||
'canonical-url': string
|
'canonical-url': string
|
||||||
'matched-text': string
|
'matched-text': string
|
||||||
title: string
|
title: string
|
||||||
description: string
|
description?: string
|
||||||
jpegThumbnail?: Buffer
|
jpegThumbnail?: Buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +182,7 @@ export type MediaGenerationOptions = {
|
|||||||
mediaUploadTimeoutMs?: number
|
mediaUploadTimeoutMs?: number
|
||||||
}
|
}
|
||||||
export type MessageContentGenerationOptions = MediaGenerationOptions & {
|
export type MessageContentGenerationOptions = MediaGenerationOptions & {
|
||||||
getUrlInfo?: (text: string) => Promise<WAUrlInfo>
|
getUrlInfo?: (text: string) => Promise<WAUrlInfo | undefined>
|
||||||
}
|
}
|
||||||
export type MessageGenerationOptions = MessageContentGenerationOptions & MessageGenerationOptionsFromContent
|
export type MessageGenerationOptions = MessageContentGenerationOptions & MessageGenerationOptionsFromContent
|
||||||
|
|
||||||
|
|||||||
@@ -8,9 +8,7 @@ import { MediaConnInfo } from './Message'
|
|||||||
export type WAVersion = [number, number, number]
|
export type WAVersion = [number, number, number]
|
||||||
export type WABrowserDescription = [string, string, string]
|
export type WABrowserDescription = [string, string, string]
|
||||||
|
|
||||||
export type CommonSocketConfig<T> = {
|
export type CommonSocketConfig = {
|
||||||
/** provide an auth state object to maintain the auth state */
|
|
||||||
auth?: T
|
|
||||||
/** the WS url to connect to WA */
|
/** the WS url to connect to WA */
|
||||||
waWebSocketUrl: string | URL
|
waWebSocketUrl: string | URL
|
||||||
/** Fails the connection if the socket times out in this interval */
|
/** Fails the connection if the socket times out in this interval */
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export type ConnectionState = {
|
|||||||
connection: WAConnectionState
|
connection: WAConnectionState
|
||||||
/** the error that caused the connection to close */
|
/** the error that caused the connection to close */
|
||||||
lastDisconnect?: {
|
lastDisconnect?: {
|
||||||
error: Error
|
error: Error | undefined
|
||||||
date: Date
|
date: Date
|
||||||
}
|
}
|
||||||
/** is this a new login */
|
/** is this a new login */
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ import { CommonSocketConfig } from './Socket'
|
|||||||
|
|
||||||
export type MessageRetryMap = { [msgId: string]: number }
|
export type MessageRetryMap = { [msgId: string]: number }
|
||||||
|
|
||||||
export type SocketConfig = CommonSocketConfig<AuthenticationState> & {
|
export type SocketConfig = CommonSocketConfig & {
|
||||||
|
/** provide an auth state object to maintain the auth state */
|
||||||
|
auth: AuthenticationState
|
||||||
/** By default true, should history messages be downloaded and processed */
|
/** By default true, should history messages be downloaded and processed */
|
||||||
downloadHistory: boolean
|
downloadHistory: boolean
|
||||||
/** transaction capability options for SignalKeyStore */
|
/** transaction capability options for SignalKeyStore */
|
||||||
@@ -67,18 +69,16 @@ export type WABusinessHoursConfig = {
|
|||||||
|
|
||||||
export type WABusinessProfile = {
|
export type WABusinessProfile = {
|
||||||
description: string
|
description: string
|
||||||
email: string
|
email: string | undefined
|
||||||
business_hours: {
|
business_hours: {
|
||||||
timezone?: string
|
timezone?: string
|
||||||
config?: WABusinessHoursConfig[]
|
config?: WABusinessHoursConfig[]
|
||||||
business_config?: WABusinessHoursConfig[]
|
business_config?: WABusinessHoursConfig[]
|
||||||
}
|
}
|
||||||
website: string[]
|
website: string[]
|
||||||
categories: {
|
category?: string
|
||||||
id: string
|
|
||||||
localized_display_name: string
|
|
||||||
}[]
|
|
||||||
wid?: string
|
wid?: string
|
||||||
|
address?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -36,8 +36,7 @@ export const addTransactionCapability = (state: SignalKeyStore, logger: Logger,
|
|||||||
dbQueriesInTransaction += 1
|
dbQueriesInTransaction += 1
|
||||||
const result = await state.get(type, idsRequiringFetch)
|
const result = await state.get(type, idsRequiringFetch)
|
||||||
|
|
||||||
transactionCache[type] = transactionCache[type] || { }
|
transactionCache[type] = Object.assign(transactionCache[type] || { }, result)
|
||||||
Object.assign(transactionCache[type], result)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ export const parseCollectionsNode = (node: BinaryNode) => {
|
|||||||
const collectionsNode = getBinaryNodeChild(node, 'collections')
|
const collectionsNode = getBinaryNodeChild(node, 'collections')
|
||||||
const collections = getBinaryNodeChildren(collectionsNode, 'collection').map<CatalogCollection>(
|
const collections = getBinaryNodeChildren(collectionsNode, 'collection').map<CatalogCollection>(
|
||||||
collectionNode => {
|
collectionNode => {
|
||||||
const id = getBinaryNodeChildString(collectionNode, 'id')
|
const id = getBinaryNodeChildString(collectionNode, 'id')!
|
||||||
const name = getBinaryNodeChildString(collectionNode, 'name')
|
const name = getBinaryNodeChildString(collectionNode, 'name')!
|
||||||
|
|
||||||
const products = getBinaryNodeChildren(collectionNode, 'product').map(parseProductNode)
|
const products = getBinaryNodeChildren(collectionNode, 'product').map(parseProductNode)
|
||||||
return {
|
return {
|
||||||
@@ -36,14 +36,14 @@ export const parseOrderDetailsNode = (node: BinaryNode) => {
|
|||||||
const orderNode = getBinaryNodeChild(node, 'order')
|
const orderNode = getBinaryNodeChild(node, 'order')
|
||||||
const products = getBinaryNodeChildren(orderNode, 'product').map<OrderProduct>(
|
const products = getBinaryNodeChildren(orderNode, 'product').map<OrderProduct>(
|
||||||
productNode => {
|
productNode => {
|
||||||
const imageNode = getBinaryNodeChild(productNode, 'image')
|
const imageNode = getBinaryNodeChild(productNode, 'image')!
|
||||||
return {
|
return {
|
||||||
id: getBinaryNodeChildString(productNode, 'id'),
|
id: getBinaryNodeChildString(productNode, 'id')!,
|
||||||
name: getBinaryNodeChildString(productNode, 'name'),
|
name: getBinaryNodeChildString(productNode, 'name')!,
|
||||||
imageUrl: getBinaryNodeChildString(imageNode, 'url'),
|
imageUrl: getBinaryNodeChildString(imageNode, 'url')!,
|
||||||
price: +getBinaryNodeChildString(productNode, 'price'),
|
price: +getBinaryNodeChildString(productNode, 'price')!,
|
||||||
currency: getBinaryNodeChildString(productNode, 'currency'),
|
currency: getBinaryNodeChildString(productNode, 'currency')!,
|
||||||
quantity: +getBinaryNodeChildString(productNode, 'quantity')
|
quantity: +getBinaryNodeChildString(productNode, 'quantity')!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -52,8 +52,8 @@ export const parseOrderDetailsNode = (node: BinaryNode) => {
|
|||||||
|
|
||||||
const orderDetails: OrderDetails = {
|
const orderDetails: OrderDetails = {
|
||||||
price: {
|
price: {
|
||||||
total: +getBinaryNodeChildString(priceNode, 'total'),
|
total: +getBinaryNodeChildString(priceNode, 'total')!,
|
||||||
currency: getBinaryNodeChildString(priceNode, 'currency'),
|
currency: getBinaryNodeChildString(priceNode, 'currency')!,
|
||||||
},
|
},
|
||||||
products
|
products
|
||||||
}
|
}
|
||||||
@@ -172,24 +172,24 @@ export const toProductNode = (productId: string | undefined, product: ProductCre
|
|||||||
|
|
||||||
export const parseProductNode = (productNode: BinaryNode) => {
|
export const parseProductNode = (productNode: BinaryNode) => {
|
||||||
const isHidden = productNode.attrs.is_hidden === 'true'
|
const isHidden = productNode.attrs.is_hidden === 'true'
|
||||||
const id = getBinaryNodeChildString(productNode, 'id')
|
const id = getBinaryNodeChildString(productNode, 'id')!
|
||||||
|
|
||||||
const mediaNode = getBinaryNodeChild(productNode, 'media')
|
const mediaNode = getBinaryNodeChild(productNode, 'media')!
|
||||||
const statusInfoNode = getBinaryNodeChild(productNode, 'status_info')
|
const statusInfoNode = getBinaryNodeChild(productNode, 'status_info')!
|
||||||
|
|
||||||
const product: Product = {
|
const product: Product = {
|
||||||
id,
|
id,
|
||||||
imageUrls: parseImageUrls(mediaNode),
|
imageUrls: parseImageUrls(mediaNode),
|
||||||
reviewStatus: {
|
reviewStatus: {
|
||||||
whatsapp: getBinaryNodeChildString(statusInfoNode, 'status'),
|
whatsapp: getBinaryNodeChildString(statusInfoNode, 'status')!,
|
||||||
},
|
},
|
||||||
availability: 'in stock',
|
availability: 'in stock',
|
||||||
name: getBinaryNodeChildString(productNode, 'name'),
|
name: getBinaryNodeChildString(productNode, 'name')!,
|
||||||
retailerId: getBinaryNodeChildString(productNode, 'retailer_id'),
|
retailerId: getBinaryNodeChildString(productNode, 'retailer_id'),
|
||||||
url: getBinaryNodeChildString(productNode, 'url'),
|
url: getBinaryNodeChildString(productNode, 'url'),
|
||||||
description: getBinaryNodeChildString(productNode, 'description'),
|
description: getBinaryNodeChildString(productNode, 'description')!,
|
||||||
price: +getBinaryNodeChildString(productNode, 'price'),
|
price: +getBinaryNodeChildString(productNode, 'price')!,
|
||||||
currency: getBinaryNodeChildString(productNode, 'currency'),
|
currency: getBinaryNodeChildString(productNode, 'currency')!,
|
||||||
isHidden,
|
isHidden,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,15 +246,15 @@ export const uploadingNecessaryImages = async(images: WAMediaUpload[], waUploadT
|
|||||||
const parseImageUrls = (mediaNode: BinaryNode) => {
|
const parseImageUrls = (mediaNode: BinaryNode) => {
|
||||||
const imgNode = getBinaryNodeChild(mediaNode, 'image')
|
const imgNode = getBinaryNodeChild(mediaNode, 'image')
|
||||||
return {
|
return {
|
||||||
requested: getBinaryNodeChildString(imgNode, 'request_image_url'),
|
requested: getBinaryNodeChildString(imgNode, 'request_image_url')!,
|
||||||
original: getBinaryNodeChildString(imgNode, 'original_image_url')
|
original: getBinaryNodeChildString(imgNode, 'original_image_url')!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const parseStatusInfo = (mediaNode: BinaryNode): CatalogStatus => {
|
const parseStatusInfo = (mediaNode: BinaryNode): CatalogStatus => {
|
||||||
const node = getBinaryNodeChild(mediaNode, 'status_info')
|
const node = getBinaryNodeChild(mediaNode, 'status_info')
|
||||||
return {
|
return {
|
||||||
status: getBinaryNodeChildString(node, 'status'),
|
status: getBinaryNodeChildString(node, 'status')!,
|
||||||
canAppeal: getBinaryNodeChildString(node, 'can_appeal') === 'true',
|
canAppeal: getBinaryNodeChildString(node, 'can_appeal') === 'true',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -220,7 +220,7 @@ export const decodeSyncdMutations = async(
|
|||||||
const encContent = content.slice(0, -32)
|
const encContent = content.slice(0, -32)
|
||||||
const ogValueMac = content.slice(-32)
|
const ogValueMac = content.slice(-32)
|
||||||
if(validateMacs) {
|
if(validateMacs) {
|
||||||
const contentHmac = generateMac(operation, encContent, record.keyId!.id!, key.valueMacKey)
|
const contentHmac = generateMac(operation!, encContent, record.keyId!.id!, key.valueMacKey)
|
||||||
if(Buffer.compare(contentHmac, ogValueMac) !== 0) {
|
if(Buffer.compare(contentHmac, ogValueMac) !== 0) {
|
||||||
throw new Boom('HMAC content verification failed')
|
throw new Boom('HMAC content verification failed')
|
||||||
}
|
}
|
||||||
@@ -231,7 +231,7 @@ export const decodeSyncdMutations = async(
|
|||||||
|
|
||||||
if(validateMacs) {
|
if(validateMacs) {
|
||||||
const hmac = hmacSign(syncAction.index, key.indexKey)
|
const hmac = hmacSign(syncAction.index, key.indexKey)
|
||||||
if(Buffer.compare(hmac, record.index!.blob) !== 0) {
|
if(Buffer.compare(hmac, record.index!.blob!) !== 0) {
|
||||||
throw new Boom('HMAC index verification failed')
|
throw new Boom('HMAC index verification failed')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -242,7 +242,7 @@ export const decodeSyncdMutations = async(
|
|||||||
ltGenerator.mix({
|
ltGenerator.mix({
|
||||||
indexMac: record.index!.blob!,
|
indexMac: record.index!.blob!,
|
||||||
valueMac: ogValueMac,
|
valueMac: ogValueMac,
|
||||||
operation: operation
|
operation: operation!
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,13 +258,13 @@ export const decodeSyncdPatch = async(
|
|||||||
validateMacs: boolean
|
validateMacs: boolean
|
||||||
) => {
|
) => {
|
||||||
if(validateMacs) {
|
if(validateMacs) {
|
||||||
const base64Key = Buffer.from(msg.keyId!.id).toString('base64')
|
const base64Key = Buffer.from(msg.keyId!.id!).toString('base64')
|
||||||
const mainKeyObj = await getAppStateSyncKey(base64Key)
|
const mainKeyObj = await getAppStateSyncKey(base64Key)
|
||||||
const mainKey = mutationKeys(mainKeyObj.keyData!)
|
const mainKey = mutationKeys(mainKeyObj.keyData!)
|
||||||
const mutationmacs = msg.mutations!.map(mutation => mutation.record!.value!.blob!.slice(-32))
|
const mutationmacs = msg.mutations!.map(mutation => mutation.record!.value!.blob!.slice(-32))
|
||||||
|
|
||||||
const patchMac = generatePatchMac(msg.snapshotMac, mutationmacs, toNumber(msg.version!.version), name, mainKey.patchMacKey)
|
const patchMac = generatePatchMac(msg.snapshotMac!, mutationmacs, toNumber(msg.version!.version!), name, mainKey.patchMacKey)
|
||||||
if(Buffer.compare(patchMac, msg.patchMac) !== 0) {
|
if(Buffer.compare(patchMac, msg.patchMac!) !== 0) {
|
||||||
throw new Boom('Invalid patch mac')
|
throw new Boom('Invalid patch mac')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -418,10 +418,10 @@ export const decodePatches = async(
|
|||||||
logger?.trace({ name, version }, 'downloading external patch')
|
logger?.trace({ name, version }, 'downloading external patch')
|
||||||
const ref = await downloadExternalPatch(syncd.externalMutations)
|
const ref = await downloadExternalPatch(syncd.externalMutations)
|
||||||
logger?.debug({ name, version, mutations: ref.mutations.length }, 'downloaded external patch')
|
logger?.debug({ name, version, mutations: ref.mutations.length }, 'downloaded external patch')
|
||||||
syncd.mutations.push(...ref.mutations)
|
syncd.mutations?.push(...ref.mutations)
|
||||||
}
|
}
|
||||||
|
|
||||||
const patchVersion = toNumber(version.version!)
|
const patchVersion = toNumber(version!.version!)
|
||||||
|
|
||||||
newState.version = patchVersion
|
newState.version = patchVersion
|
||||||
const shouldMutate = typeof minimumVersionNumber === 'undefined' || patchVersion > minimumVersionNumber
|
const shouldMutate = typeof minimumVersionNumber === 'undefined' || patchVersion > minimumVersionNumber
|
||||||
@@ -439,7 +439,7 @@ export const decodePatches = async(
|
|||||||
|
|
||||||
const result = mutationKeys(keyEnc.keyData!)
|
const result = mutationKeys(keyEnc.keyData!)
|
||||||
const computedSnapshotMac = generateSnapshotMac(newState.hash, newState.version, name, result.snapshotMacKey)
|
const computedSnapshotMac = generateSnapshotMac(newState.hash, newState.version, name, result.snapshotMacKey)
|
||||||
if(Buffer.compare(snapshotMac, computedSnapshotMac) !== 0) {
|
if(Buffer.compare(snapshotMac!, computedSnapshotMac) !== 0) {
|
||||||
throw new Boom(`failed to verify LTHash at ${newState.version} of ${name}`)
|
throw new Boom(`failed to verify LTHash at ${newState.version} of ${name}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -482,7 +482,6 @@ export const chatModificationToAppPatch = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(m.key.participant) {
|
if(m.key.participant) {
|
||||||
m.key = { ...m.key }
|
|
||||||
m.key.participant = jidNormalizedUser(m.key.participant)
|
m.key.participant = jidNormalizedUser(m.key.participant)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -627,7 +626,7 @@ export const processSyncAction = (
|
|||||||
if(
|
if(
|
||||||
isValidPatchBasedOnMessageRange(id, archiveAction.messageRange)
|
isValidPatchBasedOnMessageRange(id, archiveAction.messageRange)
|
||||||
|| !isInitialSync
|
|| !isInitialSync
|
||||||
|| !accountSettings.unarchiveChats
|
|| !accountSettings?.unarchiveChats
|
||||||
) {
|
) {
|
||||||
// basically we don't need to fire an "archive" update if the chat is being marked unarchvied
|
// basically we don't need to fire an "archive" update if the chat is being marked unarchvied
|
||||||
// this only applies for the initial sync
|
// this only applies for the initial sync
|
||||||
@@ -661,19 +660,21 @@ export const processSyncAction = (
|
|||||||
}
|
}
|
||||||
] })
|
] })
|
||||||
} else if(action?.contactAction) {
|
} else if(action?.contactAction) {
|
||||||
ev.emit('contacts.upsert', [{ id, name: action.contactAction!.fullName }])
|
ev.emit('contacts.upsert', [{ id, name: action.contactAction!.fullName! }])
|
||||||
} else if(action?.pushNameSetting) {
|
} else if(action?.pushNameSetting) {
|
||||||
if(me?.name !== action?.pushNameSetting) {
|
if(me?.name !== action?.pushNameSetting) {
|
||||||
ev.emit('creds.update', { me: { ...me, name: action?.pushNameSetting?.name! } })
|
ev.emit('creds.update', { me: { ...me, name: action?.pushNameSetting?.name! } })
|
||||||
}
|
}
|
||||||
} else if(action?.pinAction) {
|
} else if(action?.pinAction) {
|
||||||
ev.emit('chats.update', [{ id, pin: action.pinAction?.pinned ? toNumber(action.timestamp) : null }])
|
ev.emit('chats.update', [{ id, pin: action.pinAction?.pinned ? toNumber(action.timestamp!) : null }])
|
||||||
} else if(action?.unarchiveChatsSetting) {
|
} else if(action?.unarchiveChatsSetting) {
|
||||||
const unarchiveChats = !!action.unarchiveChatsSetting.unarchiveChats
|
const unarchiveChats = !!action.unarchiveChatsSetting.unarchiveChats
|
||||||
ev.emit('creds.update', { accountSettings: { unarchiveChats } })
|
ev.emit('creds.update', { accountSettings: { unarchiveChats } })
|
||||||
|
|
||||||
logger.info(`archive setting updated => '${action.unarchiveChatsSetting.unarchiveChats}'`)
|
logger?.info(`archive setting updated => '${action.unarchiveChatsSetting.unarchiveChats}'`)
|
||||||
accountSettings.unarchiveChats = unarchiveChats
|
if(accountSettings) {
|
||||||
|
accountSettings.unarchiveChats = unarchiveChats
|
||||||
|
}
|
||||||
} else if(action?.starAction) {
|
} else if(action?.starAction) {
|
||||||
ev.emit('messages.update', [
|
ev.emit('messages.update', [
|
||||||
{
|
{
|
||||||
@@ -689,12 +690,12 @@ export const processSyncAction = (
|
|||||||
ev.emit('chats.delete', [id])
|
ev.emit('chats.delete', [id])
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.warn({ syncAction, id }, 'unprocessable update')
|
logger?.warn({ syncAction, id }, 'unprocessable update')
|
||||||
}
|
}
|
||||||
|
|
||||||
function isValidPatchBasedOnMessageRange(id: string, msgRange: proto.ISyncActionMessageRange) {
|
function isValidPatchBasedOnMessageRange(id: string, msgRange: proto.ISyncActionMessageRange | null | undefined) {
|
||||||
const chat = recvChats?.[id]
|
const chat = recvChats?.[id]
|
||||||
const lastMsgTimestamp = msgRange.lastMessageTimestamp || msgRange.lastSystemMessageTimestamp || 0
|
const lastMsgTimestamp = msgRange?.lastMessageTimestamp || msgRange?.lastSystemMessageTimestamp || 0
|
||||||
const chatLastMsgTimestamp = chat?.lastMsgRecvTimestamp || 0
|
const chatLastMsgTimestamp = chat?.lastMsgRecvTimestamp || 0
|
||||||
return lastMsgTimestamp >= chatLastMsgTimestamp
|
return lastMsgTimestamp >= chatLastMsgTimestamp
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ export const decodeMessageStanza = (stanza: BinaryNode, auth: AuthenticationStat
|
|||||||
|
|
||||||
chatId = from
|
chatId = from
|
||||||
author = participant
|
author = participant
|
||||||
|
} else {
|
||||||
|
throw new Boom('Unknown message type', { data: stanza })
|
||||||
}
|
}
|
||||||
|
|
||||||
const sender = msgType === 'chat' ? author : chatId
|
const sender = msgType === 'chat' ? author : chatId
|
||||||
@@ -117,6 +119,8 @@ export const decodeMessageStanza = (stanza: BinaryNode, auth: AuthenticationStat
|
|||||||
const user = isJidUser(sender) ? sender : author
|
const user = isJidUser(sender) ? sender : author
|
||||||
msgBuffer = await decryptSignalProto(user, e2eType, content as Buffer, auth)
|
msgBuffer = await decryptSignalProto(user, e2eType, content as Buffer, auth)
|
||||||
break
|
break
|
||||||
|
default:
|
||||||
|
throw new Error(`Unknown e2e type: ${e2eType}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
let msg: proto.IMessage = proto.Message.decode(unpadRandomMax16(msgBuffer))
|
let msg: proto.IMessage = proto.Message.decode(unpadRandomMax16(msgBuffer))
|
||||||
|
|||||||
@@ -96,6 +96,8 @@ export const makeEventBuffer = (logger: Logger): BaileysBufferableEventEmitter =
|
|||||||
isBuffering = true
|
isBuffering = true
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
},
|
},
|
||||||
async flush() {
|
async flush() {
|
||||||
if(!isBuffering) {
|
if(!isBuffering) {
|
||||||
@@ -209,12 +211,13 @@ function append<E extends BufferableEvent>(
|
|||||||
case 'contacts.update':
|
case 'contacts.update':
|
||||||
const contactUpdates = eventData as BaileysEventMap<any>['contacts.update']
|
const contactUpdates = eventData as BaileysEventMap<any>['contacts.update']
|
||||||
for(const update of contactUpdates) {
|
for(const update of contactUpdates) {
|
||||||
|
const id = update.id!
|
||||||
const upsert = data.contactUpserts[update.id!]
|
const upsert = data.contactUpserts[update.id!]
|
||||||
if(upsert) {
|
if(upsert) {
|
||||||
Object.assign(upsert, update)
|
Object.assign(upsert, update)
|
||||||
} else {
|
} else {
|
||||||
const contactUpdate = data.contactUpdates[update.id] || { }
|
const contactUpdate = data.contactUpdates[id] || { }
|
||||||
data.contactUpdates[update.id] = Object.assign(contactUpdate, update)
|
data.contactUpdates[id] = Object.assign(contactUpdate, update)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,8 +315,9 @@ function append<E extends BufferableEvent>(
|
|||||||
case 'groups.update':
|
case 'groups.update':
|
||||||
const groupUpdates = eventData as BaileysEventMap<any>['groups.update']
|
const groupUpdates = eventData as BaileysEventMap<any>['groups.update']
|
||||||
for(const update of groupUpdates) {
|
for(const update of groupUpdates) {
|
||||||
const groupUpdate = data.groupUpdates[update.id] || { }
|
const id = update.id!
|
||||||
data.groupUpdates[update.id] = Object.assign(groupUpdate, update)
|
const groupUpdate = data.groupUpdates[id] || { }
|
||||||
|
data.groupUpdates[id] = Object.assign(groupUpdate, update)
|
||||||
}
|
}
|
||||||
|
|
||||||
break
|
break
|
||||||
@@ -324,12 +328,12 @@ function append<E extends BufferableEvent>(
|
|||||||
function decrementChatReadCounterIfMsgDidUnread(message: WAMessage) {
|
function decrementChatReadCounterIfMsgDidUnread(message: WAMessage) {
|
||||||
// decrement chat unread counter
|
// decrement chat unread counter
|
||||||
// if the message has already been marked read by us
|
// if the message has already been marked read by us
|
||||||
const chatId = message.key.remoteJid
|
const chatId = message.key.remoteJid!
|
||||||
const chat = data.chatUpdates[chatId] || data.chatUpserts[chatId]
|
const chat = data.chatUpdates[chatId] || data.chatUpserts[chatId]
|
||||||
if(
|
if(
|
||||||
isRealMessage(message)
|
isRealMessage(message)
|
||||||
&& shouldIncrementChatUnread(message)
|
&& shouldIncrementChatUnread(message)
|
||||||
&& typeof chat?.unreadCount !== 'undefined'
|
&& typeof chat?.unreadCount === 'number'
|
||||||
&& chat.unreadCount > 0
|
&& chat.unreadCount > 0
|
||||||
) {
|
) {
|
||||||
logger.debug({ chatId: chat.id }, 'decrementing chat counter')
|
logger.debug({ chatId: chat.id }, 'decrementing chat counter')
|
||||||
@@ -413,16 +417,16 @@ function consolidateEvents(data: BufferedEventData) {
|
|||||||
function concatChats<C extends Partial<Chat>>(a: C, b: C) {
|
function concatChats<C extends Partial<Chat>>(a: C, b: C) {
|
||||||
if(b.unreadCount === null) {
|
if(b.unreadCount === null) {
|
||||||
// neutralize unread counter
|
// neutralize unread counter
|
||||||
if(a.unreadCount < 0) {
|
if(a.unreadCount! < 0) {
|
||||||
a.unreadCount = undefined
|
a.unreadCount = undefined
|
||||||
b.unreadCount = undefined
|
b.unreadCount = undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(typeof a.unreadCount !== 'undefined' && typeof b.unreadCount !== 'undefined') {
|
if(typeof a.unreadCount === 'number' && typeof b.unreadCount === 'number') {
|
||||||
b = { ...b }
|
b = { ...b }
|
||||||
if(b.unreadCount >= 0) {
|
if(b.unreadCount! >= 0) {
|
||||||
b.unreadCount = Math.max(b.unreadCount, 0) + Math.max(a.unreadCount, 0)
|
b.unreadCount = Math.max(b.unreadCount!, 0) + Math.max(a.unreadCount, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,40 +86,21 @@ export const encodeBigEndian = (e: number, t = 4) => {
|
|||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
export const toNumber = (t: Long | number): number => ((typeof t === 'object' && t) ? ('toNumber' in t ? t.toNumber() : (t as any).low) : t)
|
export const toNumber = (t: Long | number | null | undefined): number => ((typeof t === 'object' && t) ? ('toNumber' in t ? t.toNumber() : (t as any).low) : t)
|
||||||
|
|
||||||
export function shallowChanges <T>(old: T, current: T, { lookForDeletedKeys }: {lookForDeletedKeys: boolean}): Partial<T> {
|
|
||||||
const changes: Partial<T> = {}
|
|
||||||
for(const key in current) {
|
|
||||||
if(old[key] !== current[key]) {
|
|
||||||
changes[key] = current[key] || null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(lookForDeletedKeys) {
|
|
||||||
for(const key in old) {
|
|
||||||
if(!changes[key] && old[key] !== current[key]) {
|
|
||||||
changes[key] = current[key] || null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return changes
|
|
||||||
}
|
|
||||||
|
|
||||||
/** unix timestamp of a date in seconds */
|
/** unix timestamp of a date in seconds */
|
||||||
export const unixTimestampSeconds = (date: Date = new Date()) => Math.floor(date.getTime() / 1000)
|
export const unixTimestampSeconds = (date: Date = new Date()) => Math.floor(date.getTime() / 1000)
|
||||||
|
|
||||||
export type DebouncedTimeout = ReturnType<typeof debouncedTimeout>
|
export type DebouncedTimeout = ReturnType<typeof debouncedTimeout>
|
||||||
|
|
||||||
export const debouncedTimeout = (intervalMs: number = 1000, task: () => void = undefined) => {
|
export const debouncedTimeout = (intervalMs: number = 1000, task?: () => void) => {
|
||||||
let timeout: NodeJS.Timeout
|
let timeout: NodeJS.Timeout | undefined
|
||||||
return {
|
return {
|
||||||
start: (newIntervalMs?: number, newTask?: () => void) => {
|
start: (newIntervalMs?: number, newTask?: () => void) => {
|
||||||
task = newTask || task
|
task = newTask || task
|
||||||
intervalMs = newIntervalMs || intervalMs
|
intervalMs = newIntervalMs || intervalMs
|
||||||
timeout && clearTimeout(timeout)
|
timeout && clearTimeout(timeout)
|
||||||
timeout = setTimeout(task, intervalMs)
|
timeout = setTimeout(() => task?.(), intervalMs)
|
||||||
},
|
},
|
||||||
cancel: () => {
|
cancel: () => {
|
||||||
timeout && clearTimeout(timeout)
|
timeout && clearTimeout(timeout)
|
||||||
@@ -155,7 +136,7 @@ export const delayCancellable = (ms: number) => {
|
|||||||
return { delay, cancel }
|
return { delay, cancel }
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function promiseTimeout<T>(ms: number, promise: (resolve: (v?: T)=>void, reject: (error) => void) => void) {
|
export async function promiseTimeout<T>(ms: number | undefined, promise: (resolve: (v?: T)=>void, reject: (error) => void) => void) {
|
||||||
if(!ms) {
|
if(!ms) {
|
||||||
return new Promise (promise)
|
return new Promise (promise)
|
||||||
}
|
}
|
||||||
@@ -185,7 +166,7 @@ export async function promiseTimeout<T>(ms: number, promise: (resolve: (v?: T)=>
|
|||||||
export const generateMessageID = () => 'BAE5' + randomBytes(6).toString('hex').toUpperCase()
|
export const generateMessageID = () => 'BAE5' + randomBytes(6).toString('hex').toUpperCase()
|
||||||
|
|
||||||
export function bindWaitForEvent<T extends keyof BaileysEventMap<any>>(ev: CommonBaileysEventEmitter<any>, event: T) {
|
export function bindWaitForEvent<T extends keyof BaileysEventMap<any>>(ev: CommonBaileysEventEmitter<any>, event: T) {
|
||||||
return async(check: (u: BaileysEventMap<any>[T]) => boolean, timeoutMs?: number) => {
|
return async(check: (u: BaileysEventMap<any>[T]) => boolean | undefined, timeoutMs?: number) => {
|
||||||
let listener: (item: BaileysEventMap<any>[T]) => void
|
let listener: (item: BaileysEventMap<any>[T]) => void
|
||||||
let closeListener: any
|
let closeListener: any
|
||||||
await (
|
await (
|
||||||
@@ -291,7 +272,7 @@ const STATUS_MAP: { [_: string]: proto.WebMessageInfo.WebMessageInfoStatus } = {
|
|||||||
* @param type type from receipt
|
* @param type type from receipt
|
||||||
*/
|
*/
|
||||||
export const getStatusFromReceiptType = (type: string | undefined) => {
|
export const getStatusFromReceiptType = (type: string | undefined) => {
|
||||||
const status = STATUS_MAP[type]
|
const status = STATUS_MAP[type!]
|
||||||
if(typeof type === 'undefined') {
|
if(typeof type === 'undefined') {
|
||||||
return proto.WebMessageInfo.WebMessageInfoStatus.DELIVERY_ACK
|
return proto.WebMessageInfo.WebMessageInfoStatus.DELIVERY_ACK
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ export const processHistoryMessage = (
|
|||||||
switch (item.syncType) {
|
switch (item.syncType) {
|
||||||
case proto.HistorySync.HistorySyncHistorySyncType.INITIAL_BOOTSTRAP:
|
case proto.HistorySync.HistorySyncHistorySyncType.INITIAL_BOOTSTRAP:
|
||||||
case proto.HistorySync.HistorySyncHistorySyncType.RECENT:
|
case proto.HistorySync.HistorySyncHistorySyncType.RECENT:
|
||||||
for(const chat of item.conversations) {
|
for(const chat of item.conversations!) {
|
||||||
const contactId = `c:${chat.id}`
|
const contactId = `c:${chat.id}`
|
||||||
if(chat.name && !historyCache.has(contactId)) {
|
if(chat.name && !historyCache.has(contactId)) {
|
||||||
contacts.push({ id: chat.id, name: chat.name })
|
contacts.push({ id: chat.id, name: chat.name })
|
||||||
@@ -43,15 +43,16 @@ export const processHistoryMessage = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
const msgs = chat.messages || []
|
const msgs = chat.messages || []
|
||||||
for(const { message } of msgs) {
|
for(const item of msgs) {
|
||||||
|
const message = item.message!
|
||||||
const uqId = `${message.key.remoteJid}:${message.key.id}`
|
const uqId = `${message.key.remoteJid}:${message.key.id}`
|
||||||
if(!historyCache.has(uqId)) {
|
if(!historyCache.has(uqId)) {
|
||||||
messages.push(message)
|
messages.push(message)
|
||||||
|
|
||||||
const curItem = recvChats[message.key.remoteJid]
|
const curItem = recvChats[message.key.remoteJid!]
|
||||||
const timestamp = toNumber(message.messageTimestamp)
|
const timestamp = toNumber(message.messageTimestamp)
|
||||||
if(!message.key.fromMe && (!curItem || timestamp > curItem.lastMsgRecvTimestamp)) {
|
if(!message.key.fromMe && (!curItem || timestamp > curItem.lastMsgRecvTimestamp)) {
|
||||||
recvChats[message.key.remoteJid] = { lastMsgRecvTimestamp: timestamp }
|
recvChats[message.key.remoteJid!] = { lastMsgRecvTimestamp: timestamp }
|
||||||
// keep only the most recent message in the chat array
|
// keep only the most recent message in the chat array
|
||||||
chat.messages = [{ message }]
|
chat.messages = [{ message }]
|
||||||
}
|
}
|
||||||
@@ -72,10 +73,10 @@ export const processHistoryMessage = (
|
|||||||
|
|
||||||
break
|
break
|
||||||
case proto.HistorySync.HistorySyncHistorySyncType.PUSH_NAME:
|
case proto.HistorySync.HistorySyncHistorySyncType.PUSH_NAME:
|
||||||
for(const c of item.pushnames) {
|
for(const c of item.pushnames!) {
|
||||||
const contactId = `c:${c.id}`
|
const contactId = `c:${c.id}`
|
||||||
if(!historyCache.has(contactId)) {
|
if(!historyCache.has(contactId)) {
|
||||||
contacts.push({ notify: c.pushname, id: c.id })
|
contacts.push({ notify: c.pushname!, id: c.id! })
|
||||||
historyCache.add(contactId)
|
historyCache.add(contactId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export const decodeWAMessage = (
|
|||||||
// If a query was done, the server will respond with the same message tag we sent the query with
|
// If a query was done, the server will respond with the same message tag we sent the query with
|
||||||
const messageTag: string = message.slice(0, commaIndex).toString()
|
const messageTag: string = message.slice(0, commaIndex).toString()
|
||||||
let json: any
|
let json: any
|
||||||
let tags: WATag
|
let tags: WATag | undefined
|
||||||
if(data.length) {
|
if(data.length) {
|
||||||
const possiblyEnc = (data.length > 32 && data.length % 16 === 0)
|
const possiblyEnc = (data.length > 32 && data.length % 16 === 0)
|
||||||
if(typeof data === 'string' || !possiblyEnc) {
|
if(typeof data === 'string' || !possiblyEnc) {
|
||||||
|
|||||||
@@ -62,7 +62,11 @@ export const hkdfInfoKey = (type: MediaType) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** generates all the keys required to encrypt/decrypt & sign a media message */
|
/** generates all the keys required to encrypt/decrypt & sign a media message */
|
||||||
export function getMediaKeys(buffer: Uint8Array | string, mediaType: MediaType): MediaDecryptionKeyInfo {
|
export function getMediaKeys(buffer: Uint8Array | string | null | undefined, mediaType: MediaType): MediaDecryptionKeyInfo {
|
||||||
|
if(!buffer) {
|
||||||
|
throw new Boom('Cannot derive from empty media key')
|
||||||
|
}
|
||||||
|
|
||||||
if(typeof buffer === 'string') {
|
if(typeof buffer === 'string') {
|
||||||
buffer = Buffer.from(buffer.replace('data:;base64,', ''), 'base64')
|
buffer = Buffer.from(buffer.replace('data:;base64,', ''), 'base64')
|
||||||
}
|
}
|
||||||
@@ -163,13 +167,13 @@ export async function getAudioDuration(buffer: Buffer | string | Readable) {
|
|||||||
const musicMetadata = await import('music-metadata')
|
const musicMetadata = await import('music-metadata')
|
||||||
let metadata: IAudioMetadata
|
let metadata: IAudioMetadata
|
||||||
if(Buffer.isBuffer(buffer)) {
|
if(Buffer.isBuffer(buffer)) {
|
||||||
metadata = await musicMetadata.parseBuffer(buffer, null, { duration: true })
|
metadata = await musicMetadata.parseBuffer(buffer, undefined, { duration: true })
|
||||||
} else if(typeof buffer === 'string') {
|
} else if(typeof buffer === 'string') {
|
||||||
const rStream = createReadStream(buffer)
|
const rStream = createReadStream(buffer)
|
||||||
metadata = await musicMetadata.parseStream(rStream, null, { duration: true })
|
metadata = await musicMetadata.parseStream(rStream, undefined, { duration: true })
|
||||||
rStream.close()
|
rStream.close()
|
||||||
} else {
|
} else {
|
||||||
metadata = await musicMetadata.parseStream(buffer, null, { duration: true })
|
metadata = await musicMetadata.parseStream(buffer, undefined, { duration: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
return metadata.format.duration
|
return metadata.format.duration
|
||||||
@@ -216,7 +220,7 @@ export async function generateThumbnail(
|
|||||||
logger?: Logger
|
logger?: Logger
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
let thumbnail: string
|
let thumbnail: string | undefined
|
||||||
if(mediaType === 'image') {
|
if(mediaType === 'image') {
|
||||||
const buff = await extractImageThumb(file)
|
const buff = await extractImageThumb(file)
|
||||||
thumbnail = buff.toString('base64')
|
thumbnail = buff.toString('base64')
|
||||||
@@ -259,8 +263,8 @@ export const encryptedStream = async(
|
|||||||
// const encWriteStream = createWriteStream(encBodyPath)
|
// const encWriteStream = createWriteStream(encBodyPath)
|
||||||
const encWriteStream = new Readable({ read: () => {} })
|
const encWriteStream = new Readable({ read: () => {} })
|
||||||
|
|
||||||
let bodyPath: string
|
let bodyPath: string | undefined
|
||||||
let writeStream: WriteStream
|
let writeStream: WriteStream | undefined
|
||||||
let didSaveToTmpPath = false
|
let didSaveToTmpPath = false
|
||||||
if(type === 'file') {
|
if(type === 'file') {
|
||||||
bodyPath = (media as any).url
|
bodyPath = (media as any).url
|
||||||
@@ -272,7 +276,7 @@ export const encryptedStream = async(
|
|||||||
|
|
||||||
let fileLength = 0
|
let fileLength = 0
|
||||||
const aes = Crypto.createCipheriv('aes-256-cbc', cipherKey, iv)
|
const aes = Crypto.createCipheriv('aes-256-cbc', cipherKey, iv)
|
||||||
let hmac = Crypto.createHmac('sha256', macKey).update(iv)
|
let hmac = Crypto.createHmac('sha256', macKey!).update(iv)
|
||||||
let sha256Plain = Crypto.createHash('sha256')
|
let sha256Plain = Crypto.createHash('sha256')
|
||||||
let sha256Enc = Crypto.createHash('sha256')
|
let sha256Enc = Crypto.createHash('sha256')
|
||||||
|
|
||||||
@@ -323,7 +327,7 @@ export const encryptedStream = async(
|
|||||||
}
|
}
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
encWriteStream.destroy(error)
|
encWriteStream.destroy(error)
|
||||||
writeStream.destroy(error)
|
writeStream?.destroy(error)
|
||||||
aes.destroy(error)
|
aes.destroy(error)
|
||||||
hmac.destroy(error)
|
hmac.destroy(error)
|
||||||
sha256Plain.destroy(error)
|
sha256Plain.destroy(error)
|
||||||
@@ -353,7 +357,7 @@ export const downloadContentFromMessage = (
|
|||||||
type: MediaType,
|
type: MediaType,
|
||||||
opts: MediaDownloadOptions = { }
|
opts: MediaDownloadOptions = { }
|
||||||
) => {
|
) => {
|
||||||
const downloadUrl = url || getUrlFromDirectPath(directPath)
|
const downloadUrl = url || getUrlFromDirectPath(directPath!)
|
||||||
const keys = getMediaKeys(mediaKey, type)
|
const keys = getMediaKeys(mediaKey, type)
|
||||||
|
|
||||||
return downloadEncryptedContent(downloadUrl, keys, opts)
|
return downloadEncryptedContent(downloadUrl, keys, opts)
|
||||||
@@ -410,8 +414,8 @@ export const downloadEncryptedContent = async(
|
|||||||
|
|
||||||
const pushBytes = (bytes: Buffer, push: (bytes: Buffer) => void) => {
|
const pushBytes = (bytes: Buffer, push: (bytes: Buffer) => void) => {
|
||||||
if(startByte || endByte) {
|
if(startByte || endByte) {
|
||||||
const start = bytesFetched >= startByte ? undefined : Math.max(startByte - bytesFetched, 0)
|
const start = bytesFetched >= startByte! ? undefined : Math.max(startByte! - bytesFetched, 0)
|
||||||
const end = bytesFetched + bytes.length < endByte ? undefined : Math.max(endByte - bytesFetched, 0)
|
const end = bytesFetched + bytes.length < endByte! ? undefined : Math.max(endByte! - bytesFetched, 0)
|
||||||
|
|
||||||
push(bytes.slice(start, end))
|
push(bytes.slice(start, end))
|
||||||
|
|
||||||
@@ -486,13 +490,13 @@ export function extensionForMediaMessage(message: WAMessageContent) {
|
|||||||
return extension
|
return extension
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger }: CommonSocketConfig<any>, refreshMediaConn: (force: boolean) => Promise<MediaConnInfo>): WAMediaUploadFunction => {
|
export const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger }: CommonSocketConfig, refreshMediaConn: (force: boolean) => Promise<MediaConnInfo>): WAMediaUploadFunction => {
|
||||||
return async(stream, { mediaType, fileEncSha256B64, timeoutMs }) => {
|
return async(stream, { mediaType, fileEncSha256B64, timeoutMs }) => {
|
||||||
const { default: axios } = await import('axios')
|
const { default: axios } = await import('axios')
|
||||||
// send a query JSON to obtain the url & auth token to upload our media
|
// send a query JSON to obtain the url & auth token to upload our media
|
||||||
let uploadInfo = await refreshMediaConn(false)
|
let uploadInfo = await refreshMediaConn(false)
|
||||||
|
|
||||||
let urls: { mediaUrl: string, directPath: string }
|
let urls: { mediaUrl: string, directPath: string } | undefined
|
||||||
const hosts = [ ...customUploadHosts, ...uploadInfo.hosts ]
|
const hosts = [ ...customUploadHosts, ...uploadInfo.hosts ]
|
||||||
|
|
||||||
const chunks: Buffer[] = []
|
const chunks: Buffer[] = []
|
||||||
@@ -500,7 +504,7 @@ export const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger }: C
|
|||||||
chunks.push(chunk)
|
chunks.push(chunk)
|
||||||
}
|
}
|
||||||
|
|
||||||
let reqBody = Buffer.concat(chunks)
|
const reqBody = Buffer.concat(chunks)
|
||||||
|
|
||||||
for(const { hostname, maxContentLengthBytes } of hosts) {
|
for(const { hostname, maxContentLengthBytes } of hosts) {
|
||||||
logger.debug(`uploading to "${hostname}"`)
|
logger.debug(`uploading to "${hostname}"`)
|
||||||
@@ -550,9 +554,6 @@ export const getWAUploadToServer = ({ customUploadHosts, fetchAgent, logger }: C
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear buffer just to be sure we're releasing the memory
|
|
||||||
reqBody = undefined
|
|
||||||
|
|
||||||
if(!urls) {
|
if(!urls) {
|
||||||
throw new Boom(
|
throw new Boom(
|
||||||
'Media upload failed on all hosts',
|
'Media upload failed on all hosts',
|
||||||
@@ -583,12 +584,12 @@ export const encryptMediaRetryRequest = (
|
|||||||
|
|
||||||
const iv = Crypto.randomBytes(12)
|
const iv = Crypto.randomBytes(12)
|
||||||
const retryKey = getMediaRetryKey(mediaKey)
|
const retryKey = getMediaRetryKey(mediaKey)
|
||||||
const ciphertext = aesEncryptGCM(recpBuffer, retryKey, iv, Buffer.from(key.id))
|
const ciphertext = aesEncryptGCM(recpBuffer, retryKey, iv, Buffer.from(key.id!))
|
||||||
|
|
||||||
const req: BinaryNode = {
|
const req: BinaryNode = {
|
||||||
tag: 'receipt',
|
tag: 'receipt',
|
||||||
attrs: {
|
attrs: {
|
||||||
id: key.id,
|
id: key.id!,
|
||||||
to: jidNormalizedUser(meId),
|
to: jidNormalizedUser(meId),
|
||||||
type: 'server-error'
|
type: 'server-error'
|
||||||
},
|
},
|
||||||
@@ -607,8 +608,9 @@ export const encryptMediaRetryRequest = (
|
|||||||
{
|
{
|
||||||
tag: 'rmr',
|
tag: 'rmr',
|
||||||
attrs: {
|
attrs: {
|
||||||
jid: key.remoteJid,
|
jid: key.remoteJid!,
|
||||||
from_me: (!!key.fromMe).toString(),
|
from_me: (!!key.fromMe).toString(),
|
||||||
|
// @ts-ignore
|
||||||
participant: key.participant || undefined
|
participant: key.participant || undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -619,7 +621,7 @@ export const encryptMediaRetryRequest = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const decodeMediaRetryNode = (node: BinaryNode) => {
|
export const decodeMediaRetryNode = (node: BinaryNode) => {
|
||||||
const rmrNode = getBinaryNodeChild(node, 'rmr')
|
const rmrNode = getBinaryNodeChild(node, 'rmr')!
|
||||||
|
|
||||||
const event: BaileysEventMap<any>['messages.media-update'][number] = {
|
const event: BaileysEventMap<any>['messages.media-update'][number] = {
|
||||||
key: {
|
key: {
|
||||||
|
|||||||
@@ -75,13 +75,17 @@ export const prepareWAMessageMedia = async(
|
|||||||
) => {
|
) => {
|
||||||
const logger = options.logger
|
const logger = options.logger
|
||||||
|
|
||||||
let mediaType: typeof MEDIA_KEYS[number]
|
let mediaType: typeof MEDIA_KEYS[number] | undefined
|
||||||
for(const key of MEDIA_KEYS) {
|
for(const key of MEDIA_KEYS) {
|
||||||
if(key in message) {
|
if(key in message) {
|
||||||
mediaType = key
|
mediaType = key
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!mediaType) {
|
||||||
|
throw new Boom('Invalid media type', { statusCode: 400 })
|
||||||
|
}
|
||||||
|
|
||||||
const uploadData: MediaUploadData = {
|
const uploadData: MediaUploadData = {
|
||||||
...message,
|
...message,
|
||||||
media: message[mediaType]
|
media: message[mediaType]
|
||||||
@@ -106,15 +110,14 @@ export const prepareWAMessageMedia = async(
|
|||||||
|
|
||||||
// check for cache hit
|
// check for cache hit
|
||||||
if(cacheableKey) {
|
if(cacheableKey) {
|
||||||
const mediaBuff: Buffer = options.mediaCache!.get(cacheableKey)
|
const mediaBuff = options.mediaCache!.get<Buffer>(cacheableKey)
|
||||||
if(mediaBuff) {
|
if(mediaBuff) {
|
||||||
logger?.debug({ cacheableKey }, 'got media cache hit')
|
logger?.debug({ cacheableKey }, 'got media cache hit')
|
||||||
|
|
||||||
const obj = WAProto.Message.decode(mediaBuff)
|
const obj = WAProto.Message.decode(mediaBuff)
|
||||||
const key = `${mediaType}Message`
|
const key = `${mediaType}Message`
|
||||||
|
|
||||||
delete uploadData.media
|
Object.assign(obj[key], { ...uploadData, media: undefined })
|
||||||
Object.assign(obj[key], { ...uploadData })
|
|
||||||
|
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
@@ -153,12 +156,12 @@ export const prepareWAMessageMedia = async(
|
|||||||
(async() => {
|
(async() => {
|
||||||
try {
|
try {
|
||||||
if(requiresThumbnailComputation) {
|
if(requiresThumbnailComputation) {
|
||||||
uploadData.jpegThumbnail = await generateThumbnail(bodyPath, mediaType as any, options)
|
uploadData.jpegThumbnail = await generateThumbnail(bodyPath!, mediaType as any, options)
|
||||||
logger?.debug('generated thumbnail')
|
logger?.debug('generated thumbnail')
|
||||||
}
|
}
|
||||||
|
|
||||||
if(requiresDurationComputation) {
|
if(requiresDurationComputation) {
|
||||||
uploadData.seconds = await getAudioDuration(bodyPath)
|
uploadData.seconds = await getAudioDuration(bodyPath!)
|
||||||
logger?.debug('computed audio duration')
|
logger?.debug('computed audio duration')
|
||||||
}
|
}
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
@@ -177,8 +180,6 @@ export const prepareWAMessageMedia = async(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
delete uploadData.media
|
|
||||||
|
|
||||||
const obj = WAProto.Message.fromObject({
|
const obj = WAProto.Message.fromObject({
|
||||||
[`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject(
|
[`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject(
|
||||||
{
|
{
|
||||||
@@ -189,13 +190,14 @@ export const prepareWAMessageMedia = async(
|
|||||||
fileSha256,
|
fileSha256,
|
||||||
fileLength,
|
fileLength,
|
||||||
mediaKeyTimestamp: unixTimestampSeconds(),
|
mediaKeyTimestamp: unixTimestampSeconds(),
|
||||||
...uploadData
|
...uploadData,
|
||||||
|
media: undefined
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
if(cacheableKey) {
|
if(cacheableKey) {
|
||||||
logger.debug({ cacheableKey }, 'set cache')
|
logger?.debug({ cacheableKey }, 'set cache')
|
||||||
options.mediaCache!.set(cacheableKey, WAProto.Message.encode(obj).finish())
|
options.mediaCache!.set(cacheableKey, WAProto.Message.encode(obj).finish())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,8 +234,8 @@ export const generateForwardMessageContent = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// hacky copy
|
// hacky copy
|
||||||
content = normalizeMessageContent(message.message)
|
content = normalizeMessageContent(content)
|
||||||
content = proto.Message.decode(proto.Message.encode(content).finish())
|
content = proto.Message.decode(proto.Message.encode(content!).finish())
|
||||||
|
|
||||||
let key = Object.keys(content)[0] as MessageType
|
let key = Object.keys(content)[0] as MessageType
|
||||||
|
|
||||||
@@ -428,8 +430,8 @@ export const generateWAMessageFromContent = (
|
|||||||
if(quoted) {
|
if(quoted) {
|
||||||
const participant = quoted.key.fromMe ? userJid : (quoted.participant || quoted.key.participant || quoted.key.remoteJid)
|
const participant = quoted.key.fromMe ? userJid : (quoted.participant || quoted.key.participant || quoted.key.remoteJid)
|
||||||
|
|
||||||
let quotedMsg = normalizeMessageContent(quoted.message)
|
let quotedMsg = normalizeMessageContent(quoted.message)!
|
||||||
const msgType = getContentType(quotedMsg)
|
const msgType = getContentType(quotedMsg)!
|
||||||
// strip any redundant properties
|
// strip any redundant properties
|
||||||
quotedMsg = proto.Message.fromObject({ [msgType]: quotedMsg[msgType] })
|
quotedMsg = proto.Message.fromObject({ [msgType]: quotedMsg[msgType] })
|
||||||
|
|
||||||
@@ -439,7 +441,7 @@ export const generateWAMessageFromContent = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
const contextInfo: proto.IContextInfo = message[key].contextInfo || { }
|
const contextInfo: proto.IContextInfo = message[key].contextInfo || { }
|
||||||
contextInfo.participant = jidNormalizedUser(participant)
|
contextInfo.participant = jidNormalizedUser(participant!)
|
||||||
contextInfo.stanzaId = quoted.key.id
|
contextInfo.stanzaId = quoted.key.id
|
||||||
contextInfo.quotedMessage = quotedMsg
|
contextInfo.quotedMessage = quotedMsg
|
||||||
|
|
||||||
@@ -521,7 +523,7 @@ export const getContentType = (content: WAProto.IMessage | undefined) => {
|
|||||||
* @param content
|
* @param content
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const normalizeMessageContent = (content: WAMessageContent | undefined): WAMessageContent => {
|
export const normalizeMessageContent = (content: WAMessageContent | null | undefined): WAMessageContent | undefined => {
|
||||||
content = content?.ephemeralMessage?.message?.viewOnceMessage?.message ||
|
content = content?.ephemeralMessage?.message?.viewOnceMessage?.message ||
|
||||||
content?.ephemeralMessage?.message ||
|
content?.ephemeralMessage?.message ||
|
||||||
content?.viewOnceMessage?.message ||
|
content?.viewOnceMessage?.message ||
|
||||||
@@ -614,13 +616,13 @@ export const aggregateMessageKeysNotFromMe = (keys: proto.IMessageKey[]) => {
|
|||||||
const uqKey = `${remoteJid}:${participant || ''}`
|
const uqKey = `${remoteJid}:${participant || ''}`
|
||||||
if(!keyMap[uqKey]) {
|
if(!keyMap[uqKey]) {
|
||||||
keyMap[uqKey] = {
|
keyMap[uqKey] = {
|
||||||
jid: remoteJid,
|
jid: remoteJid!,
|
||||||
participant,
|
participant: participant!,
|
||||||
messageIds: []
|
messageIds: []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
keyMap[uqKey].messageIds.push(id)
|
keyMap[uqKey].messageIds.push(id!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -650,7 +652,7 @@ export const downloadMediaMessage = async(
|
|||||||
if(ctx) {
|
if(ctx) {
|
||||||
if(axios.isAxiosError(error)) {
|
if(axios.isAxiosError(error)) {
|
||||||
// check if the message requires a reupload
|
// check if the message requires a reupload
|
||||||
if(REUPLOAD_REQUIRED_STATUS.includes(error.response?.status)) {
|
if(REUPLOAD_REQUIRED_STATUS.includes(error.response?.status!)) {
|
||||||
ctx.logger.info({ key: message.key }, 'sending reupload media request...')
|
ctx.logger.info({ key: message.key }, 'sending reupload media request...')
|
||||||
// request reupload
|
// request reupload
|
||||||
message = await ctx.reuploadRequest(message)
|
message = await ctx.reuploadRequest(message)
|
||||||
@@ -670,9 +672,9 @@ export const downloadMediaMessage = async(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const contentType = getContentType(mContent)
|
const contentType = getContentType(mContent)
|
||||||
const mediaType = contentType.replace('Message', '') as MediaType
|
const mediaType = contentType?.replace('Message', '') as MediaType
|
||||||
const media = mContent[contentType]
|
const media = mContent[contentType!]
|
||||||
if(typeof media !== 'object' || !('url' in media)) {
|
if(!media || typeof media !== 'object' || !('url' in media)) {
|
||||||
throw new Boom(`"${contentType}" message is not a media message`)
|
throw new Boom(`"${contentType}" message is not a media message`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -691,7 +693,7 @@ export const downloadMediaMessage = async(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Checks whether the given message is a media message; if it is returns the inner content */
|
/** Checks whether the given message is a media message; if it is returns the inner content */
|
||||||
export const assertMediaContent = (content: proto.IMessage) => {
|
export const assertMediaContent = (content: proto.IMessage | null | undefined) => {
|
||||||
content = extractMessageContent(content)
|
content = extractMessageContent(content)
|
||||||
const mediaContent = content?.documentMessage
|
const mediaContent = content?.documentMessage
|
||||||
|| content?.imageMessage
|
|| content?.imageMessage
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ export const makeNoiseHandler = (
|
|||||||
finishInit,
|
finishInit,
|
||||||
processHandshake: ({ serverHello }: proto.HandshakeMessage, noiseKey: KeyPair) => {
|
processHandshake: ({ serverHello }: proto.HandshakeMessage, noiseKey: KeyPair) => {
|
||||||
authenticate(serverHello!.ephemeral!)
|
authenticate(serverHello!.ephemeral!)
|
||||||
mixIntoKey(Curve.sharedKey(privateKey, serverHello.ephemeral!))
|
mixIntoKey(Curve.sharedKey(privateKey, serverHello!.ephemeral!))
|
||||||
|
|
||||||
const decStaticContent = decrypt(serverHello!.static!)
|
const decStaticContent = decrypt(serverHello!.static!)
|
||||||
mixIntoKey(Curve.sharedKey(privateKey, decStaticContent))
|
mixIntoKey(Curve.sharedKey(privateKey, decStaticContent))
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export const isRealMessage = (message: proto.IWebMessageInfo) => {
|
|||||||
const normalizedContent = normalizeMessageContent(message.message)
|
const normalizedContent = normalizeMessageContent(message.message)
|
||||||
return (
|
return (
|
||||||
!!normalizedContent
|
!!normalizedContent
|
||||||
|| MSG_MISSED_CALL_TYPES.has(message.messageStubType)
|
|| MSG_MISSED_CALL_TYPES.has(message.messageStubType!)
|
||||||
)
|
)
|
||||||
&& !normalizedContent?.protocolMessage
|
&& !normalizedContent?.protocolMessage
|
||||||
&& !normalizedContent?.reactionMessage
|
&& !normalizedContent?.reactionMessage
|
||||||
@@ -59,7 +59,7 @@ const processMessage = async(
|
|||||||
const meId = creds.me!.id
|
const meId = creds.me!.id
|
||||||
const { accountSettings } = creds
|
const { accountSettings } = creds
|
||||||
|
|
||||||
const chat: Partial<Chat> = { id: jidNormalizedUser(message.key.remoteJid) }
|
const chat: Partial<Chat> = { id: jidNormalizedUser(message.key.remoteJid!) }
|
||||||
|
|
||||||
if(isRealMessage(message)) {
|
if(isRealMessage(message)) {
|
||||||
chat.conversationTimestamp = toNumber(message.messageTimestamp)
|
chat.conversationTimestamp = toNumber(message.messageTimestamp)
|
||||||
@@ -79,7 +79,7 @@ const processMessage = async(
|
|||||||
if(protocolMsg) {
|
if(protocolMsg) {
|
||||||
switch (protocolMsg.type) {
|
switch (protocolMsg.type) {
|
||||||
case proto.ProtocolMessage.ProtocolMessageType.HISTORY_SYNC_NOTIFICATION:
|
case proto.ProtocolMessage.ProtocolMessageType.HISTORY_SYNC_NOTIFICATION:
|
||||||
const histNotification = protocolMsg!.historySyncNotification
|
const histNotification = protocolMsg!.historySyncNotification!
|
||||||
|
|
||||||
logger?.info({ histNotification, id: message.key.id }, 'got history notification')
|
logger?.info({ histNotification, id: message.key.id }, 'got history notification')
|
||||||
|
|
||||||
@@ -117,10 +117,10 @@ const processMessage = async(
|
|||||||
await keyStore.transaction(
|
await keyStore.transaction(
|
||||||
async() => {
|
async() => {
|
||||||
for(const { keyData, keyId } of keys) {
|
for(const { keyData, keyId } of keys) {
|
||||||
const strKeyId = Buffer.from(keyId.keyId!).toString('base64')
|
const strKeyId = Buffer.from(keyId!.keyId!).toString('base64')
|
||||||
|
|
||||||
logger?.info({ strKeyId }, 'injecting new app state sync key')
|
logger?.info({ strKeyId }, 'injecting new app state sync key')
|
||||||
await keyStore.set({ 'app-state-sync-key': { [strKeyId]: keyData } })
|
await keyStore.set({ 'app-state-sync-key': { [strKeyId]: keyData! } })
|
||||||
|
|
||||||
newAppStateSyncKeyId = strKeyId
|
newAppStateSyncKeyId = strKeyId
|
||||||
}
|
}
|
||||||
@@ -176,7 +176,7 @@ const processMessage = async(
|
|||||||
switch (message.messageStubType) {
|
switch (message.messageStubType) {
|
||||||
case WAMessageStubType.GROUP_PARTICIPANT_LEAVE:
|
case WAMessageStubType.GROUP_PARTICIPANT_LEAVE:
|
||||||
case WAMessageStubType.GROUP_PARTICIPANT_REMOVE:
|
case WAMessageStubType.GROUP_PARTICIPANT_REMOVE:
|
||||||
participants = message.messageStubParameters
|
participants = message.messageStubParameters || []
|
||||||
emitParticipantsUpdate('remove')
|
emitParticipantsUpdate('remove')
|
||||||
// mark the chat read only if you left the group
|
// mark the chat read only if you left the group
|
||||||
if(participantsIncludesMe()) {
|
if(participantsIncludesMe()) {
|
||||||
@@ -187,7 +187,7 @@ const processMessage = async(
|
|||||||
case WAMessageStubType.GROUP_PARTICIPANT_ADD:
|
case WAMessageStubType.GROUP_PARTICIPANT_ADD:
|
||||||
case WAMessageStubType.GROUP_PARTICIPANT_INVITE:
|
case WAMessageStubType.GROUP_PARTICIPANT_INVITE:
|
||||||
case WAMessageStubType.GROUP_PARTICIPANT_ADD_REQUEST_JOIN:
|
case WAMessageStubType.GROUP_PARTICIPANT_ADD_REQUEST_JOIN:
|
||||||
participants = message.messageStubParameters
|
participants = message.messageStubParameters || []
|
||||||
if(participantsIncludesMe()) {
|
if(participantsIncludesMe()) {
|
||||||
chat.readOnly = false
|
chat.readOnly = false
|
||||||
}
|
}
|
||||||
@@ -195,23 +195,23 @@ const processMessage = async(
|
|||||||
emitParticipantsUpdate('add')
|
emitParticipantsUpdate('add')
|
||||||
break
|
break
|
||||||
case WAMessageStubType.GROUP_PARTICIPANT_DEMOTE:
|
case WAMessageStubType.GROUP_PARTICIPANT_DEMOTE:
|
||||||
participants = message.messageStubParameters
|
participants = message.messageStubParameters || []
|
||||||
emitParticipantsUpdate('demote')
|
emitParticipantsUpdate('demote')
|
||||||
break
|
break
|
||||||
case WAMessageStubType.GROUP_PARTICIPANT_PROMOTE:
|
case WAMessageStubType.GROUP_PARTICIPANT_PROMOTE:
|
||||||
participants = message.messageStubParameters
|
participants = message.messageStubParameters || []
|
||||||
emitParticipantsUpdate('promote')
|
emitParticipantsUpdate('promote')
|
||||||
break
|
break
|
||||||
case WAMessageStubType.GROUP_CHANGE_ANNOUNCE:
|
case WAMessageStubType.GROUP_CHANGE_ANNOUNCE:
|
||||||
const announceValue = message.messageStubParameters[0]
|
const announceValue = message.messageStubParameters?.[0]
|
||||||
emitGroupUpdate({ announce: announceValue === 'true' || announceValue === 'on' })
|
emitGroupUpdate({ announce: announceValue === 'true' || announceValue === 'on' })
|
||||||
break
|
break
|
||||||
case WAMessageStubType.GROUP_CHANGE_RESTRICT:
|
case WAMessageStubType.GROUP_CHANGE_RESTRICT:
|
||||||
const restrictValue = message.messageStubParameters[0]
|
const restrictValue = message.messageStubParameters?.[0]
|
||||||
emitGroupUpdate({ restrict: restrictValue === 'true' || restrictValue === 'on' })
|
emitGroupUpdate({ restrict: restrictValue === 'true' || restrictValue === 'on' })
|
||||||
break
|
break
|
||||||
case WAMessageStubType.GROUP_CHANGE_SUBJECT:
|
case WAMessageStubType.GROUP_CHANGE_SUBJECT:
|
||||||
const name = message.messageStubParameters[0]
|
const name = message.messageStubParameters?.[0]
|
||||||
chat.name = name
|
chat.name = name
|
||||||
emitGroupUpdate({ subject: name })
|
emitGroupUpdate({ subject: name })
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ export const processSenderKeyMessage = async(
|
|||||||
auth: SignalAuthState
|
auth: SignalAuthState
|
||||||
) => {
|
) => {
|
||||||
const builder = new GroupSessionBuilder(signalStorage(auth))
|
const builder = new GroupSessionBuilder(signalStorage(auth))
|
||||||
const senderName = jidToSignalSenderKeyName(item.groupId, authorJid)
|
const senderName = jidToSignalSenderKeyName(item.groupId!, authorJid)
|
||||||
|
|
||||||
const senderMsg = new SenderKeyDistributionMessage(null, null, null, null, item.axolotlSenderKeyDistributionMessage)
|
const senderMsg = new SenderKeyDistributionMessage(null, null, null, null, item.axolotlSenderKeyDistributionMessage)
|
||||||
const { [senderName]: senderKey } = await auth.keys.get('sender-key', [senderName])
|
const { [senderName]: senderKey } = await auth.keys.get('sender-key', [senderName])
|
||||||
@@ -203,9 +203,7 @@ export const parseAndInjectE2ESessions = async(node: BinaryNode, auth: SignalAut
|
|||||||
const extractKey = (key: BinaryNode) => (
|
const extractKey = (key: BinaryNode) => (
|
||||||
key ? ({
|
key ? ({
|
||||||
keyId: getBinaryNodeChildUInt(key, 'id', 3),
|
keyId: getBinaryNodeChildUInt(key, 'id', 3),
|
||||||
publicKey: generateSignalPubKey(
|
publicKey: generateSignalPubKey(getBinaryNodeChildBuffer(key, 'value')!),
|
||||||
getBinaryNodeChildBuffer(key, 'value')
|
|
||||||
),
|
|
||||||
signature: getBinaryNodeChildBuffer(key, 'signature'),
|
signature: getBinaryNodeChildBuffer(key, 'signature'),
|
||||||
}) : undefined
|
}) : undefined
|
||||||
)
|
)
|
||||||
@@ -217,9 +215,9 @@ export const parseAndInjectE2ESessions = async(node: BinaryNode, auth: SignalAut
|
|||||||
await Promise.all(
|
await Promise.all(
|
||||||
nodes.map(
|
nodes.map(
|
||||||
async node => {
|
async node => {
|
||||||
const signedKey = getBinaryNodeChild(node, 'skey')
|
const signedKey = getBinaryNodeChild(node, 'skey')!
|
||||||
const key = getBinaryNodeChild(node, 'key')
|
const key = getBinaryNodeChild(node, 'key')!
|
||||||
const identity = getBinaryNodeChildBuffer(node, 'identity')
|
const identity = getBinaryNodeChildBuffer(node, 'identity')!
|
||||||
const jid = node.attrs.jid
|
const jid = node.attrs.jid
|
||||||
const registrationId = getBinaryNodeChildUInt(node, 'registration', 4)
|
const registrationId = getBinaryNodeChildUInt(node, 'registration', 4)
|
||||||
|
|
||||||
@@ -237,13 +235,13 @@ export const parseAndInjectE2ESessions = async(node: BinaryNode, auth: SignalAut
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const extractDeviceJids = (result: BinaryNode, myJid: string, excludeZeroDevices: boolean) => {
|
export const extractDeviceJids = (result: BinaryNode, myJid: string, excludeZeroDevices: boolean) => {
|
||||||
const { user: myUser, device: myDevice } = jidDecode(myJid)
|
const { user: myUser, device: myDevice } = jidDecode(myJid)!
|
||||||
const extracted: JidWithDevice[] = []
|
const extracted: JidWithDevice[] = []
|
||||||
for(const node of result.content as BinaryNode[]) {
|
for(const node of result.content as BinaryNode[]) {
|
||||||
const list = getBinaryNodeChild(node, 'list')?.content
|
const list = getBinaryNodeChild(node, 'list')?.content
|
||||||
if(list && Array.isArray(list)) {
|
if(list && Array.isArray(list)) {
|
||||||
for(const item of list) {
|
for(const item of list) {
|
||||||
const { user } = jidDecode(item.attrs.jid)
|
const { user } = jidDecode(item.attrs.jid)!
|
||||||
const devicesNode = getBinaryNodeChild(item, 'devices')
|
const devicesNode = getBinaryNodeChild(item, 'devices')
|
||||||
const deviceListNode = getBinaryNodeChild(devicesNode, 'device-list')
|
const deviceListNode = getBinaryNodeChild(devicesNode, 'device-list')
|
||||||
if(Array.isArray(deviceListNode?.content)) {
|
if(Array.isArray(deviceListNode?.content)) {
|
||||||
|
|||||||
@@ -15,12 +15,12 @@ import { BufferJSON } from './generics'
|
|||||||
export const useMultiFileAuthState = async(folder: string): Promise<{ state: AuthenticationState, saveCreds: () => Promise<void> }> => {
|
export const useMultiFileAuthState = async(folder: string): Promise<{ state: AuthenticationState, saveCreds: () => Promise<void> }> => {
|
||||||
|
|
||||||
const writeData = (data: any, file: string) => {
|
const writeData = (data: any, file: string) => {
|
||||||
return writeFile(join(folder, fixFileName(file)), JSON.stringify(data, BufferJSON.replacer))
|
return writeFile(join(folder, fixFileName(file)!), JSON.stringify(data, BufferJSON.replacer))
|
||||||
}
|
}
|
||||||
|
|
||||||
const readData = async(file: string) => {
|
const readData = async(file: string) => {
|
||||||
try {
|
try {
|
||||||
const data = await readFile(join(folder, fixFileName(file)), { encoding: 'utf-8' })
|
const data = await readFile(join(folder, fixFileName(file)!), { encoding: 'utf-8' })
|
||||||
return JSON.parse(data, BufferJSON.reviver)
|
return JSON.parse(data, BufferJSON.reviver)
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
return null
|
return null
|
||||||
@@ -29,7 +29,7 @@ export const useMultiFileAuthState = async(folder: string): Promise<{ state: Aut
|
|||||||
|
|
||||||
const removeData = async(file: string) => {
|
const removeData = async(file: string) => {
|
||||||
try {
|
try {
|
||||||
await unlink(fixFileName(file))
|
await unlink(fixFileName(file)!)
|
||||||
} catch{
|
} catch{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ const getClientPayload = (config: ClientPayloadConfig): proto.IClientPayload =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const generateLoginNode = (userJid: string, config: ClientPayloadConfig): proto.IClientPayload => {
|
export const generateLoginNode = (userJid: string, config: ClientPayloadConfig): proto.IClientPayload => {
|
||||||
const { user, device } = jidDecode(userJid)
|
const { user, device } = jidDecode(userJid)!
|
||||||
const payload: proto.IClientPayload = {
|
const payload: proto.IClientPayload = {
|
||||||
...getClientPayload(config),
|
...getClientPayload(config),
|
||||||
passive: true,
|
passive: true,
|
||||||
@@ -137,7 +137,7 @@ export const configureSuccessfulPairing = (
|
|||||||
const deviceMsg = Buffer.concat([ Buffer.from([6, 1]), deviceDetails, signedIdentityKey.public, accountSignatureKey ])
|
const deviceMsg = Buffer.concat([ Buffer.from([6, 1]), deviceDetails, signedIdentityKey.public, accountSignatureKey ])
|
||||||
account.deviceSignature = Curve.sign(signedIdentityKey.private, deviceMsg)
|
account.deviceSignature = Curve.sign(signedIdentityKey.private, deviceMsg)
|
||||||
// do not provide the "accountSignatureKey" back
|
// do not provide the "accountSignatureKey" back
|
||||||
account.accountSignatureKey = null
|
account.accountSignatureKey = Buffer.alloc(0)
|
||||||
|
|
||||||
const identity = createSignalIdentity(jid, accountSignatureKey)
|
const identity = createSignalIdentity(jid, accountSignatureKey)
|
||||||
const accountEnc = proto.ADVSignedDeviceIdentity.encode(account).finish()
|
const accountEnc = proto.ADVSignedDeviceIdentity.encode(account).finish()
|
||||||
|
|||||||
@@ -201,5 +201,5 @@ export const SINGLE_BYTE_TOKENS = [
|
|||||||
export const TOKEN_MAP: { [token: string]: { dict?: number, index: number } } = { }
|
export const TOKEN_MAP: { [token: string]: { dict?: number, index: number } } = { }
|
||||||
|
|
||||||
for(let i = 0;i < SINGLE_BYTE_TOKENS.length;i++) {
|
for(let i = 0;i < SINGLE_BYTE_TOKENS.length;i++) {
|
||||||
TOKEN_MAP[SINGLE_BYTE_TOKENS[i]] = { index: i }
|
TOKEN_MAP[SINGLE_BYTE_TOKENS[i]!] = { index: i }
|
||||||
}
|
}
|
||||||
File diff suppressed because one or more lines are too long
@@ -153,7 +153,7 @@ export const decodeDecompressedBinaryNode = (
|
|||||||
|
|
||||||
const readString = (tag: number): string => {
|
const readString = (tag: number): string => {
|
||||||
if(tag >= 1 && tag < SINGLE_BYTE_TOKENS.length) {
|
if(tag >= 1 && tag < SINGLE_BYTE_TOKENS.length) {
|
||||||
return SINGLE_BYTE_TOKENS[tag]
|
return SINGLE_BYTE_TOKENS[tag] || ''
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
@@ -163,7 +163,7 @@ export const decodeDecompressedBinaryNode = (
|
|||||||
case TAGS.DICTIONARY_3:
|
case TAGS.DICTIONARY_3:
|
||||||
return getTokenDouble(tag - TAGS.DICTIONARY_0, readByte())
|
return getTokenDouble(tag - TAGS.DICTIONARY_0, readByte())
|
||||||
case TAGS.LIST_EMPTY:
|
case TAGS.LIST_EMPTY:
|
||||||
return null
|
return ''
|
||||||
case TAGS.BINARY_8:
|
case TAGS.BINARY_8:
|
||||||
return readStringFromChars(readByte())
|
return readStringFromChars(readByte())
|
||||||
case TAGS.BINARY_20:
|
case TAGS.BINARY_20:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
import * as constants from './constants'
|
import * as constants from './constants'
|
||||||
import { jidDecode } from './jid-utils'
|
import { FullJid, jidDecode } from './jid-utils'
|
||||||
import type { BinaryNode, BinaryNodeCodingOptions } from './types'
|
import type { BinaryNode, BinaryNodeCodingOptions } from './types'
|
||||||
|
|
||||||
export const encodeBinaryNode = (
|
export const encodeBinaryNode = (
|
||||||
@@ -52,7 +52,7 @@ export const encodeBinaryNode = (
|
|||||||
pushBytes(bytes)
|
pushBytes(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
const writeJid = ({ agent, device, user, server }: ReturnType<typeof jidDecode>) => {
|
const writeJid = ({ agent, device, user, server }: FullJid) => {
|
||||||
if(typeof agent !== 'undefined' || typeof device !== 'undefined') {
|
if(typeof agent !== 'undefined' || typeof device !== 'undefined') {
|
||||||
pushByte(TAGS.AD_JID)
|
pushByte(TAGS.AD_JID)
|
||||||
pushByte(agent || 0)
|
pushByte(agent || 0)
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import { BinaryNode } from './types'
|
|||||||
|
|
||||||
// some extra useful utilities
|
// some extra useful utilities
|
||||||
|
|
||||||
export const getBinaryNodeChildren = ({ content }: BinaryNode, childTag: string) => {
|
export const getBinaryNodeChildren = (node: BinaryNode | undefined, childTag: string) => {
|
||||||
if(Array.isArray(content)) {
|
if(Array.isArray(node?.content)) {
|
||||||
return content.filter(item => item.tag === childTag)
|
return node!.content.filter(item => item.tag === childTag)
|
||||||
}
|
}
|
||||||
|
|
||||||
return []
|
return []
|
||||||
@@ -20,20 +20,20 @@ export const getAllBinaryNodeChildren = ({ content }: BinaryNode) => {
|
|||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getBinaryNodeChild = ({ content }: BinaryNode, childTag: string) => {
|
export const getBinaryNodeChild = (node: BinaryNode | undefined, childTag: string) => {
|
||||||
if(Array.isArray(content)) {
|
if(Array.isArray(node?.content)) {
|
||||||
return content.find(item => item.tag === childTag)
|
return node?.content.find(item => item.tag === childTag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getBinaryNodeChildBuffer = (node: BinaryNode, childTag: string) => {
|
export const getBinaryNodeChildBuffer = (node: BinaryNode | undefined, childTag: string) => {
|
||||||
const child = getBinaryNodeChild(node, childTag)?.content
|
const child = getBinaryNodeChild(node, childTag)?.content
|
||||||
if(Buffer.isBuffer(child) || child instanceof Uint8Array) {
|
if(Buffer.isBuffer(child) || child instanceof Uint8Array) {
|
||||||
return child
|
return child
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getBinaryNodeChildString = (node: BinaryNode, childTag: string) => {
|
export const getBinaryNodeChildString = (node: BinaryNode | undefined, childTag: string) => {
|
||||||
const child = getBinaryNodeChild(node, childTag)?.content
|
const child = getBinaryNodeChild(node, childTag)?.content
|
||||||
if(Buffer.isBuffer(child) || child instanceof Uint8Array) {
|
if(Buffer.isBuffer(child) || child instanceof Uint8Array) {
|
||||||
return Buffer.from(child).toString('utf-8')
|
return Buffer.from(child).toString('utf-8')
|
||||||
|
|||||||
@@ -11,18 +11,23 @@ export type JidWithDevice = {
|
|||||||
device?: number
|
device?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type FullJid = JidWithDevice & {
|
||||||
|
server: JidServer | string
|
||||||
|
agent?: number
|
||||||
|
}
|
||||||
|
|
||||||
export const jidEncode = (user: string | number | null, server: JidServer, device?: number, agent?: number) => {
|
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) => {
|
export const jidDecode = (jid: string | undefined): FullJid | undefined => {
|
||||||
const sepIdx = typeof jid === 'string' ? jid.indexOf('@') : -1
|
const sepIdx = typeof jid === 'string' ? jid.indexOf('@') : -1
|
||||||
if(sepIdx < 0) {
|
if(sepIdx < 0) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
const server = jid.slice(sepIdx + 1)
|
const server = jid!.slice(sepIdx + 1)
|
||||||
const userCombined = jid.slice(0, sepIdx)
|
const userCombined = jid!.slice(0, sepIdx)
|
||||||
|
|
||||||
const [userAgent, device] = userCombined.split(':')
|
const [userAgent, device] = userCombined.split(':')
|
||||||
const [user, agent] = userAgent.split('_')
|
const [user, agent] = userAgent.split('_')
|
||||||
@@ -36,7 +41,7 @@ export const jidDecode = (jid: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** is the jid a user */
|
/** is the jid a user */
|
||||||
export const areJidsSameUser = (jid1: string, jid2: string) => (
|
export const areJidsSameUser = (jid1: string | undefined, jid2: string | undefined) => (
|
||||||
jidDecode(jid1)?.user === jidDecode(jid2)?.user
|
jidDecode(jid1)?.user === jidDecode(jid2)?.user
|
||||||
)
|
)
|
||||||
/** is the jid a user */
|
/** is the jid a user */
|
||||||
@@ -49,6 +54,6 @@ export const isJidGroup = (jid: string) => (jid?.endsWith('@g.us'))
|
|||||||
export const isJidStatusBroadcast = (jid: string) => jid === 'status@broadcast'
|
export const isJidStatusBroadcast = (jid: string) => jid === 'status@broadcast'
|
||||||
|
|
||||||
export const jidNormalizedUser = (jid: string) => {
|
export const jidNormalizedUser = (jid: string) => {
|
||||||
const { user, server } = jidDecode(jid)
|
const { user, server } = jidDecode(jid)!
|
||||||
return jidEncode(user, server === 'c.us' ? 's.whatsapp.net' : server as JidServer)
|
return jidEncode(user, server === 'c.us' ? 's.whatsapp.net' : server as JidServer)
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
"checkJs": false,
|
"checkJs": false,
|
||||||
"outDir": "lib",
|
"outDir": "lib",
|
||||||
"strict": false,
|
"strict": false,
|
||||||
|
"strictNullChecks": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"noImplicitThis": true,
|
"noImplicitThis": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
|
|||||||
Reference in New Issue
Block a user