refactor: update chat modifications to be uniform across MD + legacy

This commit is contained in:
Adhiraj Singh
2021-12-21 10:53:39 +05:30
parent 677f50baaa
commit c87d8b8129
5 changed files with 32 additions and 22 deletions

View File

@@ -179,7 +179,7 @@ export type BaileysEventMap = {
/** auth credentials updated -- some pre key state, device ID etc. */ /** auth credentials updated -- some pre key state, device ID etc. */
'creds.update': Partial<AuthenticationCreds> 'creds.update': Partial<AuthenticationCreds>
/** set chats (history sync), messages are reverse chronologically sorted */ /** set chats (history sync), messages are reverse chronologically sorted */
'chats.set': { chats: Chat[], messages: WAMessage[] } 'chats.set': { chats: Chat[], messages: WAMessage[], contacts: Contact[] }
/** upsert chats */ /** upsert chats */
'chats.upsert': Chat[] 'chats.upsert': Chat[]
/** update the given chats */ /** update the given chats */
@@ -495,7 +495,7 @@ WA uses an encrypted form of communication to send chat/app updates. This has be
- Archive a chat - Archive a chat
``` ts ``` ts
const lastMsgInChat = await getLastMessageInChat('123456@s.whatsapp.net') // implement this on your end const lastMsgInChat = await getLastMessageInChat('123456@s.whatsapp.net') // implement this on your end
await sock.chatModify({ archive: true }, '123456@s.whatsapp.net', [lastMsgInChat]) await sock.chatModify({ archive: true, lastMessages: [lastMsgInChat] }, '123456@s.whatsapp.net')
``` ```
- Mute/unmute a chat - Mute/unmute a chat
``` ts ``` ts
@@ -508,7 +508,7 @@ WA uses an encrypted form of communication to send chat/app updates. This has be
``` ts ``` ts
const lastMsgInChat = await getLastMessageInChat('123456@s.whatsapp.net') // implement this on your end const lastMsgInChat = await getLastMessageInChat('123456@s.whatsapp.net') // implement this on your end
// mark it unread // mark it unread
await sock.chatModify({ markRead: false }, '123456@s.whatsapp.net', [lastMsgInChat]) await sock.chatModify({ markRead: false, lastMessages: [lastMsgInChat] }, '123456@s.whatsapp.net')
``` ```
- Delete message for me - Delete message for me

View File

@@ -294,24 +294,30 @@ const makeChatsSocket = (config: LegacySocketConfig) => {
* Modify a given chat (archive, pin etc.) * Modify a given chat (archive, pin etc.)
* @param jid the ID of the person/group you are modifiying * @param jid the ID of the person/group you are modifiying
*/ */
chatModify: async( modification: ChatModification, jid: string, chatInfo: Pick<Chat, 'mute' | 'pin'>, index?: WAMessageKey) => { chatModify: async(modification: ChatModification, jid: string, chatInfo: Pick<Chat, 'mute' | 'pin'>, timestampNow?: number) => {
let chatAttrs: BinaryNode['attrs'] = { jid: jid } let chatAttrs: BinaryNode['attrs'] = { jid: jid }
let data: BinaryNode[] | undefined = undefined let data: BinaryNode[] | undefined = undefined
const stamp = unixTimestampSeconds()
timestampNow = timestampNow || unixTimestampSeconds()
if('archive' in modification) { if('archive' in modification) {
chatAttrs.type = modification.archive ? 'archive' : 'unarchive' chatAttrs.type = modification.archive ? 'archive' : 'unarchive'
const indexKey = modification.lastMessages[modification.lastMessages.length-1].key
if(indexKey) {
chatAttrs.index = indexKey.id
chatAttrs.owner = indexKey.fromMe ? 'true' : 'false'
}
} else if('pin' in modification) { } else if('pin' in modification) {
chatAttrs.type = 'pin' chatAttrs.type = 'pin'
if(modification.pin) { if(modification.pin) {
chatAttrs.pin = stamp.toString() chatAttrs.pin = timestampNow.toString()
} else { } else {
chatAttrs.previous = chatInfo.pin!.toString() chatAttrs.previous = chatInfo.pin!.toString()
} }
} else if('mute' in modification) { } else if('mute' in modification) {
chatAttrs.type = 'mute' chatAttrs.type = 'mute'
if(modification.mute) { if(modification.mute) {
chatAttrs.mute = (stamp + modification.mute).toString() chatAttrs.mute = (timestampNow + modification.mute).toString()
} else { } else {
chatAttrs.previous = chatInfo.mute!.toString() chatAttrs.previous = chatInfo.mute!.toString()
} }
@@ -335,12 +341,8 @@ const makeChatsSocket = (config: LegacySocketConfig) => {
} }
)) ))
} else if('markRead' in modification) { } else if('markRead' in modification) {
return chatRead(index!, modification.markRead ? 0 : -1) const indexKey = modification.lastMessages[modification.lastMessages.length-1].key
} return chatRead(indexKey, modification.markRead ? 0 : -1)
if(index) {
chatAttrs.index = index.id
chatAttrs.owner = index.fromMe ? 'true' : 'false'
} }
const node = { tag: 'chat', attrs: chatAttrs, content: data } const node = { tag: 'chat', attrs: chatAttrs, content: data }

View File

@@ -541,8 +541,8 @@ export const makeChatsSocket = (config: SocketConfig) => {
* lastMessages must be sorted in reverse chronologically * lastMessages must be sorted in reverse chronologically
* requires the last messages till the last message received; required for archive & unread * requires the last messages till the last message received; required for archive & unread
*/ */
const chatModify = (mod: ChatModification, jid: string, lastMessages: Pick<proto.IWebMessageInfo, 'key' | 'messageTimestamp'>[]) => { const chatModify = (mod: ChatModification, jid: string) => {
const patch = chatModificationToAppPatch(mod, jid, lastMessages) const patch = chatModificationToAppPatch(mod, jid)
return appPatch(patch) return appPatch(patch)
} }

View File

@@ -27,9 +27,17 @@ export type Chat = Omit<proto.IConversation, 'messages'> & {
pin?: number | null pin?: number | null
archive?: boolean archive?: boolean
} }
/**
* the last messages in a chat, sorted reverse-chronologically
* for MD modifications, the last message in the array must be the last message recv in the chat
* */
export type LastMessageList = Pick<proto.IWebMessageInfo, 'key' | 'messageTimestamp'>[]
export type ChatModification = export type ChatModification =
{ archive: boolean } | {
archive: boolean
lastMessages: LastMessageList
} |
{ {
pin: boolean pin: boolean
} | } |
@@ -48,5 +56,6 @@ export type ChatModification =
} | } |
{ {
markRead: boolean markRead: boolean
lastMessages: LastMessageList
} | } |
{ delete: true } { delete: true }

View File

@@ -1,6 +1,6 @@
import { Boom } from '@hapi/boom' import { Boom } from '@hapi/boom'
import { aesDecrypt, hmacSign, aesEncrypt, hkdf } from "./crypto" import { aesDecrypt, hmacSign, aesEncrypt, hkdf } from "./crypto"
import { WAPatchCreate, ChatMutation, WAPatchName, LTHashState, ChatModification, SignalKeyStore } from "../Types" import { WAPatchCreate, ChatMutation, WAPatchName, LTHashState, ChatModification, LastMessageList } from "../Types"
import { proto } from '../../WAProto' import { proto } from '../../WAProto'
import { LT_HASH_ANTI_TAMPERING } from './lt-hash' import { LT_HASH_ANTI_TAMPERING } from './lt-hash'
import { BinaryNode, getBinaryNodeChild, getBinaryNodeChildren } from '../WABinary' import { BinaryNode, getBinaryNodeChild, getBinaryNodeChildren } from '../WABinary'
@@ -418,11 +418,10 @@ export const decodePatches = async(
export const chatModificationToAppPatch = ( export const chatModificationToAppPatch = (
mod: ChatModification, mod: ChatModification,
jid: string, jid: string
lastMessages: Pick<proto.IWebMessageInfo, 'key' | 'messageTimestamp'>[]
) => { ) => {
const OP = proto.SyncdMutation.SyncdMutationSyncdOperation const OP = proto.SyncdMutation.SyncdMutationSyncdOperation
const getMessageRange = () => { const getMessageRange = (lastMessages: LastMessageList) => {
if(!lastMessages?.length) { if(!lastMessages?.length) {
throw new Boom('Expected last message to be not from me', { statusCode: 400 }) throw new Boom('Expected last message to be not from me', { statusCode: 400 })
} }
@@ -455,7 +454,7 @@ export const chatModificationToAppPatch = (
syncAction: { syncAction: {
archiveChatAction: { archiveChatAction: {
archived: !!mod.archive, archived: !!mod.archive,
messageRange: getMessageRange() messageRange: getMessageRange(mod.lastMessages)
} }
}, },
index: ['archive', jid], index: ['archive', jid],
@@ -468,7 +467,7 @@ export const chatModificationToAppPatch = (
syncAction: { syncAction: {
markChatAsReadAction: { markChatAsReadAction: {
read: mod.markRead, read: mod.markRead,
messageRange: getMessageRange() messageRange: getMessageRange(mod.lastMessages)
} }
}, },
index: ['markChatAsRead', jid], index: ['markChatAsRead', jid],