finalize multi-device

This commit is contained in:
Adhiraj Singh
2021-09-15 13:40:02 +05:30
parent 9cba28e891
commit f267f27ada
82 changed files with 35228 additions and 10644 deletions

View File

@@ -1,22 +1,51 @@
import type { Contact } from "./Contact"
import type { proto } from "../../WAProto"
export interface AuthenticationCredentials {
clientID: string
serverToken: string
clientToken: string
encKey: Buffer
macKey: Buffer
export type KeyPair = { public: Uint8Array, private: Uint8Array }
export type SignedKeyPair = { keyPair: KeyPair, signature: Uint8Array, keyId: number }
export type ProtocolAddress = {
name: string // jid
deviceId: number
}
export interface AuthenticationCredentialsBase64 {
clientID: string
serverToken: string
clientToken: string
encKey: string
macKey: string
export type SignalIdentity = {
identifier: ProtocolAddress
identifierKey: Uint8Array
}
export interface AuthenticationCredentialsBrowser {
WABrowserId: string
WASecretBundle: {encKey: string, macKey: string} | string
WAToken1: string
WAToken2: string
export type CollectionType = 'regular_high' | 'regular_low' | 'critical_unblock_low' | 'critical_block'
export type AuthenticationCreds = {
noiseKey: KeyPair
signedIdentityKey: KeyPair
signedPreKey: SignedKeyPair
registrationId: number
advSecretKey: string
me?: Contact
account?: proto.ADVSignedDeviceIdentity
signalIdentities?: SignalIdentity[]
appStateSyncKeys?: proto.IAppStateSyncKey[]
appStateVersion?: {
[T in CollectionType]: number
}
firstUnuploadedPreKeyId: number
serverHasPreKeys: boolean
nextPreKeyId: number
}
export type AnyAuthenticationCredentials = AuthenticationCredentialsBrowser | AuthenticationCredentialsBase64 | AuthenticationCredentials
type Awaitable<T> = T | Promise<T>
export type SignalKeyStore = {
getPreKey: (keyId: number) => Awaitable<KeyPair>
setPreKey: (keyId: number, pair: KeyPair | null) => Awaitable<void>
getSession: (sessionId: string) => Awaitable<any>
setSession: (sessionId: string, item: any | null) => Awaitable<void>
getSenderKey: (id: string) => Awaitable<any>
setSenderKey: (id: string, item: any | null) => Awaitable<void>
}
export type AuthenticationState = {
creds: AuthenticationCreds
keys: SignalKeyStore
}

View File

@@ -1,46 +1,30 @@
import type { proto } from "../../WAProto"
/** set of statuses visible to other people; see updatePresence() in WhatsAppWeb.Send */
export enum Presence {
unavailable = 'unavailable', // "offline"
available = 'available', // "online"
composing = 'composing', // "typing..."
recording = 'recording', // "recording..."
paused = 'paused', // stop typing
}
export type WAPresence = 'unavailable' | 'available' | 'composing' | 'recording' | 'paused'
export interface PresenceData {
lastKnownPresence: Presence
lastKnownPresence: WAPresence
lastSeen?: number
}
export interface Chat {
jid: string
t: number
/** number of unread messages, is < 0 if the chat is manually marked unread */
count: number
archive?: 'true' | 'false'
clear?: 'true' | 'false'
read_only?: 'true' | 'false'
mute?: string
pin?: string
spam?: 'false' | 'true'
modify_tag?: string
name?: string
/** when ephemeral messages were toggled on */
eph_setting_ts?: string
/** how long each message lasts for */
ephemeral?: string
export type Chat = Omit<proto.IConversation, 'messages'> & {
/** unix timestamp of date when mute ends, if applicable */
mute?: number | null
/** timestamp of when pinned */
pin?: number | null
archive?: boolean
}
export type ChatModification =
{ archive: boolean } |
{
/** pin at current timestamp, or provide timestamp of pin to remove */
pin: true | { remove: number }
pin: number | null
} |
{
/** mute for duration, or provide timestamp of mute to remove*/
mute: number | { remove: number }
mute: number | null
} |
{
clear: 'all' | { messages: { id: string, fromMe?: boolean }[] }
@@ -51,4 +35,7 @@ export type ChatModification =
star: boolean
}
} |
{
markRead: boolean
} |
{ delete: true }

View File

@@ -1,15 +1,11 @@
export interface Contact {
verify?: string
/** name of the contact, the contact has set on their own on WA */
notify?: string
jid: string
/** I have no idea */
vname?: string
id: string
/** name of the contact, you have saved on your WA */
name?: string
index?: string
/** short name for the contact */
short?: string
/** name of the contact, the contact has set on their own on WA */
notify?: string
/** I have no idea */
verifiedName?: string
// Baileys Added
imgUrl?: string
status?: string

View File

@@ -1,6 +1,6 @@
import { Contact } from "./Contact";
export type GroupParticipant = (Contact & { isAdmin: boolean; isSuperAdmin: boolean })
export type GroupParticipant = (Contact & { isAdmin?: boolean; isSuperAdmin?: boolean, admin?: 'admin' | 'superadmin' | null })
export type ParticipantAction = 'add' | 'remove' | 'promote' | 'demote'

View File

@@ -1,18 +1,18 @@
import type { ReadStream } from "fs"
import type { Logger } from "pino"
import type { URL } from "url"
import { proto } from '../../WAMessage'
import { proto } from '../../WAProto'
// export the WAMessage Prototypes
export { proto as WAMessageProto }
export type WAMessage = proto.WebMessageInfo
export { proto as WAProto }
export type WAMessage = proto.IWebMessageInfo
export type WAMessageContent = proto.IMessage
export type WAContactMessage = proto.ContactMessage
export type WAContactsArrayMessage = proto.ContactsArrayMessage
export type WAContactMessage = proto.IContactMessage
export type WAContactsArrayMessage = proto.IContactsArrayMessage
export type WAMessageKey = proto.IMessageKey
export type WATextMessage = proto.ExtendedTextMessage
export type WATextMessage = proto.IExtendedTextMessage
export type WAContextInfo = proto.IContextInfo
export type WALocationMessage = proto.LocationMessage
export type WALocationMessage = proto.ILocationMessage
export type WAGenericMediaMessage = proto.IVideoMessage | proto.IImageMessage | proto.IAudioMessage | proto.IDocumentMessage | proto.IStickerMessage
export import WAMessageStubType = proto.WebMessageInfo.WebMessageInfoStubType
export import WAMessageStatus = proto.WebMessageInfo.WebMessageInfoStatus
@@ -23,20 +23,10 @@ export type MessageType = keyof proto.Message
export type MediaConnInfo = {
auth: string
ttl: number
hosts: {
hostname: string
}[]
hosts: { hostname: string }[]
fetchDate: Date
}
/** Reverse stub type dictionary */
export const WA_MESSAGE_STUB_TYPES = function () {
const types = WAMessageStubType
const dict: Record<number, string> = {}
Object.keys(types).forEach(element => dict[ types[element] ] = element)
return dict
}()
export interface WAUrlInfo {
'canonical-url': string
'matched-text': string
@@ -61,7 +51,7 @@ type WithDimensions = {
width?: number
height?: number
}
export type MediaType = 'image' | 'video' | 'sticker' | 'audio' | 'document'
export type MediaType = 'image' | 'video' | 'sticker' | 'audio' | 'document' | 'history'
export type AnyMediaMessageContent = (
({
image: WAMediaUpload
@@ -121,10 +111,7 @@ export type MiscMessageGenerationOptions = {
/** the message you want to quote */
quoted?: WAMessage
/** disappearing messages settings */
ephemeralOptions?: {
expiration: number | string
eph_setting_ts?: number | string
}
ephemeralExpiration?: number | string
}
export type MessageGenerationOptionsFromContent = MiscMessageGenerationOptions & {
userJid: string
@@ -143,7 +130,7 @@ export type MessageContentGenerationOptions = MediaGenerationOptions & {
}
export type MessageGenerationOptions = MessageContentGenerationOptions & MessageGenerationOptionsFromContent
export type MessageUpdateType = 'prepend' | 'append' | 'notify' | 'last'
export type MessageUpdateType = 'append' | 'notify'
export type MessageInfoEventMap = { [jid: string]: Date }
export interface MessageInfo {

17
src/Types/State.ts Normal file
View File

@@ -0,0 +1,17 @@
export type WAConnectionState = 'open' | 'connecting' | 'close'
export type ConnectionState = {
/** connection is now open, connecting or closed */
connection: WAConnectionState
/** the error that caused the connection to close */
lastDisconnect?: {
error: Error
date: Date
}
/** is this a new login */
isNewLogin?: boolean
/** the current QR code */
qr?: string
/** has the device received all pending notifications while it was offline */
receivedPendingNotifications?: boolean
}

View File

@@ -1,25 +0,0 @@
import type KeyedDB from '@adiwajshing/keyed-db'
import type { Chat } from './Chat'
import type { Contact } from './Contact'
export type WAConnectionState = 'open' | 'connecting' | 'close'
export type ConnectionState = {
user?: Contact
phoneConnected: boolean
phoneInfo?: any
connection: WAConnectionState
lastDisconnect?: {
error: Error,
date: Date
},
isNewLogin?: boolean
connectionTriesLeft?: number
qr?: string
}
export type BaileysState = {
connection: ConnectionState
chats: KeyedDB<Chat, string>
contacts: { [jid: string]: Contact }
}

View File

@@ -2,134 +2,56 @@ export * from './Auth'
export * from './GroupMetadata'
export * from './Chat'
export * from './Contact'
export * from './Store'
export * from './State'
export * from './Message'
import type EventEmitter from "events"
import type { Agent } from "https"
import type { Logger } from "pino"
import type { URL } from "url"
import type BinaryNode from "../BinaryNode"
import { AnyAuthenticationCredentials, AuthenticationCredentials } from './Auth'
import { AuthenticationState } from './Auth'
import { Chat, PresenceData } from './Chat'
import { Contact } from './Contact'
import { ConnectionState } from './Store'
import { ConnectionState } from './State'
import { GroupMetadata, ParticipantAction } from './GroupMetadata'
import { MessageInfo, MessageInfoUpdate, MessageUpdateType, WAMessage, WAMessageKey, WAMessageUpdate } from './Message'
import { proto } from '../../WAMessage'
/** used for binary messages */
export enum WAMetric {
debugLog = 1,
queryResume = 2,
liveLocation = 3,
queryMedia = 4,
queryChat = 5,
queryContact = 6,
queryMessages = 7,
presence = 8,
presenceSubscribe = 9,
group = 10,
read = 11,
chat = 12,
received = 13,
picture = 14,
status = 15,
message = 16,
queryActions = 17,
block = 18,
queryGroup = 19,
queryPreview = 20,
queryEmoji = 21,
queryRead = 22,
queryVCard = 29,
queryStatus = 30,
queryStatusUpdate = 31,
queryLiveLocation = 33,
queryLabel = 36,
queryQuickReply = 39
}
/** used for binary messages */
export enum WAFlag {
available = 160,
other = 136, // don't know this one
ignore = 1 << 7,
acknowledge = 1 << 6,
unavailable = 1 << 4,
expires = 1 << 3,
composing = 1 << 2,
recording = 1 << 2,
paused = 1 << 2
}
/** Tag used with binary queries */
export type WATag = [WAMetric, WAFlag]
export type SocketSendMessageOptions = {
json: BinaryNode | any[]
binaryTag?: WATag
tag?: string
longTag?: boolean
}
import { MessageInfoUpdate, MessageUpdateType, WAMessage, WAMessageUpdate } from './Message'
export type WAVersion = [number, number, number]
export type WABrowserDescription = [string, string, string]
export type ReconnectMode = 'no-reconnects' | 'on-any-error' | 'on-connection-error'
export type SocketConfig = {
/** provide an auth state object to maintain the auth state */
auth?: AuthenticationState
/** the WS url to connect to WA */
waWebSocketUrl: string | URL
/** Fails the connection if the connection times out in this time interval or no data is received */
/** Fails the connection if the socket times out in this interval */
connectTimeoutMs: number
/** max time for the phone to respond to a connectivity test */
phoneResponseTimeMs: number
/** ping-pong interval for WS connection */
keepAliveIntervalMs: number
expectResponseTimeout: number
/** proxy agent */
agent?: Agent
/** pino logger */
logger: Logger
/** version to connect with */
version: WAVersion
/** override browser config */
browser: WABrowserDescription
/** maximum attempts to connect */
maxRetries: number
connectCooldownMs: number
/** agent used for fetch requests -- uploading/downloading media */
fetchAgent?: Agent
/** credentials used to sign back in */
credentials?: AnyAuthenticationCredentials | string
/**
* Sometimes WA does not send the chats,
* this keeps pinging the phone to send the chats over
* */
queryChatsTillReceived?: boolean
/** */
pendingRequestTimeoutMs: number
reconnectMode: ReconnectMode
maxQRCodes: number
/** should the QR be printed in the terminal */
printQRInTerminal: boolean
phoneConnectionChanged: (connected: boolean) => void
}
export type SocketQueryOptions = SocketSendMessageOptions & {
timeoutMs?: number
expect200?: boolean
requiresPhoneConnection?: boolean
}
export enum DisconnectReason {
connectionClosed = 428,
connectionReplaced = 440,
connectionLost = 408,
timedOut = 408,
credentialsInvalidated = 401,
badSession = 500
loggedOut = 401,
badSession = 500,
restartRequired = 410
}
export type WAInitResponse = {
@@ -160,36 +82,40 @@ export type WABusinessProfile = {
wid?: string
}
export type QueryOptions = SocketQueryOptions & {
waitForOpen?: boolean
maxRetries?: number
startDebouncedTimeout?: boolean
}
export type CurveKeyPair = { private: Uint8Array; public: Uint8Array }
export type BaileysEventMap = {
/** connection state has been updated -- WS closed, opened, connecting etc. */
'connection.update': Partial<ConnectionState>
'credentials.update': AuthenticationCredentials
'chats.set': { chats: Chat[] }
/** auth state updated -- some pre keys, or identity keys etc. */
'auth-state.update': AuthenticationState
/** set chats (history sync), messages are reverse chronologically sorted */
'chats.set': { chats: Chat[], messages: WAMessage[] }
/** upsert chats */
'chats.upsert': Chat[]
/** update the given chats */
'chats.update': Partial<Chat>[]
/** delete chats with given ID */
'chats.delete': string[]
/** presence of contact in a chat updated */
'presence.update': { id: string, presences: { [participant: string]: PresenceData } }
'presence.update': { jid: string, presences: { [participant: string]: PresenceData } }
'contacts.set': { contacts: Contact[] }
'contacts.upsert': Contact[]
'contacts.update': Partial<Contact>[]
'messages.delete': { jid: string, ids: string[] } | { jid: string, all: true }
'messages.update': WAMessageUpdate[]
/**
* add/update the given messages. If they were received while the connection was online,
* the update will have type: "notify"
* */
'messages.upsert': { messages: WAMessage[], type: MessageUpdateType }
'message-info.update': MessageInfoUpdate[]
'groups.update': Partial<GroupMetadata>[]
'group-participants.update': { jid: string, participants: string[], action: ParticipantAction }
/** apply an action to participants in a group */
'group-participants.update': { id: string, participants: string[], action: ParticipantAction }
'blocklist.set': { blocklist: string[] }
'blocklist.update': { blocklist: string[], type: 'add' | 'remove' }