Skip to content

Commit

Permalink
Merge branch 'WhiskeySockets:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
edupoli authored Jan 11, 2024
2 parents d524637 + a60cdfb commit 8df8362
Show file tree
Hide file tree
Showing 20 changed files with 166 additions and 142 deletions.
1 change: 1 addition & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
github: [purpshell, auties00, edgardmessias]
112 changes: 20 additions & 92 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -376,65 +376,6 @@ const sentMsg = await sock.sendMessage(
}
)
// send a buttons message!
const buttons = [
{buttonId: 'id1', buttonText: {displayText: 'Button 1'}, type: 1},
{buttonId: 'id2', buttonText: {displayText: 'Button 2'}, type: 1},
{buttonId: 'id3', buttonText: {displayText: 'Button 3'}, type: 1}
]
const buttonMessage = {
text: "Hi it's button message",
footer: 'Hello World',
buttons: buttons,
headerType: 1
}
const sendMsg = await sock.sendMessage(id, buttonMessage)
//send a template message!
const templateButtons = [
{index: 1, urlButton: {displayText: '⭐ Star Baileys on GitHub!', url: 'https://github.com/adiwajshing/Baileys'}},
{index: 2, callButton: {displayText: 'Call me!', phoneNumber: '+1 (234) 5678-901'}},
{index: 3, quickReplyButton: {displayText: 'This is a reply, just like normal buttons!', id: 'id-like-buttons-message'}},
]
const templateMessage = {
text: "Hi it's a template message",
footer: 'Hello World',
templateButtons: templateButtons
}
const sendMsg = await sock.sendMessage(id, templateMessage)
// send a list message!
const sections = [
{
title: "Section 1",
rows: [
{title: "Option 1", rowId: "option1"},
{title: "Option 2", rowId: "option2", description: "This is a description"}
]
},
{
title: "Section 2",
rows: [
{title: "Option 3", rowId: "option3"},
{title: "Option 4", rowId: "option4", description: "This is a description V2"}
]
},
]
const listMessage = {
text: "This is a list",
footer: "nice footer, link: https://google.com",
title: "Amazing boldfaced list title",
buttonText: "Required, text on the button to view the list",
sections
}
const sendMsg = await sock.sendMessage(id, listMessage)
const reactionMessage = {
react: {
text: "💖", // use an empty string to remove the reaction
Expand Down Expand Up @@ -489,39 +430,6 @@ await sock.sendMessage(
{ audio: { url: "./Media/audio.mp3" }, mimetype: 'audio/mp4' }
{ url: "Media/audio.mp3" }, // can send mp3, mp4, & ogg
)

// send a buttons message with image header!
const buttons = [
{buttonId: 'id1', buttonText: {displayText: 'Button 1'}, type: 1},
{buttonId: 'id2', buttonText: {displayText: 'Button 2'}, type: 1},
{buttonId: 'id3', buttonText: {displayText: 'Button 3'}, type: 1}
]

const buttonMessage = {
image: {url: 'https://example.com/image.jpeg'},
caption: "Hi it's button message",
footer: 'Hello World',
buttons: buttons,
headerType: 4
}

const sendMsg = await sock.sendMessage(id, buttonMessage)

//send a template message with an image **attached**!
const templateButtons = [
{index: 1, urlButton: {displayText: '⭐ Star Baileys on GitHub!', url: 'https://github.com/adiwajshing/Baileys'}},
{index: 2, callButton: {displayText: 'Call me!', phoneNumber: '+1 (234) 5678-901'}},
{index: 3, quickReplyButton: {displayText: 'This is a reply, just like normal buttons!', id: 'id-like-buttons-message'}},
]

const buttonMessage = {
text: "Hi it's a template message",
footer: 'Hello World',
templateButtons: templateButtons,
image: {url: 'https://example.com/image.jpeg'}
}

const sendMsg = await sock.sendMessage(id, templateMessage)
```

### Notes
Expand Down Expand Up @@ -648,6 +556,17 @@ await sock.sendMessage(jid, { delete: response.key })

**Note:** deleting for oneself is supported via `chatModify` (next section)

## Updating Messages

``` ts
const jid = '1234@s.whatsapp.net'
await sock.sendMessage(jid, {
text: 'updated text goes here',
edit: response.key,
});
```

## Modifying Chats

WA uses an encrypted form of communication to send chat/app updates. This has been implemented mostly and you can send the following updates:
Expand Down Expand Up @@ -698,6 +617,15 @@ WA uses an encrypted form of communication to send chat/app updates. This has be
},
'123456@s.whatsapp.net')
```

- Star/unstar a message
``` ts
await sock.chatModify({
star: {
messages: [{ id: 'messageID', fromMe: true // or `false` }],
star: true // - true: Star Message; false: Unstar Message
}},'123456@s.whatsapp.net');
```

**Note:** if you mess up one of your updates, WA can log you out of all your devices and you'll have to log in again.

Expand Down
15 changes: 14 additions & 1 deletion src/Socket/chats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -777,6 +777,18 @@ export const makeChatsSocket = (config: SocketConfig) => {
return appPatch(patch)
}

/**
* Star or Unstar a message
*/
const star = (jid: string, messages: { id: string, fromMe?: boolean }[], star: boolean) => {
return chatModify({
star: {
messages,
star
}
}, jid)
}

/**
* Adds label for the chats
*/
Expand Down Expand Up @@ -999,6 +1011,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
addChatLabel,
removeChatLabel,
addMessageLabel,
removeMessageLabel
removeMessageLabel,
star
}
}
2 changes: 1 addition & 1 deletion src/Socket/groups.ts
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ export const extractGroupMetadata = (result: BinaryNode) => {

const groupId = group.attrs.id.includes('@') ? group.attrs.id : jidEncode(group.attrs.id, 'g.us')
const eph = getBinaryNodeChild(group, 'ephemeral')?.attrs.expiration
const memberAddMode = getBinaryNodeChildString(group, 'member_add_mode') == "all_member_add"
const memberAddMode = getBinaryNodeChildString(group, 'member_add_mode') === 'all_member_add'
const metadata: GroupMetadata = {
id: groupId,
subject: group.attrs.subject,
Expand Down
25 changes: 17 additions & 8 deletions src/Socket/messages-recv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -392,16 +392,15 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
},
}
})
} else if (child.tag === 'blocklist') {
} else if(child.tag === 'blocklist') {
const blocklists = getBinaryNodeChildren(child, 'item')

for(const { attrs } of blocklists) {
const blocklist = [attrs.jid]
const type = (attrs.action === 'block') ? 'add' : 'remove'

ev.emit('blocklist.update', { blocklist, type })
const blocklist = [attrs.jid]
const type = (attrs.action === 'block') ? 'add' : 'remove'
ev.emit('blocklist.update', { blocklist, type })
}
}
}

break
case 'link_code_companion_reg':
Expand Down Expand Up @@ -541,7 +540,8 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {

const handleReceipt = async(node: BinaryNode) => {
const { attrs, content } = node
const isNodeFromMe = areJidsSameUser(attrs.participant || attrs.from, authState.creds.me?.id)
const isLid = attrs.from.includes('lid')
const isNodeFromMe = areJidsSameUser(attrs.participant || attrs.from, isLid ? authState.creds.me?.lid : authState.creds.me?.id)
const remoteJid = !isNodeFromMe || isJidGroup(attrs.from) ? attrs.from : attrs.recipient
const fromMe = !attrs.recipient || (attrs.type === 'retry' && isNodeFromMe)

Expand Down Expand Up @@ -664,9 +664,17 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
const { fullMessage: msg, category, author, decrypt } = decryptMessageNode(
node,
authState.creds.me!.id,
authState.creds.me!.lid || '',
signalRepository,
logger,
)

if(msg.message?.protocolMessage?.type === proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER) {
if(node.attrs.sender_pn) {
ev.emit('chats.phoneNumberShare', { lid: node.attrs.from, jid: node.attrs.sender_pn })
}
}

if(shouldIgnoreJid(msg.key.remoteJid!)) {
logger.debug({ key: msg.key }, 'ignored message')
await sendMessageAck(node)
Expand Down Expand Up @@ -744,7 +752,8 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {

if(status === 'offer') {
call.isVideo = !!getBinaryNodeChild(infoChild, 'video')
call.isGroup = infoChild.attrs.type === 'group'
call.isGroup = infoChild.attrs.type === 'group' || !!infoChild.attrs['group-jid']
call.groupJid = infoChild.attrs['group-jid']
callOfferCache.set(call.id, call)
}

Expand Down
12 changes: 7 additions & 5 deletions src/Socket/messages-send.ts
Original file line number Diff line number Diff line change
Expand Up @@ -312,12 +312,13 @@ export const makeMessagesSocket = (config: SocketConfig) => {
const statusJid = 'status@broadcast'
const isGroup = server === 'g.us'
const isStatus = jid === statusJid
const isLid = server === 'lid'

msgId = msgId || generateMessageID()
useUserDevicesCache = useUserDevicesCache !== false

const participants: BinaryNode[] = []
const destinationJid = (!isStatus) ? jidEncode(user, isGroup ? 'g.us' : 's.whatsapp.net') : statusJid
const destinationJid = (!isStatus) ? jidEncode(user, isLid ? 'lid' : isGroup ? 'g.us' : 's.whatsapp.net') : statusJid
const binaryNodeContent: BinaryNode[] = []
const devices: JidWithDevice[] = []

Expand Down Expand Up @@ -377,7 +378,7 @@ export const makeMessagesSocket = (config: SocketConfig) => {
devices.push(...additionalDevices)
}

const patched = await patchMessageBeforeSending(message, devices.map(d => jidEncode(d.user, 's.whatsapp.net', d.device)))
const patched = await patchMessageBeforeSending(message, devices.map(d => jidEncode(d.user, isLid ? 'lid' : 's.whatsapp.net', d.device)))
const bytes = encodeWAMessage(patched)

const { ciphertext, senderKeyDistributionMessage } = await signalRepository.encryptGroupMessage(
Expand All @@ -391,7 +392,7 @@ export const makeMessagesSocket = (config: SocketConfig) => {
const senderKeyJids: string[] = []
// ensure a connection is established with every device
for(const { user, device } of devices) {
const jid = jidEncode(user, 's.whatsapp.net', device)
const jid = jidEncode(user, isLid ? 'lid' : 's.whatsapp.net', device)
if(!senderKeyMap[jid] || !!participant) {
senderKeyJids.push(jid)
// store that this person has had the sender keys sent to them
Expand Down Expand Up @@ -444,8 +445,8 @@ export const makeMessagesSocket = (config: SocketConfig) => {
const meJids: string[] = []
const otherJids: string[] = []
for(const { user, device } of devices) {
const jid = jidEncode(user, 's.whatsapp.net', device)
const isMe = user === meUser
const jid = jidEncode(isMe && isLid ? authState.creds?.me?.lid!.split(':')[0] || user : user, isLid ? 'lid' : 's.whatsapp.net', device)
if(isMe) {
meJids.push(jid)
} else {
Expand Down Expand Up @@ -642,9 +643,10 @@ export const makeMessagesSocket = (config: SocketConfig) => {
relayMessage,
sendReceipt,
sendReceipts,
getButtonArgs,
readMessages,
refreshMediaConn,
waUploadToServer,
waUploadToServer,
fetchPrivacySettings,
updateMediaMessage: async(message: proto.IWebMessageInfo) => {
const content = assertMediaContent(message.message)
Expand Down
6 changes: 4 additions & 2 deletions src/Socket/socket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ export const makeSocket = (config: SocketConfig) => {
{
tag: 'companion_platform_display',
attrs: {},
content: config.browser[0]
content: `${browser[1]} (${browser[0]})`
},
{
tag: 'link_code_pairing_nonce',
Expand Down Expand Up @@ -623,13 +623,15 @@ export const makeSocket = (config: SocketConfig) => {
}
})
// login complete
ws.on('CB:success', async() => {
ws.on('CB:success', async(node: BinaryNode) => {
await uploadPreKeysToServerIfRequired()
await sendPassiveIq('active')

logger.info('opened connection to WA')
clearTimeout(qrTimer) // will never happen in all likelyhood -- but just in case WA sends success on first try

ev.emit('creds.update', { me: { ...authState.creds.me!, lid: node.attrs.lid } })

ev.emit('connection.update', { connection: 'open' })
})

Expand Down
3 changes: 2 additions & 1 deletion src/Types/Call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ export type WACallEvent = {
chatId: string
from: string
isGroup?: boolean
groupJid?: string
id: string
date: Date
isVideo?: boolean
status: WACallUpdateType
offline: boolean
latencyMs?: number
}
}
1 change: 1 addition & 0 deletions src/Types/Contact.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export interface Contact {
id: string
lid?: string
/** name of the contact, you have saved on your WA */
name?: string
/** name of the contact, the contact has set on their own on WA */
Expand Down
4 changes: 3 additions & 1 deletion src/Types/Events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export type BaileysEventMap = {
'chats.upsert': Chat[]
/** update the given chats */
'chats.update': ChatUpdate[]
'chats.phoneNumberShare': {lid: string, jid: string}
/** delete chats with given ID */
'chats.delete': string[]
/** presence of contact in a chat updated */
Expand All @@ -50,10 +51,11 @@ export type BaileysEventMap = {
'groups.upsert': GroupMetadata[]
'groups.update': Partial<GroupMetadata>[]
/** apply an action to participants in a group */
'group-participants.update': { id: string, participants: string[], action: ParticipantAction }
'group-participants.update': { id: string, author: string, participants: string[], action: ParticipantAction }

'blocklist.set': { blocklist: string[] }
'blocklist.update': { blocklist: string[], type: 'add' | 'remove' }

/** Receive an update on a call, including when the call was received, rejected, accepted */
'call': WACallEvent[]
'labels.edit': Label
Expand Down
10 changes: 9 additions & 1 deletion src/Types/Message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,14 @@ export type PollMessageOptions = {
messageSecret?: Uint8Array
}

type SharePhoneNumber = {
sharePhoneNumber: boolean
}

type RequestPhoneNumber = {
requestPhoneNumber: boolean
}

export type MediaType = keyof typeof MEDIA_HKDF_KEY_MAPPING
export type AnyMediaMessageContent = (
({
Expand Down Expand Up @@ -169,7 +177,7 @@ export type AnyRegularMessageContent = (
businessOwnerJid?: string
body?: string
footer?: string
}
} | SharePhoneNumber | RequestPhoneNumber
) & ViewOnce

export type AnyMessageContent = AnyRegularMessageContent | {
Expand Down
Loading

0 comments on commit 8df8362

Please sign in to comment.