├── lib ├── Defaults │ ├── baileys-version.json │ ├── phonenumber-mcc.json │ └── index.js ├── Types │ ├── Auth.js │ ├── Call.js │ ├── State.js │ ├── Contact.js │ ├── Events.js │ ├── Product.js │ ├── Signal.js │ ├── Socket.js │ ├── GroupMetadata.js │ ├── Chat.js │ ├── Call.d.ts │ ├── LabelAssociation.js │ ├── Message.js │ ├── Contact.d.ts │ ├── Label.d.ts │ ├── State.d.ts │ ├── LabelAssociation.d.ts │ ├── Label.js │ ├── Newsletter.js │ ├── index.d.ts │ ├── Signal.d.ts │ ├── GroupMetadata.d.ts │ ├── Product.d.ts │ ├── index.js │ ├── Newsletter.d.ts │ ├── Auth.d.ts │ ├── Chat.d.ts │ ├── Socket.d.ts │ └── Events.d.ts ├── WABinary │ ├── types.js │ ├── index.d.ts │ ├── encode.d.ts │ ├── decode.d.ts │ ├── types.d.ts │ ├── constants.d.ts │ ├── index.js │ ├── generic-utils.d.ts │ ├── jid-utils.d.ts │ ├── jid-utils.js │ └── generic-utils.js ├── WAM │ ├── index.d.ts │ ├── encode.d.ts │ ├── BinaryInfo.js │ ├── BinaryInfo.d.ts │ ├── index.js │ ├── constants.d.ts │ └── encode.js ├── Utils │ ├── logger.d.ts │ ├── make-mutex.d.ts │ ├── logger.js │ ├── lt-hash.d.ts │ ├── use-multi-file-auth-state.d.ts │ ├── index.d.ts │ ├── baileys-event-stream.d.ts │ ├── decode-wa-message.d.ts │ ├── history.d.ts │ ├── link-preview.d.ts │ ├── validate-connection.d.ts │ ├── noise-handler.d.ts │ ├── auth-utils.d.ts │ ├── business.d.ts │ ├── make-mutex.js │ ├── event-buffer.d.ts │ ├── signal.d.ts │ ├── index.js │ ├── lt-hash.js │ ├── process-message.d.ts │ ├── crypto.d.ts │ ├── baileys-event-stream.js │ ├── use-multi-file-auth-state.js │ ├── chat-utils.d.ts │ ├── link-preview.js │ ├── history.js │ ├── generics.d.ts │ ├── messages.d.ts │ ├── messages-media.d.ts │ └── noise-handler.js ├── Socket │ ├── Client │ │ ├── index.d.ts │ │ ├── abstract-socket-client.js │ │ ├── web-socket-client.d.ts │ │ ├── mobile-socket-client.d.ts │ │ ├── abstract-socket-client.d.ts │ │ ├── index.js │ │ ├── mobile-socket-client.js │ │ └── web-socket-client.js │ ├── index.js │ ├── socket.d.ts │ ├── chats.d.ts │ └── groups.d.ts ├── Store │ ├── index.d.ts │ ├── object-repository.d.ts │ ├── make-cache-manager-store.d.ts │ ├── make-ordered-dictionary.d.ts │ ├── index.js │ ├── object-repository.js │ ├── make-ordered-dictionary.js │ ├── make-cache-manager-store.js │ └── make-in-memory-store.d.ts ├── Signal │ └── libsignal.d.ts ├── index.d.ts └── index.js ├── WASignalGroup ├── protobufs.js ├── ciphertext_message.js ├── index.js ├── keyhelper.js ├── sender_message_key.js ├── sender_chain_key.js ├── sender_key_name.js ├── sender_key_record.js ├── group_session_builder.js ├── queue_job.js ├── sender_key_distribution_message.js ├── sender_key_message.js ├── group_cipher.js └── sender_key_state.js ├── typedoc.json ├── WAProto └── GenerateStatics.sh ├── tsconfig.json └── package.json /lib/Defaults/baileys-version.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": [2, 2413, 1] 3 | } 4 | -------------------------------------------------------------------------------- /lib/Types/Auth.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /lib/Types/Call.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /lib/Types/State.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /lib/Types/Contact.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /lib/Types/Events.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /lib/Types/Product.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /lib/Types/Signal.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /lib/Types/Socket.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /lib/WABinary/types.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /WASignalGroup/protobufs.js: -------------------------------------------------------------------------------- 1 | const { groupproto } = require('./GroupProtocol') 2 | 3 | module.exports = groupproto -------------------------------------------------------------------------------- /lib/Types/GroupMetadata.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | -------------------------------------------------------------------------------- /lib/WAM/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from './constants'; 2 | export * from './encode'; 3 | export * from './BinaryInfo'; 4 | -------------------------------------------------------------------------------- /lib/Utils/logger.d.ts: -------------------------------------------------------------------------------- 1 | declare const _default: import("pino").Logger<{ 2 | timestamp: () => string; 3 | }>; 4 | export default _default; 5 | -------------------------------------------------------------------------------- /lib/Socket/Client/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from './abstract-socket-client'; 2 | export * from './mobile-socket-client'; 3 | export * from './web-socket-client'; 4 | -------------------------------------------------------------------------------- /lib/WAM/encode.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { BinaryInfo } from './BinaryInfo'; 3 | export declare const encodeWAM: (binaryInfo: BinaryInfo) => Buffer; 4 | -------------------------------------------------------------------------------- /lib/WABinary/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from './encode'; 2 | export * from './decode'; 3 | export * from './generic-utils'; 4 | export * from './jid-utils'; 5 | export * from './types'; 6 | -------------------------------------------------------------------------------- /lib/Store/index.d.ts: -------------------------------------------------------------------------------- 1 | import makeCacheManagerAuthState from './make-cache-manager-store'; 2 | import makeInMemoryStore from './make-in-memory-store'; 3 | export { makeInMemoryStore, makeCacheManagerAuthState }; 4 | -------------------------------------------------------------------------------- /lib/Signal/libsignal.d.ts: -------------------------------------------------------------------------------- 1 | import { SignalAuthState } from '../Types'; 2 | import { SignalRepository } from '../Types/Signal'; 3 | export declare function makeLibSignalRepository(auth: SignalAuthState): SignalRepository; 4 | -------------------------------------------------------------------------------- /lib/Types/Chat.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.ALL_WA_PATCH_NAMES = void 0; 4 | exports.ALL_WA_PATCH_NAMES = ['critical_block', 'critical_unblock_low', 'regular_high', 'regular_low', 'regular']; 5 | -------------------------------------------------------------------------------- /typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "entryPoints": ["./lib/index.ts"], 3 | "excludePrivate": true, 4 | "excludeProtected": true, 5 | "excludeExternals": true, 6 | "includeVersion": false, 7 | "out": "docs", 8 | "gaID": "G-WBY63HR4VS" 9 | } 10 | -------------------------------------------------------------------------------- /lib/WABinary/encode.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import type { BinaryNode, BinaryNodeCodingOptions } from './types'; 3 | export declare const encodeBinaryNode: ({ tag, attrs, content }: BinaryNode, opts?: Pick, buffer?: number[]) => Buffer; 4 | -------------------------------------------------------------------------------- /lib/Utils/make-mutex.d.ts: -------------------------------------------------------------------------------- 1 | export declare const makeMutex: () => { 2 | mutex(code: () => T | Promise): Promise; 3 | }; 4 | export type Mutex = ReturnType; 5 | export declare const makeKeyedMutex: () => { 6 | mutex(key: string, task: () => T | Promise): Promise; 7 | }; 8 | -------------------------------------------------------------------------------- /WAProto/GenerateStatics.sh: -------------------------------------------------------------------------------- 1 | yarn pbjs -t static-module -w commonjs -o ./WAProto/index.js ./WAProto/WAProto.proto; 2 | yarn pbts -o ./WAProto/index.d.ts ./WAProto/index.js; 3 | 4 | #protoc --plugin=./node_modules/.bin/protoc-gen-ts_proto --ts_proto_opt=env=node,useOptionals=true,forceLong=long --ts_proto_out=. ./src/Binary/WAMessage.proto; -------------------------------------------------------------------------------- /WASignalGroup/ciphertext_message.js: -------------------------------------------------------------------------------- 1 | class CiphertextMessage { 2 | UNSUPPORTED_VERSION = 1; 3 | 4 | CURRENT_VERSION = 3; 5 | 6 | WHISPER_TYPE = 2; 7 | 8 | PREKEY_TYPE = 3; 9 | 10 | SENDERKEY_TYPE = 4; 11 | 12 | SENDERKEY_DISTRIBUTION_TYPE = 5; 13 | 14 | ENCRYPTED_MESSAGE_OVERHEAD = 53; 15 | } 16 | module.exports = CiphertextMessage; -------------------------------------------------------------------------------- /WASignalGroup/index.js: -------------------------------------------------------------------------------- 1 | module.exports.GroupSessionBuilder = require('./group_session_builder') 2 | module.exports.SenderKeyDistributionMessage = require('./sender_key_distribution_message') 3 | module.exports.SenderKeyRecord = require('./sender_key_record') 4 | module.exports.SenderKeyName = require('./sender_key_name') 5 | module.exports.GroupCipher = require('./group_cipher') -------------------------------------------------------------------------------- /lib/index.d.ts: -------------------------------------------------------------------------------- 1 | import makeWASocket from './Socket'; 2 | export * from '../WAProto'; 3 | export * from './Utils'; 4 | export * from './Types'; 5 | export * from './Store'; 6 | export * from './Defaults'; 7 | export * from './WABinary'; 8 | export * from './WAM'; 9 | export type WASocket = ReturnType; 10 | export { makeWASocket }; 11 | export default makeWASocket; 12 | -------------------------------------------------------------------------------- /lib/Utils/logger.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | const pino_1 = __importDefault(require("pino")); 7 | exports.default = (0, pino_1.default)({ timestamp: () => `,"time":"${new Date().toJSON()}"` }); 8 | -------------------------------------------------------------------------------- /lib/Types/Call.d.ts: -------------------------------------------------------------------------------- 1 | export type WACallUpdateType = 'offer' | 'ringing' | 'timeout' | 'reject' | 'accept'; 2 | export type WACallEvent = { 3 | chatId: string; 4 | from: string; 5 | isGroup?: boolean; 6 | groupJid?: string; 7 | id: string; 8 | date: Date; 9 | isVideo?: boolean; 10 | status: WACallUpdateType; 11 | offline: boolean; 12 | latencyMs?: number; 13 | }; 14 | -------------------------------------------------------------------------------- /lib/Store/object-repository.d.ts: -------------------------------------------------------------------------------- 1 | export declare class ObjectRepository { 2 | readonly entityMap: Map; 3 | constructor(entities?: Record); 4 | findById(id: string): T | undefined; 5 | findAll(): T[]; 6 | upsertById(id: string, entity: T): Map; 7 | deleteById(id: string): boolean; 8 | count(): number; 9 | toJSON(): T[]; 10 | } 11 | -------------------------------------------------------------------------------- /lib/WAM/BinaryInfo.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.BinaryInfo = void 0; 4 | class BinaryInfo { 5 | constructor(options = {}) { 6 | this.protocolVersion = 5; 7 | this.sequence = 0; 8 | this.events = []; 9 | this.buffer = []; 10 | Object.assign(this, options); 11 | } 12 | } 13 | exports.BinaryInfo = BinaryInfo; 14 | -------------------------------------------------------------------------------- /lib/Socket/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const Defaults_1 = require("../Defaults"); 4 | const registration_1 = require("./registration"); 5 | // export the last socket layer 6 | const makeWASocket = (config) => ((0, registration_1.makeRegistrationSocket)({ 7 | ...Defaults_1.DEFAULT_CONNECTION_CONFIG, 8 | ...config 9 | })); 10 | exports.default = makeWASocket; 11 | -------------------------------------------------------------------------------- /lib/Types/LabelAssociation.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.LabelAssociationType = void 0; 4 | /** Association type */ 5 | var LabelAssociationType; 6 | (function (LabelAssociationType) { 7 | LabelAssociationType["Chat"] = "label_jid"; 8 | LabelAssociationType["Message"] = "label_message"; 9 | })(LabelAssociationType = exports.LabelAssociationType || (exports.LabelAssociationType = {})); 10 | -------------------------------------------------------------------------------- /lib/Utils/lt-hash.d.ts: -------------------------------------------------------------------------------- 1 | declare class d { 2 | salt: string; 3 | constructor(e: string); 4 | add(e: any, t: any): any; 5 | subtract(e: any, t: any): any; 6 | subtractThenAdd(e: any, t: any, r: any): any; 7 | _addSingle(e: any, t: any): ArrayBuffer; 8 | _subtractSingle(e: any, t: any): ArrayBuffer; 9 | performPointwiseWithOverflow(e: any, t: any, r: any): ArrayBuffer; 10 | } 11 | export declare const LT_HASH_ANTI_TAMPERING: d; 12 | export {}; 13 | -------------------------------------------------------------------------------- /lib/WAM/BinaryInfo.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | export declare class BinaryInfo { 3 | protocolVersion: number; 4 | sequence: number; 5 | events: { 6 | [x: string]: { 7 | props: { 8 | [x: string]: any; 9 | }; 10 | globals: { 11 | [x: string]: any; 12 | }; 13 | }; 14 | }[]; 15 | buffer: Buffer[]; 16 | constructor(options?: Partial); 17 | } 18 | -------------------------------------------------------------------------------- /lib/WABinary/decode.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import type { BinaryNode, BinaryNodeCodingOptions } from './types'; 3 | export declare const decompressingIfRequired: (buffer: Buffer) => Buffer; 4 | export declare const decodeDecompressedBinaryNode: (buffer: Buffer, opts: Pick, indexRef?: { 5 | index: number; 6 | }) => BinaryNode; 7 | export declare const decodeBinaryNode: (buff: Buffer) => BinaryNode; 8 | -------------------------------------------------------------------------------- /lib/Socket/Client/abstract-socket-client.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.AbstractSocketClient = void 0; 4 | const events_1 = require("events"); 5 | class AbstractSocketClient extends events_1.EventEmitter { 6 | constructor(url, config) { 7 | super(); 8 | this.url = url; 9 | this.config = config; 10 | this.setMaxListeners(0); 11 | } 12 | } 13 | exports.AbstractSocketClient = AbstractSocketClient; 14 | -------------------------------------------------------------------------------- /lib/Socket/Client/web-socket-client.d.ts: -------------------------------------------------------------------------------- 1 | import WebSocket from 'ws'; 2 | import { AbstractSocketClient } from './abstract-socket-client'; 3 | export declare class WebSocketClient extends AbstractSocketClient { 4 | protected socket: WebSocket | null; 5 | get isOpen(): boolean; 6 | get isClosed(): boolean; 7 | get isClosing(): boolean; 8 | get isConnecting(): boolean; 9 | connect(): Promise; 10 | close(): Promise; 11 | send(str: string | Uint8Array, cb?: (err?: Error) => void): boolean; 12 | } 13 | -------------------------------------------------------------------------------- /lib/Store/make-cache-manager-store.d.ts: -------------------------------------------------------------------------------- 1 | import { AuthenticationCreds } from '../Types'; 2 | declare const makeCacheManagerAuthState: (store: Storage, sessionKey: string) => Promise<{ 3 | clearState: () => Promise; 4 | saveCreds: () => Promise; 5 | state: { 6 | creds: AuthenticationCreds; 7 | keys: { 8 | get: (type: string, ids: string[]) => Promise<{}>; 9 | set: (data: any) => Promise; 10 | }; 11 | }; 12 | }>; 13 | export default makeCacheManagerAuthState; 14 | -------------------------------------------------------------------------------- /WASignalGroup/keyhelper.js: -------------------------------------------------------------------------------- 1 | const curve = require('libsignal/src/curve'); 2 | const nodeCrypto = require('crypto'); 3 | 4 | exports.generateSenderKey = function() { 5 | return nodeCrypto.randomBytes(32); 6 | } 7 | 8 | exports.generateSenderKeyId = function() { 9 | return nodeCrypto.randomInt(2147483647); 10 | } 11 | 12 | exports.generateSenderSigningKey = function(key) { 13 | if (!key) { 14 | key = curve.generateKeyPair(); 15 | } 16 | 17 | return { 18 | public: key.pubKey, 19 | private: key.privKey, 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /lib/Utils/use-multi-file-auth-state.d.ts: -------------------------------------------------------------------------------- 1 | import { AuthenticationState } from '../Types'; 2 | /** 3 | * stores the full authentication state in a single folder. 4 | * Far more efficient than singlefileauthstate 5 | * 6 | * Again, I wouldn't endorse this for any production level use other than perhaps a bot. 7 | * Would recommend writing an auth state for use with a proper SQL or No-SQL DB 8 | * */ 9 | export declare const useMultiFileAuthState: (folder: string) => Promise<{ 10 | state: AuthenticationState; 11 | saveCreds: () => Promise; 12 | }>; 13 | -------------------------------------------------------------------------------- /lib/Socket/Client/mobile-socket-client.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Socket } from 'net'; 3 | import { AbstractSocketClient } from './abstract-socket-client'; 4 | export declare class MobileSocketClient extends AbstractSocketClient { 5 | protected socket: Socket | null; 6 | get isOpen(): boolean; 7 | get isClosed(): boolean; 8 | get isClosing(): boolean; 9 | get isConnecting(): boolean; 10 | connect(): Promise; 11 | close(): Promise; 12 | send(str: string | Uint8Array, cb?: (err?: Error) => void): boolean; 13 | } 14 | -------------------------------------------------------------------------------- /lib/Store/make-ordered-dictionary.d.ts: -------------------------------------------------------------------------------- 1 | declare function makeOrderedDictionary(idGetter: (item: T) => string): { 2 | array: T[]; 3 | get: (id: string) => T | undefined; 4 | upsert: (item: T, mode: 'append' | 'prepend') => void; 5 | update: (item: T) => boolean; 6 | remove: (item: T) => boolean; 7 | updateAssign: (id: string, update: Partial) => boolean; 8 | clear: () => void; 9 | filter: (contain: (item: T) => boolean) => void; 10 | toJSON: () => T[]; 11 | fromJSON: (newItems: T[]) => void; 12 | }; 13 | export default makeOrderedDictionary; 14 | -------------------------------------------------------------------------------- /lib/Utils/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from './generics'; 2 | export * from './decode-wa-message'; 3 | export * from './messages'; 4 | export * from './messages-media'; 5 | export * from './validate-connection'; 6 | export * from './crypto'; 7 | export * from './signal'; 8 | export * from './noise-handler'; 9 | export * from './history'; 10 | export * from './chat-utils'; 11 | export * from './lt-hash'; 12 | export * from './auth-utils'; 13 | export * from './baileys-event-stream'; 14 | export * from './use-multi-file-auth-state'; 15 | export * from './link-preview'; 16 | export * from './event-buffer'; 17 | export * from './process-message'; 18 | -------------------------------------------------------------------------------- /lib/Store/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.makeCacheManagerAuthState = exports.makeInMemoryStore = void 0; 7 | const make_cache_manager_store_1 = __importDefault(require("./make-cache-manager-store")); 8 | exports.makeCacheManagerAuthState = make_cache_manager_store_1.default; 9 | const make_in_memory_store_1 = __importDefault(require("./make-in-memory-store")); 10 | exports.makeInMemoryStore = make_in_memory_store_1.default; 11 | -------------------------------------------------------------------------------- /lib/Types/Message.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.WAMessageStatus = exports.WAMessageStubType = exports.WAProto = void 0; 4 | const WAProto_1 = require("../../WAProto"); 5 | Object.defineProperty(exports, "WAProto", { enumerable: true, get: function () { return WAProto_1.proto; } }); 6 | // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars 7 | exports.WAMessageStubType = WAProto_1.proto.WebMessageInfo.StubType; 8 | // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars 9 | exports.WAMessageStatus = WAProto_1.proto.WebMessageInfo.Status; 10 | -------------------------------------------------------------------------------- /lib/Types/Contact.d.ts: -------------------------------------------------------------------------------- 1 | export interface Contact { 2 | id: string; 3 | lid?: string; 4 | /** name of the contact, you have saved on your WA */ 5 | name?: string; 6 | /** name of the contact, the contact has set on their own on WA */ 7 | notify?: string; 8 | /** I have no idea */ 9 | verifiedName?: string; 10 | /** 11 | * Url of the profile picture of the contact 12 | * 13 | * 'changed' => if the profile picture has changed 14 | * null => if the profile picture has not been set (default profile picture) 15 | * any other string => url of the profile picture 16 | */ 17 | imgUrl?: string | null | 'changed'; 18 | status?: string; 19 | } 20 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "module": "CommonJS", 5 | "moduleResolution": "NodeNext", 6 | "experimentalDecorators": true, 7 | "allowJs": false, 8 | "checkJs": false, 9 | "outDir": "lib", 10 | "strict": false, 11 | "strictNullChecks": true, 12 | "skipLibCheck": true, 13 | "noImplicitThis": true, 14 | "esModuleInterop": true, 15 | "resolveJsonModule": true, 16 | "forceConsistentCasingInFileNames": true, 17 | "declaration": true, 18 | "lib": ["es2020", "esnext.array", "DOM"] 19 | }, 20 | "include": ["./lib/**/*.ts"], 21 | "exclude": ["node_modules", "lib/Tests/*", "lib/Binary/GenerateStatics.ts"] 22 | } 23 | -------------------------------------------------------------------------------- /lib/Utils/baileys-event-stream.d.ts: -------------------------------------------------------------------------------- 1 | import type { BaileysEventEmitter } from '../Types'; 2 | /** 3 | * Captures events from a baileys event emitter & stores them in a file 4 | * @param ev The event emitter to read events from 5 | * @param filename File to save to 6 | */ 7 | export declare const captureEventStream: (ev: BaileysEventEmitter, filename: string) => void; 8 | /** 9 | * Read event file and emit events from there 10 | * @param filename filename containing event data 11 | * @param delayIntervalMs delay between each event emit 12 | */ 13 | export declare const readAndEmitEventStream: (filename: string, delayIntervalMs?: number) => { 14 | ev: BaileysEventEmitter; 15 | task: Promise; 16 | }; 17 | -------------------------------------------------------------------------------- /lib/WABinary/types.d.ts: -------------------------------------------------------------------------------- 1 | import * as constants from './constants'; 2 | /** 3 | * the binary node WA uses internally for communication 4 | * 5 | * this is manipulated soley as an object and it does not have any functions. 6 | * This is done for easy serialization, to prevent running into issues with prototypes & 7 | * to maintain functional code structure 8 | * */ 9 | export type BinaryNode = { 10 | tag: string; 11 | attrs: { 12 | [key: string]: string; 13 | }; 14 | content?: BinaryNode[] | string | Uint8Array; 15 | }; 16 | export type BinaryNodeAttributes = BinaryNode['attrs']; 17 | export type BinaryNodeData = BinaryNode['content']; 18 | export type BinaryNodeCodingOptions = typeof constants; 19 | -------------------------------------------------------------------------------- /lib/Socket/Client/abstract-socket-client.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | import { EventEmitter } from 'events'; 4 | import { URL } from 'url'; 5 | import { SocketConfig } from '../../Types'; 6 | export declare abstract class AbstractSocketClient extends EventEmitter { 7 | url: URL; 8 | config: SocketConfig; 9 | abstract get isOpen(): boolean; 10 | abstract get isClosed(): boolean; 11 | abstract get isClosing(): boolean; 12 | abstract get isConnecting(): boolean; 13 | constructor(url: URL, config: SocketConfig); 14 | abstract connect(): Promise; 15 | abstract close(): Promise; 16 | abstract send(str: Uint8Array | string, cb?: (err?: Error) => void): boolean; 17 | } 18 | -------------------------------------------------------------------------------- /lib/WABinary/constants.d.ts: -------------------------------------------------------------------------------- 1 | export declare const TAGS: { 2 | LIST_EMPTY: number; 3 | DICTIONARY_0: number; 4 | DICTIONARY_1: number; 5 | DICTIONARY_2: number; 6 | DICTIONARY_3: number; 7 | AD_JID: number; 8 | LIST_8: number; 9 | LIST_16: number; 10 | JID_PAIR: number; 11 | HEX_8: number; 12 | BINARY_8: number; 13 | BINARY_20: number; 14 | BINARY_32: number; 15 | NIBBLE_8: number; 16 | PACKED_MAX: number; 17 | SINGLE_BYTE_MAX: number; 18 | STREAM_END: number; 19 | }; 20 | export declare const DOUBLE_BYTE_TOKENS: string[][]; 21 | export declare const SINGLE_BYTE_TOKENS: (string | null)[]; 22 | export declare const TOKEN_MAP: { 23 | [token: string]: { 24 | dict?: number; 25 | index: number; 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /lib/Utils/decode-wa-message.d.ts: -------------------------------------------------------------------------------- 1 | import { Logger } from 'pino'; 2 | import { proto } from '../../WAProto'; 3 | import { SignalRepository } from '../Types'; 4 | import { BinaryNode } from '../WABinary'; 5 | /** 6 | * Decode the received node as a message. 7 | * @note this will only parse the message, not decrypt it 8 | */ 9 | export declare function decodeMessageNode(stanza: BinaryNode, meId: string, meLid: string): { 10 | fullMessage: proto.IWebMessageInfo; 11 | author: string; 12 | sender: string; 13 | }; 14 | export declare const decryptMessageNode: (stanza: BinaryNode, meId: string, meLid: string, repository: SignalRepository, logger: Logger) => { 15 | fullMessage: proto.IWebMessageInfo; 16 | category: string; 17 | author: string; 18 | decrypt(): Promise; 19 | }; 20 | -------------------------------------------------------------------------------- /lib/Store/object-repository.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.ObjectRepository = void 0; 4 | class ObjectRepository { 5 | constructor(entities = {}) { 6 | this.entityMap = new Map(Object.entries(entities)); 7 | } 8 | findById(id) { 9 | return this.entityMap.get(id); 10 | } 11 | findAll() { 12 | return Array.from(this.entityMap.values()); 13 | } 14 | upsertById(id, entity) { 15 | return this.entityMap.set(id, { ...entity }); 16 | } 17 | deleteById(id) { 18 | return this.entityMap.delete(id); 19 | } 20 | count() { 21 | return this.entityMap.size; 22 | } 23 | toJSON() { 24 | return this.findAll(); 25 | } 26 | } 27 | exports.ObjectRepository = ObjectRepository; 28 | -------------------------------------------------------------------------------- /lib/Utils/history.d.ts: -------------------------------------------------------------------------------- 1 | import { AxiosRequestConfig } from 'axios'; 2 | import { proto } from '../../WAProto'; 3 | import { Chat, Contact } from '../Types'; 4 | export declare const downloadHistory: (msg: proto.Message.IHistorySyncNotification, options: AxiosRequestConfig) => Promise; 5 | export declare const processHistoryMessage: (item: proto.IHistorySync) => { 6 | chats: Chat[]; 7 | contacts: Contact[]; 8 | messages: proto.IWebMessageInfo[]; 9 | }; 10 | export declare const downloadAndProcessHistorySyncNotification: (msg: proto.Message.IHistorySyncNotification, options: AxiosRequestConfig) => Promise<{ 11 | chats: Chat[]; 12 | contacts: Contact[]; 13 | messages: proto.IWebMessageInfo[]; 14 | }>; 15 | export declare const getHistoryMsg: (message: proto.IMessage) => proto.Message.IHistorySyncNotification | null | undefined; 16 | -------------------------------------------------------------------------------- /lib/Types/Label.d.ts: -------------------------------------------------------------------------------- 1 | export interface Label { 2 | /** Label uniq ID */ 3 | id: string; 4 | /** Label name */ 5 | name: string; 6 | /** Label color ID */ 7 | color: number; 8 | /** Is label has been deleted */ 9 | deleted: boolean; 10 | /** WhatsApp has 5 predefined labels (New customer, New order & etc) */ 11 | predefinedId?: string; 12 | } 13 | /** WhatsApp has 20 predefined colors */ 14 | export declare enum LabelColor { 15 | Color1 = 0, 16 | Color2 = 1, 17 | Color3 = 2, 18 | Color4 = 3, 19 | Color5 = 4, 20 | Color6 = 5, 21 | Color7 = 6, 22 | Color8 = 7, 23 | Color9 = 8, 24 | Color10 = 9, 25 | Color11 = 10, 26 | Color12 = 11, 27 | Color13 = 12, 28 | Color14 = 13, 29 | Color15 = 14, 30 | Color16 = 15, 31 | Color17 = 16, 32 | Color18 = 17, 33 | Color19 = 18, 34 | Color20 = 19 35 | } 36 | -------------------------------------------------------------------------------- /lib/Utils/link-preview.d.ts: -------------------------------------------------------------------------------- 1 | import { AxiosRequestConfig } from 'axios'; 2 | import { Logger } from 'pino'; 3 | import { WAMediaUploadFunction, WAUrlInfo } from '../Types'; 4 | export type URLGenerationOptions = { 5 | thumbnailWidth: number; 6 | fetchOpts: { 7 | /** Timeout in ms */ 8 | timeout: number; 9 | proxyUrl?: string; 10 | headers?: AxiosRequestConfig<{}>['headers']; 11 | }; 12 | uploadImage?: WAMediaUploadFunction; 13 | logger?: Logger; 14 | }; 15 | /** 16 | * Given a piece of text, checks for any URL present, generates link preview for the same and returns it 17 | * Return undefined if the fetch failed or no URL was found 18 | * @param text first matched URL in text 19 | * @returns the URL info required to generate link preview 20 | */ 21 | export declare const getUrlInfo: (text: string, opts?: URLGenerationOptions) => Promise; 22 | -------------------------------------------------------------------------------- /lib/WAM/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __exportStar = (this && this.__exportStar) || function(m, exports) { 14 | for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); 15 | }; 16 | Object.defineProperty(exports, "__esModule", { value: true }); 17 | __exportStar(require("./constants"), exports); 18 | __exportStar(require("./encode"), exports); 19 | __exportStar(require("./BinaryInfo"), exports); 20 | -------------------------------------------------------------------------------- /lib/Utils/validate-connection.d.ts: -------------------------------------------------------------------------------- 1 | import { proto } from '../../WAProto'; 2 | import type { AuthenticationCreds, SignalCreds, SocketConfig } from '../Types'; 3 | import { BinaryNode } from '../WABinary'; 4 | export declare const generateMobileNode: (config: SocketConfig) => proto.IClientPayload; 5 | export declare const generateLoginNode: (userJid: string, config: SocketConfig) => proto.IClientPayload; 6 | export declare const generateRegistrationNode: ({ registrationId, signedPreKey, signedIdentityKey }: SignalCreds, config: SocketConfig) => proto.ClientPayload; 7 | export declare const configureSuccessfulPairing: (stanza: BinaryNode, { advSecretKey, signedIdentityKey, signalIdentities }: Pick) => { 8 | creds: Partial; 9 | reply: BinaryNode; 10 | }; 11 | export declare const encodeSignedDeviceIdentity: (account: proto.IADVSignedDeviceIdentity, includeSignatureKey: boolean) => Uint8Array; 12 | -------------------------------------------------------------------------------- /lib/Socket/Client/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __exportStar = (this && this.__exportStar) || function(m, exports) { 14 | for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); 15 | }; 16 | Object.defineProperty(exports, "__esModule", { value: true }); 17 | __exportStar(require("./abstract-socket-client"), exports); 18 | __exportStar(require("./mobile-socket-client"), exports); 19 | __exportStar(require("./web-socket-client"), exports); 20 | -------------------------------------------------------------------------------- /lib/Types/State.d.ts: -------------------------------------------------------------------------------- 1 | import { Contact } from './Contact'; 2 | export type WAConnectionState = 'open' | 'connecting' | 'close'; 3 | export type ConnectionState = { 4 | /** connection is now open, connecting or closed */ 5 | connection: WAConnectionState; 6 | /** the error that caused the connection to close */ 7 | lastDisconnect?: { 8 | error: Error | undefined; 9 | date: Date; 10 | }; 11 | /** is this a new login */ 12 | isNewLogin?: boolean; 13 | /** the current QR code */ 14 | qr?: string; 15 | /** has the device received all pending notifications while it was offline */ 16 | receivedPendingNotifications?: boolean; 17 | /** legacy connection options */ 18 | legacy?: { 19 | phoneConnected: boolean; 20 | user?: Contact; 21 | }; 22 | /** 23 | * if the client is shown as an active, online client. 24 | * If this is false, the primary phone and other devices will receive notifs 25 | * */ 26 | isOnline?: boolean; 27 | }; 28 | -------------------------------------------------------------------------------- /lib/Types/LabelAssociation.d.ts: -------------------------------------------------------------------------------- 1 | /** Association type */ 2 | export declare enum LabelAssociationType { 3 | Chat = "label_jid", 4 | Message = "label_message" 5 | } 6 | export type LabelAssociationTypes = `${LabelAssociationType}`; 7 | /** Association for chat */ 8 | export interface ChatLabelAssociation { 9 | type: LabelAssociationType.Chat; 10 | chatId: string; 11 | labelId: string; 12 | } 13 | /** Association for message */ 14 | export interface MessageLabelAssociation { 15 | type: LabelAssociationType.Message; 16 | chatId: string; 17 | messageId: string; 18 | labelId: string; 19 | } 20 | export type LabelAssociation = ChatLabelAssociation | MessageLabelAssociation; 21 | /** Body for add/remove chat label association action */ 22 | export interface ChatLabelAssociationActionBody { 23 | labelId: string; 24 | } 25 | /** body for add/remove message label association action */ 26 | export interface MessageLabelAssociationActionBody { 27 | labelId: string; 28 | messageId: string; 29 | } 30 | -------------------------------------------------------------------------------- /lib/Utils/noise-handler.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Logger } from 'pino'; 3 | import { proto } from '../../WAProto'; 4 | import { KeyPair } from '../Types'; 5 | import { BinaryNode } from '../WABinary'; 6 | export declare const makeNoiseHandler: ({ keyPair: { private: privateKey, public: publicKey }, NOISE_HEADER, mobile, logger, routingInfo }: { 7 | keyPair: KeyPair; 8 | NOISE_HEADER: Uint8Array; 9 | mobile: boolean; 10 | logger: Logger; 11 | routingInfo?: Buffer | undefined; 12 | }) => { 13 | encrypt: (plaintext: Uint8Array) => Buffer; 14 | decrypt: (ciphertext: Uint8Array) => Buffer; 15 | authenticate: (data: Uint8Array) => void; 16 | mixIntoKey: (data: Uint8Array) => void; 17 | finishInit: () => void; 18 | processHandshake: ({ serverHello }: proto.HandshakeMessage, noiseKey: KeyPair) => Buffer; 19 | encodeFrame: (data: Buffer | Uint8Array) => Buffer; 20 | decodeFrame: (newData: Buffer | Uint8Array, onFrame: (buff: Uint8Array | BinaryNode) => void) => void; 21 | }; 22 | -------------------------------------------------------------------------------- /lib/WABinary/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __exportStar = (this && this.__exportStar) || function(m, exports) { 14 | for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); 15 | }; 16 | Object.defineProperty(exports, "__esModule", { value: true }); 17 | __exportStar(require("./encode"), exports); 18 | __exportStar(require("./decode"), exports); 19 | __exportStar(require("./generic-utils"), exports); 20 | __exportStar(require("./jid-utils"), exports); 21 | __exportStar(require("./types"), exports); 22 | -------------------------------------------------------------------------------- /lib/WAM/constants.d.ts: -------------------------------------------------------------------------------- 1 | export declare const WEB_EVENTS: Event[]; 2 | export declare const WEB_GLOBALS: Global[]; 3 | export declare const FLAG_BYTE = 8, FLAG_GLOBAL = 0, FLAG_EVENT = 1, FLAG_FIELD = 2, FLAG_EXTENDED = 4; 4 | export type Event = { 5 | name: string; 6 | id: number; 7 | props: { 8 | [key: string]: [number, string | { 9 | [key: string]: number; 10 | }]; 11 | }; 12 | weight: number; 13 | wamChannel: string; 14 | privateStatsIdInt: number; 15 | }; 16 | export type Global = { 17 | name: string; 18 | id: number; 19 | type: string | { 20 | [key: string]: number; 21 | }; 22 | validator?: string; 23 | channels: string[]; 24 | }; 25 | type EventByName = Extract; 28 | export type EventInputType = { 29 | [key in Event['name']]: { 30 | props: { 31 | [k in keyof EventByName['props']]: any; 32 | }; 33 | globals: { 34 | [x: string]: any; 35 | }; 36 | }; 37 | } & {}; 38 | export {}; 39 | -------------------------------------------------------------------------------- /WASignalGroup/sender_message_key.js: -------------------------------------------------------------------------------- 1 | const { deriveSecrets } = require('libsignal/src/crypto'); 2 | class SenderMessageKey { 3 | iteration = 0; 4 | 5 | iv = Buffer.alloc(0); 6 | 7 | cipherKey = Buffer.alloc(0); 8 | 9 | seed = Buffer.alloc(0); 10 | 11 | constructor(iteration, seed) { 12 | const derivative = deriveSecrets(seed, Buffer.alloc(32), Buffer.from('WhisperGroup')); 13 | const keys = new Uint8Array(32); 14 | keys.set(new Uint8Array(derivative[0].slice(16))); 15 | keys.set(new Uint8Array(derivative[1].slice(0, 16)), 16); 16 | this.iv = Buffer.from(derivative[0].slice(0, 16)); 17 | this.cipherKey = Buffer.from(keys.buffer); 18 | 19 | this.iteration = iteration; 20 | this.seed = seed; 21 | } 22 | 23 | getIteration() { 24 | return this.iteration; 25 | } 26 | 27 | getIv() { 28 | return this.iv; 29 | } 30 | 31 | getCipherKey() { 32 | return this.cipherKey; 33 | } 34 | 35 | getSeed() { 36 | return this.seed; 37 | } 38 | } 39 | module.exports = SenderMessageKey; -------------------------------------------------------------------------------- /lib/Utils/auth-utils.d.ts: -------------------------------------------------------------------------------- 1 | import type { Logger } from 'pino'; 2 | import type { AuthenticationCreds, CacheStore, SignalKeyStore, SignalKeyStoreWithTransaction, TransactionCapabilityOptions } from '../Types'; 3 | /** 4 | * Adds caching capability to a SignalKeyStore 5 | * @param store the store to add caching to 6 | * @param logger to log trace events 7 | * @param _cache cache store to use 8 | */ 9 | export declare function makeCacheableSignalKeyStore(store: SignalKeyStore, logger: Logger, _cache?: CacheStore): SignalKeyStore; 10 | /** 11 | * Adds DB like transaction capability (https://en.wikipedia.org/wiki/Database_transaction) to the SignalKeyStore, 12 | * this allows batch read & write operations & improves the performance of the lib 13 | * @param state the key store to apply this capability to 14 | * @param logger logger to log events 15 | * @returns SignalKeyStore with transaction capability 16 | */ 17 | export declare const addTransactionCapability: (state: SignalKeyStore, logger: Logger, { maxCommitRetries, delayBetweenTriesMs }: TransactionCapabilityOptions) => SignalKeyStoreWithTransaction; 18 | export declare const initAuthCreds: () => AuthenticationCreds; 19 | -------------------------------------------------------------------------------- /lib/WABinary/generic-utils.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { proto } from '../../WAProto'; 3 | import { BinaryNode } from './types'; 4 | export declare const getBinaryNodeChildren: (node: BinaryNode | undefined, childTag: string) => BinaryNode[]; 5 | export declare const getAllBinaryNodeChildren: ({ content }: BinaryNode) => BinaryNode[]; 6 | export declare const getBinaryNodeChild: (node: BinaryNode | undefined, childTag: string) => BinaryNode | undefined; 7 | export declare const getBinaryNodeChildBuffer: (node: BinaryNode | undefined, childTag: string) => Uint8Array | Buffer | undefined; 8 | export declare const getBinaryNodeChildString: (node: BinaryNode | undefined, childTag: string) => string | undefined; 9 | export declare const getBinaryNodeChildUInt: (node: BinaryNode, childTag: string, length: number) => number | undefined; 10 | export declare const assertNodeErrorFree: (node: BinaryNode) => void; 11 | export declare const reduceBinaryNodeToDictionary: (node: BinaryNode, tag: string) => { 12 | [_: string]: string; 13 | }; 14 | export declare const getBinaryNodeMessages: ({ content }: BinaryNode) => proto.WebMessageInfo[]; 15 | export declare function binaryNodeToString(node: BinaryNode | BinaryNode['content'], i?: number): any; 16 | -------------------------------------------------------------------------------- /lib/Utils/business.d.ts: -------------------------------------------------------------------------------- 1 | import { CatalogCollection, OrderDetails, Product, ProductCreate, ProductUpdate, WAMediaUpload, WAMediaUploadFunction } from '../Types'; 2 | import { BinaryNode } from '../WABinary'; 3 | export declare const parseCatalogNode: (node: BinaryNode) => { 4 | products: Product[]; 5 | nextPageCursor: string | undefined; 6 | }; 7 | export declare const parseCollectionsNode: (node: BinaryNode) => { 8 | collections: CatalogCollection[]; 9 | }; 10 | export declare const parseOrderDetailsNode: (node: BinaryNode) => OrderDetails; 11 | export declare const toProductNode: (productId: string | undefined, product: ProductCreate | ProductUpdate) => BinaryNode; 12 | export declare const parseProductNode: (productNode: BinaryNode) => Product; 13 | /** 14 | * Uploads images not already uploaded to WA's servers 15 | */ 16 | export declare function uploadingNecessaryImagesOfProduct(product: T, waUploadToServer: WAMediaUploadFunction, timeoutMs?: number): Promise; 17 | /** 18 | * Uploads images not already uploaded to WA's servers 19 | */ 20 | export declare const uploadingNecessaryImages: (images: WAMediaUpload[], waUploadToServer: WAMediaUploadFunction, timeoutMs?: number) => Promise<{ 21 | url: string; 22 | }[]>; 23 | -------------------------------------------------------------------------------- /WASignalGroup/sender_chain_key.js: -------------------------------------------------------------------------------- 1 | const SenderMessageKey = require('./sender_message_key'); 2 | //const HKDF = require('./hkdf'); 3 | const crypto = require('libsignal/src/crypto'); 4 | 5 | class SenderChainKey { 6 | MESSAGE_KEY_SEED = Buffer.from([0x01]); 7 | 8 | CHAIN_KEY_SEED = Buffer.from([0x02]); 9 | 10 | iteration = 0; 11 | 12 | chainKey = Buffer.alloc(0); 13 | 14 | constructor(iteration, chainKey) { 15 | this.iteration = iteration; 16 | this.chainKey = chainKey; 17 | } 18 | 19 | getIteration() { 20 | return this.iteration; 21 | } 22 | 23 | getSenderMessageKey() { 24 | return new SenderMessageKey( 25 | this.iteration, 26 | this.getDerivative(this.MESSAGE_KEY_SEED, this.chainKey) 27 | ); 28 | } 29 | 30 | getNext() { 31 | return new SenderChainKey( 32 | this.iteration + 1, 33 | this.getDerivative(this.CHAIN_KEY_SEED, this.chainKey) 34 | ); 35 | } 36 | 37 | getSeed() { 38 | return typeof this.chainKey === 'string' ? Buffer.from(this.chainKey, 'base64') : this.chainKey; 39 | } 40 | 41 | getDerivative(seed, key) { 42 | key = typeof key === 'string' ? Buffer.from(key, 'base64') : key; 43 | const hash = crypto.calculateMAC(key, seed); 44 | //const hash = new Hash().hmac_hash(key, seed, 'sha256', ''); 45 | 46 | return hash; 47 | } 48 | } 49 | 50 | module.exports = SenderChainKey; -------------------------------------------------------------------------------- /lib/Types/Label.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.LabelColor = void 0; 4 | /** WhatsApp has 20 predefined colors */ 5 | var LabelColor; 6 | (function (LabelColor) { 7 | LabelColor[LabelColor["Color1"] = 0] = "Color1"; 8 | LabelColor[LabelColor["Color2"] = 1] = "Color2"; 9 | LabelColor[LabelColor["Color3"] = 2] = "Color3"; 10 | LabelColor[LabelColor["Color4"] = 3] = "Color4"; 11 | LabelColor[LabelColor["Color5"] = 4] = "Color5"; 12 | LabelColor[LabelColor["Color6"] = 5] = "Color6"; 13 | LabelColor[LabelColor["Color7"] = 6] = "Color7"; 14 | LabelColor[LabelColor["Color8"] = 7] = "Color8"; 15 | LabelColor[LabelColor["Color9"] = 8] = "Color9"; 16 | LabelColor[LabelColor["Color10"] = 9] = "Color10"; 17 | LabelColor[LabelColor["Color11"] = 10] = "Color11"; 18 | LabelColor[LabelColor["Color12"] = 11] = "Color12"; 19 | LabelColor[LabelColor["Color13"] = 12] = "Color13"; 20 | LabelColor[LabelColor["Color14"] = 13] = "Color14"; 21 | LabelColor[LabelColor["Color15"] = 14] = "Color15"; 22 | LabelColor[LabelColor["Color16"] = 15] = "Color16"; 23 | LabelColor[LabelColor["Color17"] = 16] = "Color17"; 24 | LabelColor[LabelColor["Color18"] = 17] = "Color18"; 25 | LabelColor[LabelColor["Color19"] = 18] = "Color19"; 26 | LabelColor[LabelColor["Color20"] = 19] = "Color20"; 27 | })(LabelColor = exports.LabelColor || (exports.LabelColor = {})); 28 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __exportStar = (this && this.__exportStar) || function(m, exports) { 14 | for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); 15 | }; 16 | var __importDefault = (this && this.__importDefault) || function (mod) { 17 | return (mod && mod.__esModule) ? mod : { "default": mod }; 18 | }; 19 | Object.defineProperty(exports, "__esModule", { value: true }); 20 | exports.makeWASocket = void 0; 21 | const Socket_1 = __importDefault(require("./Socket")); 22 | exports.makeWASocket = Socket_1.default; 23 | __exportStar(require("../WAProto"), exports); 24 | __exportStar(require("./Utils"), exports); 25 | __exportStar(require("./Types"), exports); 26 | __exportStar(require("./Store"), exports); 27 | __exportStar(require("./Defaults"), exports); 28 | __exportStar(require("./WABinary"), exports); 29 | __exportStar(require("./WAM"), exports); 30 | exports.default = Socket_1.default; 31 | -------------------------------------------------------------------------------- /lib/Utils/make-mutex.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.makeKeyedMutex = exports.makeMutex = void 0; 4 | const makeMutex = () => { 5 | let task = Promise.resolve(); 6 | let taskTimeout; 7 | return { 8 | mutex(code) { 9 | task = (async () => { 10 | // wait for the previous task to complete 11 | // if there is an error, we swallow so as to not block the queue 12 | try { 13 | await task; 14 | } 15 | catch (_a) { } 16 | try { 17 | // execute the current task 18 | const result = await code(); 19 | return result; 20 | } 21 | finally { 22 | clearTimeout(taskTimeout); 23 | } 24 | })(); 25 | // we replace the existing task, appending the new piece of execution to it 26 | // so the next task will have to wait for this one to finish 27 | return task; 28 | }, 29 | }; 30 | }; 31 | exports.makeMutex = makeMutex; 32 | const makeKeyedMutex = () => { 33 | const map = {}; 34 | return { 35 | mutex(key, task) { 36 | if (!map[key]) { 37 | map[key] = (0, exports.makeMutex)(); 38 | } 39 | return map[key].mutex(task); 40 | } 41 | }; 42 | }; 43 | exports.makeKeyedMutex = makeKeyedMutex; 44 | -------------------------------------------------------------------------------- /lib/Utils/event-buffer.d.ts: -------------------------------------------------------------------------------- 1 | import { Logger } from 'pino'; 2 | import { BaileysEventEmitter, BaileysEventMap } from '../Types'; 3 | /** 4 | * A map that contains a list of all events that have been triggered 5 | * 6 | * Note, this can contain different type of events 7 | * this can make processing events extremely efficient -- since everything 8 | * can be done in a single transaction 9 | */ 10 | type BaileysEventData = Partial; 11 | type BaileysBufferableEventEmitter = BaileysEventEmitter & { 12 | /** Use to process events in a batch */ 13 | process(handler: (events: BaileysEventData) => void | Promise): (() => void); 14 | /** 15 | * starts buffering events, call flush() to release them 16 | * */ 17 | buffer(): void; 18 | /** buffers all events till the promise completes */ 19 | createBufferedFunction(work: (...args: A) => Promise): ((...args: A) => Promise); 20 | /** 21 | * flushes all buffered events 22 | * @param force if true, will flush all data regardless of any pending buffers 23 | * @returns returns true if the flush actually happened, otherwise false 24 | */ 25 | flush(force?: boolean): boolean; 26 | /** is there an ongoing buffer */ 27 | isBuffering(): boolean; 28 | }; 29 | /** 30 | * The event buffer logically consolidates different events into a single event 31 | * making the data processing more efficient. 32 | * @param ev the baileys event emitter 33 | */ 34 | export declare const makeEventBuffer: (logger: Logger) => BaileysBufferableEventEmitter; 35 | export {}; 36 | -------------------------------------------------------------------------------- /WASignalGroup/sender_key_name.js: -------------------------------------------------------------------------------- 1 | function isNull(str) { 2 | return str === null || str.value === ''; 3 | } 4 | 5 | /** 6 | * java String hashCode 的实现 7 | * @param strKey 8 | * @return intValue 9 | */ 10 | function intValue(num) { 11 | const MAX_VALUE = 0x7fffffff; 12 | const MIN_VALUE = -0x80000000; 13 | if (num > MAX_VALUE || num < MIN_VALUE) { 14 | // eslint-disable-next-line 15 | return (num &= 0xffffffff); 16 | } 17 | return num; 18 | } 19 | 20 | function hashCode(strKey) { 21 | let hash = 0; 22 | if (!isNull(strKey)) { 23 | for (let i = 0; i < strKey.length; i++) { 24 | hash = hash * 31 + strKey.charCodeAt(i); 25 | hash = intValue(hash); 26 | } 27 | } 28 | return hash; 29 | } 30 | 31 | /** 32 | * 将js页面的number类型转换为java的int类型 33 | * @param num 34 | * @return intValue 35 | */ 36 | 37 | class SenderKeyName { 38 | constructor(groupId, sender) { 39 | this.groupId = groupId; 40 | this.sender = sender; 41 | } 42 | 43 | getGroupId() { 44 | return this.groupId; 45 | } 46 | 47 | getSender() { 48 | return this.sender; 49 | } 50 | 51 | serialize() { 52 | return `${this.groupId}::${this.sender.id}::${this.sender.deviceId}`; 53 | } 54 | 55 | toString() { 56 | return this.serialize(); 57 | } 58 | 59 | equals(other) { 60 | if (other === null) return false; 61 | if (!(other instanceof SenderKeyName)) return false; 62 | return this.groupId === other.groupId && this.sender.toString() === other.sender.toString(); 63 | } 64 | 65 | hashCode() { 66 | return hashCode(this.groupId) ^ hashCode(this.sender.toString()); 67 | } 68 | } 69 | 70 | module.exports = SenderKeyName; -------------------------------------------------------------------------------- /lib/Types/Newsletter.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.QueryIds = exports.XWAPaths = exports.MexOperations = void 0; 4 | var MexOperations; 5 | (function (MexOperations) { 6 | MexOperations["PROMOTE"] = "NotificationNewsletterAdminPromote"; 7 | MexOperations["DEMOTE"] = "NotificationNewsletterAdminDemote"; 8 | MexOperations["UPDATE"] = "NotificationNewsletterUpdate"; 9 | })(MexOperations = exports.MexOperations || (exports.MexOperations = {})); 10 | var XWAPaths; 11 | (function (XWAPaths) { 12 | XWAPaths["PROMOTE"] = "xwa2_notify_newsletter_admin_promote"; 13 | XWAPaths["DEMOTE"] = "xwa2_notify_newsletter_admin_demote"; 14 | XWAPaths["ADMIN_COUNT"] = "xwa2_newsletter_admin"; 15 | XWAPaths["CREATE"] = "xwa2_newsletter_create"; 16 | XWAPaths["NEWSLETTER"] = "xwa2_newsletter"; 17 | XWAPaths["METADATA_UPDATE"] = "xwa2_notify_newsletter_on_metadata_update"; 18 | })(XWAPaths = exports.XWAPaths || (exports.XWAPaths = {})); 19 | var QueryIds; 20 | (function (QueryIds) { 21 | QueryIds["JOB_MUTATION"] = "7150902998257522"; 22 | QueryIds["METADATA"] = "6620195908089573"; 23 | QueryIds["UNFOLLOW"] = "7238632346214362"; 24 | QueryIds["FOLLOW"] = "7871414976211147"; 25 | QueryIds["UNMUTE"] = "7337137176362961"; 26 | QueryIds["MUTE"] = "25151904754424642"; 27 | QueryIds["CREATE"] = "6996806640408138"; 28 | QueryIds["ADMIN_COUNT"] = "7130823597031706"; 29 | QueryIds["CHANGE_OWNER"] = "7341777602580933"; 30 | QueryIds["DELETE"] = "8316537688363079"; 31 | QueryIds["DEMOTE"] = "6551828931592903"; 32 | })(QueryIds = exports.QueryIds || (exports.QueryIds = {})); 33 | -------------------------------------------------------------------------------- /lib/Types/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from './Auth'; 2 | export * from './GroupMetadata'; 3 | export * from './Chat'; 4 | export * from './Contact'; 5 | export * from './State'; 6 | export * from './Message'; 7 | export * from './Newsletter'; 8 | export * from './Socket'; 9 | export * from './Events'; 10 | export * from './Product'; 11 | export * from './Call'; 12 | export * from './Signal'; 13 | import { AuthenticationState } from './Auth'; 14 | import { SocketConfig } from './Socket'; 15 | export type UserFacingSocketConfig = Partial & { 16 | auth: AuthenticationState; 17 | }; 18 | export declare enum DisconnectReason { 19 | connectionClosed = 428, 20 | connectionLost = 408, 21 | connectionReplaced = 440, 22 | timedOut = 408, 23 | loggedOut = 401, 24 | badSession = 500, 25 | restartRequired = 515, 26 | multideviceMismatch = 411, 27 | forbidden = 403, 28 | unavailableService = 503 29 | } 30 | export type WAInitResponse = { 31 | ref: string; 32 | ttl: number; 33 | status: 200; 34 | }; 35 | export type WABusinessHoursConfig = { 36 | day_of_week: string; 37 | mode: string; 38 | open_time?: number; 39 | close_time?: number; 40 | }; 41 | export type WABusinessProfile = { 42 | description: string; 43 | email: string | undefined; 44 | business_hours: { 45 | timezone?: string; 46 | config?: WABusinessHoursConfig[]; 47 | business_config?: WABusinessHoursConfig[]; 48 | }; 49 | website: string[]; 50 | category?: string; 51 | wid?: string; 52 | address?: string; 53 | }; 54 | export type CurveKeyPair = { 55 | private: Uint8Array; 56 | public: Uint8Array; 57 | }; 58 | -------------------------------------------------------------------------------- /lib/Utils/signal.d.ts: -------------------------------------------------------------------------------- 1 | import { SignalRepository } from '../Types'; 2 | import { AuthenticationCreds, AuthenticationState, KeyPair, SignalIdentity, SignalKeyStore, SignedKeyPair } from '../Types/Auth'; 3 | import { BinaryNode, JidWithDevice } from '../WABinary'; 4 | export declare const createSignalIdentity: (wid: string, accountSignatureKey: Uint8Array) => SignalIdentity; 5 | export declare const getPreKeys: ({ get }: SignalKeyStore, min: number, limit: number) => Promise<{ 6 | [id: string]: KeyPair; 7 | }>; 8 | export declare const generateOrGetPreKeys: (creds: AuthenticationCreds, range: number) => { 9 | newPreKeys: { 10 | [id: number]: KeyPair; 11 | }; 12 | lastPreKeyId: number; 13 | preKeysRange: readonly [number, number]; 14 | }; 15 | export declare const xmppSignedPreKey: (key: SignedKeyPair) => BinaryNode; 16 | export declare const xmppPreKey: (pair: KeyPair, id: number) => BinaryNode; 17 | export declare const parseAndInjectE2ESessions: (node: BinaryNode, repository: SignalRepository) => Promise; 18 | export declare const extractDeviceJids: (result: BinaryNode, myJid: string, excludeZeroDevices: boolean) => JidWithDevice[]; 19 | /** 20 | * get the next N keys for upload or processing 21 | * @param count number of pre-keys to get or generate 22 | */ 23 | export declare const getNextPreKeys: ({ creds, keys }: AuthenticationState, count: number) => Promise<{ 24 | update: Partial; 25 | preKeys: { 26 | [id: string]: KeyPair; 27 | }; 28 | }>; 29 | export declare const getNextPreKeysNode: (state: AuthenticationState, count: number) => Promise<{ 30 | update: Partial; 31 | node: BinaryNode; 32 | }>; 33 | -------------------------------------------------------------------------------- /lib/Utils/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __exportStar = (this && this.__exportStar) || function(m, exports) { 14 | for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); 15 | }; 16 | Object.defineProperty(exports, "__esModule", { value: true }); 17 | __exportStar(require("./generics"), exports); 18 | __exportStar(require("./decode-wa-message"), exports); 19 | __exportStar(require("./messages"), exports); 20 | __exportStar(require("./messages-media"), exports); 21 | __exportStar(require("./validate-connection"), exports); 22 | __exportStar(require("./crypto"), exports); 23 | __exportStar(require("./signal"), exports); 24 | __exportStar(require("./noise-handler"), exports); 25 | __exportStar(require("./history"), exports); 26 | __exportStar(require("./chat-utils"), exports); 27 | __exportStar(require("./lt-hash"), exports); 28 | __exportStar(require("./auth-utils"), exports); 29 | __exportStar(require("./baileys-event-stream"), exports); 30 | __exportStar(require("./use-multi-file-auth-state"), exports); 31 | __exportStar(require("./link-preview"), exports); 32 | __exportStar(require("./event-buffer"), exports); 33 | __exportStar(require("./process-message"), exports); 34 | -------------------------------------------------------------------------------- /lib/WABinary/jid-utils.d.ts: -------------------------------------------------------------------------------- 1 | export declare const S_WHATSAPP_NET = "@s.whatsapp.net"; 2 | export declare const OFFICIAL_BIZ_JID = "16505361212@c.us"; 3 | export declare const SERVER_JID = "server@c.us"; 4 | export declare const PSA_WID = "0@c.us"; 5 | export declare const STORIES_JID = "status@broadcast"; 6 | export type JidServer = 'c.us' | 'g.us' | 'broadcast' | 's.whatsapp.net' | 'call' | 'lid' | 'newsletter'; 7 | export type JidWithDevice = { 8 | user: string; 9 | device?: number; 10 | }; 11 | export type FullJid = JidWithDevice & { 12 | server: JidServer | string; 13 | domainType?: number; 14 | }; 15 | export declare const jidEncode: (user: string | number | null, server: JidServer, device?: number, agent?: number) => string; 16 | export declare const jidDecode: (jid: string | undefined) => FullJid | undefined; 17 | /** is the jid a user */ 18 | export declare const areJidsSameUser: (jid1: string | undefined, jid2: string | undefined) => boolean; 19 | /** is the jid a user */ 20 | export declare const isJidUser: (jid: string | undefined) => boolean | undefined; 21 | /** is the jid a group */ 22 | export declare const isLidUser: (jid: string | undefined) => boolean | undefined; 23 | /** is the jid a broadcast */ 24 | export declare const isJidBroadcast: (jid: string | undefined) => boolean | undefined; 25 | /** is the jid a group */ 26 | export declare const isJidGroup: (jid: string | undefined) => boolean | undefined; 27 | /** is the jid the status broadcast */ 28 | export declare const isJidStatusBroadcast: (jid: string) => boolean; 29 | /** is the jid the newsletter */ 30 | export declare const isJidNewsLetter: (jid: string | undefined) => boolean | undefined; 31 | export declare const jidNormalizedUser: (jid: string | undefined) => string; 32 | -------------------------------------------------------------------------------- /lib/Types/Signal.d.ts: -------------------------------------------------------------------------------- 1 | import { proto } from '../../WAProto'; 2 | type DecryptGroupSignalOpts = { 3 | group: string; 4 | authorJid: string; 5 | msg: Uint8Array; 6 | }; 7 | type ProcessSenderKeyDistributionMessageOpts = { 8 | item: proto.Message.ISenderKeyDistributionMessage; 9 | authorJid: string; 10 | }; 11 | type DecryptSignalProtoOpts = { 12 | jid: string; 13 | type: 'pkmsg' | 'msg'; 14 | ciphertext: Uint8Array; 15 | }; 16 | type EncryptMessageOpts = { 17 | jid: string; 18 | data: Uint8Array; 19 | }; 20 | type EncryptGroupMessageOpts = { 21 | group: string; 22 | data: Uint8Array; 23 | meId: string; 24 | }; 25 | type PreKey = { 26 | keyId: number; 27 | publicKey: Uint8Array; 28 | }; 29 | type SignedPreKey = PreKey & { 30 | signature: Uint8Array; 31 | }; 32 | type E2ESession = { 33 | registrationId: number; 34 | identityKey: Uint8Array; 35 | signedPreKey: SignedPreKey; 36 | preKey: PreKey; 37 | }; 38 | type E2ESessionOpts = { 39 | jid: string; 40 | session: E2ESession; 41 | }; 42 | export type SignalRepository = { 43 | decryptGroupMessage(opts: DecryptGroupSignalOpts): Promise; 44 | processSenderKeyDistributionMessage(opts: ProcessSenderKeyDistributionMessageOpts): Promise; 45 | decryptMessage(opts: DecryptSignalProtoOpts): Promise; 46 | encryptMessage(opts: EncryptMessageOpts): Promise<{ 47 | type: 'pkmsg' | 'msg'; 48 | ciphertext: Uint8Array; 49 | }>; 50 | encryptGroupMessage(opts: EncryptGroupMessageOpts): Promise<{ 51 | senderKeyDistributionMessage: Uint8Array; 52 | ciphertext: Uint8Array; 53 | }>; 54 | injectE2ESession(opts: E2ESessionOpts): Promise; 55 | jidToSignalProtocolAddress(jid: string): string; 56 | }; 57 | export {}; 58 | -------------------------------------------------------------------------------- /WASignalGroup/sender_key_record.js: -------------------------------------------------------------------------------- 1 | const SenderKeyState = require('./sender_key_state'); 2 | 3 | class SenderKeyRecord { 4 | MAX_STATES = 5; 5 | 6 | constructor(serialized) { 7 | this.senderKeyStates = []; 8 | 9 | if (serialized) { 10 | const list = serialized; 11 | for (let i = 0; i < list.length; i++) { 12 | const structure = list[i]; 13 | this.senderKeyStates.push( 14 | new SenderKeyState(null, null, null, null, null, null, structure) 15 | ); 16 | } 17 | } 18 | } 19 | 20 | isEmpty() { 21 | return this.senderKeyStates.length === 0; 22 | } 23 | 24 | getSenderKeyState(keyId) { 25 | if (!keyId && this.senderKeyStates.length) return this.senderKeyStates[this.senderKeyStates.length - 1]; 26 | for (let i = 0; i < this.senderKeyStates.length; i++) { 27 | const state = this.senderKeyStates[i]; 28 | if (state.getKeyId() === keyId) { 29 | return state; 30 | } 31 | } 32 | } 33 | 34 | addSenderKeyState(id, iteration, chainKey, signatureKey) { 35 | this.senderKeyStates.push(new SenderKeyState(id, iteration, chainKey, null, signatureKey)); 36 | if (this.senderKeyStates.length > 5) { 37 | this.senderKeyStates.shift() 38 | } 39 | } 40 | 41 | setSenderKeyState(id, iteration, chainKey, keyPair) { 42 | this.senderKeyStates.length = 0; 43 | this.senderKeyStates.push(new SenderKeyState(id, iteration, chainKey, keyPair)); 44 | } 45 | 46 | serialize() { 47 | const recordStructure = []; 48 | for (let i = 0; i < this.senderKeyStates.length; i++) { 49 | const senderKeyState = this.senderKeyStates[i]; 50 | recordStructure.push(senderKeyState.getStructure()); 51 | } 52 | return recordStructure; 53 | } 54 | } 55 | 56 | module.exports = SenderKeyRecord; -------------------------------------------------------------------------------- /lib/Utils/lt-hash.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.LT_HASH_ANTI_TAMPERING = void 0; 4 | const crypto_1 = require("./crypto"); 5 | /** 6 | * LT Hash is a summation based hash algorithm that maintains the integrity of a piece of data 7 | * over a series of mutations. You can add/remove mutations and it'll return a hash equal to 8 | * if the same series of mutations was made sequentially. 9 | */ 10 | const o = 128; 11 | class d { 12 | constructor(e) { 13 | this.salt = e; 14 | } 15 | add(e, t) { 16 | var r = this; 17 | for (const item of t) { 18 | e = r._addSingle(e, item); 19 | } 20 | return e; 21 | } 22 | subtract(e, t) { 23 | var r = this; 24 | for (const item of t) { 25 | e = r._subtractSingle(e, item); 26 | } 27 | return e; 28 | } 29 | subtractThenAdd(e, t, r) { 30 | var n = this; 31 | return n.add(n.subtract(e, r), t); 32 | } 33 | _addSingle(e, t) { 34 | var r = this; 35 | const n = new Uint8Array((0, crypto_1.hkdf)(Buffer.from(t), o, { info: r.salt })).buffer; 36 | return r.performPointwiseWithOverflow(e, n, ((e, t) => e + t)); 37 | } 38 | _subtractSingle(e, t) { 39 | var r = this; 40 | const n = new Uint8Array((0, crypto_1.hkdf)(Buffer.from(t), o, { info: r.salt })).buffer; 41 | return r.performPointwiseWithOverflow(e, n, ((e, t) => e - t)); 42 | } 43 | performPointwiseWithOverflow(e, t, r) { 44 | const n = new DataView(e), i = new DataView(t), a = new ArrayBuffer(n.byteLength), s = new DataView(a); 45 | for (let e = 0; e < n.byteLength; e += 2) { 46 | s.setUint16(e, r(n.getUint16(e, !0), i.getUint16(e, !0)), !0); 47 | } 48 | return a; 49 | } 50 | } 51 | exports.LT_HASH_ANTI_TAMPERING = new d('WhatsApp Patch Integrity'); 52 | -------------------------------------------------------------------------------- /lib/Types/GroupMetadata.d.ts: -------------------------------------------------------------------------------- 1 | import { Contact } from './Contact'; 2 | export type GroupParticipant = (Contact & { 3 | isAdmin?: boolean; 4 | isSuperAdmin?: boolean; 5 | admin?: 'admin' | 'superadmin' | null; 6 | }); 7 | export type ParticipantAction = 'add' | 'remove' | 'promote' | 'demote'; 8 | export interface GroupMetadata { 9 | id: string; 10 | owner: string | undefined; 11 | subject: string; 12 | /** group subject owner */ 13 | subjectOwner?: string; 14 | /** group subject modification date */ 15 | subjectTime?: number; 16 | creation?: number; 17 | desc?: string; 18 | descOwner?: string; 19 | descId?: string; 20 | /** if this group is part of a community, it returns the jid of the community to which it belongs */ 21 | linkedParent?: string; 22 | /** is set when the group only allows admins to change group settings */ 23 | restrict?: boolean; 24 | /** is set when the group only allows admins to write messages */ 25 | announce?: boolean; 26 | /** is set when the group also allows members to add participants */ 27 | memberAddMode?: boolean; 28 | /** Request approval to join the group */ 29 | joinApprovalMode?: boolean; 30 | /** is this a community */ 31 | isCommunity?: boolean; 32 | /** is this the announce of a community */ 33 | isCommunityAnnounce?: boolean; 34 | /** number of group participants */ 35 | size?: number; 36 | participants: GroupParticipant[]; 37 | ephemeralDuration?: number; 38 | inviteCode?: string; 39 | /** the person who added you to group or changed some setting in group */ 40 | author?: string; 41 | } 42 | export interface WAGroupCreateResponse { 43 | status: number; 44 | gid?: string; 45 | participants?: [{ 46 | [key: string]: {}; 47 | }]; 48 | } 49 | export interface GroupModificationResponse { 50 | status: number; 51 | participants?: { 52 | [key: string]: {}; 53 | }; 54 | } 55 | -------------------------------------------------------------------------------- /WASignalGroup/group_session_builder.js: -------------------------------------------------------------------------------- 1 | //const utils = require('../../common/utils'); 2 | const SenderKeyDistributionMessage = require('./sender_key_distribution_message'); 3 | 4 | const keyhelper = require("./keyhelper"); 5 | class GroupSessionBuilder { 6 | constructor(senderKeyStore) { 7 | this.senderKeyStore = senderKeyStore; 8 | } 9 | 10 | async process(senderKeyName, senderKeyDistributionMessage) { 11 | //console.log('GroupSessionBuilder process', senderKeyName, senderKeyDistributionMessage); 12 | const senderKeyRecord = await this.senderKeyStore.loadSenderKey(senderKeyName); 13 | senderKeyRecord.addSenderKeyState( 14 | senderKeyDistributionMessage.getId(), 15 | senderKeyDistributionMessage.getIteration(), 16 | senderKeyDistributionMessage.getChainKey(), 17 | senderKeyDistributionMessage.getSignatureKey() 18 | ); 19 | await this.senderKeyStore.storeSenderKey(senderKeyName, senderKeyRecord); 20 | } 21 | 22 | // [{"senderKeyId":1742199468,"senderChainKey":{"iteration":0,"seed":"yxMY9VFQcXEP34olRAcGCtsgx1XoKsHfDIh+1ea4HAQ="},"senderSigningKey":{"public":""}}] 23 | async create(senderKeyName) { 24 | const senderKeyRecord = await this.senderKeyStore.loadSenderKey(senderKeyName); 25 | //console.log('GroupSessionBuilder create session', senderKeyName, senderKeyRecord); 26 | 27 | if (senderKeyRecord.isEmpty()) { 28 | const keyId = keyhelper.generateSenderKeyId(); 29 | const senderKey = keyhelper.generateSenderKey(); 30 | const signingKey = keyhelper.generateSenderSigningKey(); 31 | 32 | senderKeyRecord.setSenderKeyState(keyId, 0, senderKey, signingKey); 33 | await this.senderKeyStore.storeSenderKey(senderKeyName, senderKeyRecord); 34 | } 35 | 36 | const state = senderKeyRecord.getSenderKeyState(); 37 | 38 | return new SenderKeyDistributionMessage( 39 | state.getKeyId(), 40 | state.getSenderChainKey().getIteration(), 41 | state.getSenderChainKey().getSeed(), 42 | state.getSigningKeyPublic() 43 | ); 44 | } 45 | } 46 | module.exports = GroupSessionBuilder; -------------------------------------------------------------------------------- /lib/Types/Product.d.ts: -------------------------------------------------------------------------------- 1 | import { WAMediaUpload } from './Message'; 2 | export type CatalogResult = { 3 | data: { 4 | paging: { 5 | cursors: { 6 | before: string; 7 | after: string; 8 | }; 9 | }; 10 | data: any[]; 11 | }; 12 | }; 13 | export type ProductCreateResult = { 14 | data: { 15 | product: {}; 16 | }; 17 | }; 18 | export type CatalogStatus = { 19 | status: string; 20 | canAppeal: boolean; 21 | }; 22 | export type CatalogCollection = { 23 | id: string; 24 | name: string; 25 | products: Product[]; 26 | status: CatalogStatus; 27 | }; 28 | export type ProductAvailability = 'in stock'; 29 | export type ProductBase = { 30 | name: string; 31 | retailerId?: string; 32 | url?: string; 33 | description: string; 34 | price: number; 35 | currency: string; 36 | isHidden?: boolean; 37 | }; 38 | export type ProductCreate = ProductBase & { 39 | /** ISO country code for product origin. Set to undefined for no country */ 40 | originCountryCode: string | undefined; 41 | /** images of the product */ 42 | images: WAMediaUpload[]; 43 | }; 44 | export type ProductUpdate = Omit; 45 | export type Product = ProductBase & { 46 | id: string; 47 | imageUrls: { 48 | [_: string]: string; 49 | }; 50 | reviewStatus: { 51 | [_: string]: string; 52 | }; 53 | availability: ProductAvailability; 54 | }; 55 | export type OrderPrice = { 56 | currency: string; 57 | total: number; 58 | }; 59 | export type OrderProduct = { 60 | id: string; 61 | imageUrl: string; 62 | name: string; 63 | quantity: number; 64 | currency: string; 65 | price: number; 66 | }; 67 | export type OrderDetails = { 68 | price: OrderPrice; 69 | products: OrderProduct[]; 70 | }; 71 | export type CatalogCursor = string; 72 | export type GetCatalogOptions = { 73 | /** cursor to start from */ 74 | cursor?: CatalogCursor; 75 | /** number of products to fetch */ 76 | limit?: number; 77 | jid?: string; 78 | }; 79 | -------------------------------------------------------------------------------- /lib/Utils/process-message.d.ts: -------------------------------------------------------------------------------- 1 | import { AxiosRequestConfig } from 'axios'; 2 | import type { Logger } from 'pino'; 3 | import { proto } from '../../WAProto'; 4 | import { AuthenticationCreds, BaileysEventEmitter, SignalKeyStoreWithTransaction, SocketConfig } from '../Types'; 5 | type ProcessMessageContext = { 6 | shouldProcessHistoryMsg: boolean; 7 | creds: AuthenticationCreds; 8 | keyStore: SignalKeyStoreWithTransaction; 9 | ev: BaileysEventEmitter; 10 | getMessage: SocketConfig['getMessage']; 11 | logger?: Logger; 12 | options: AxiosRequestConfig<{}>; 13 | }; 14 | /** Cleans a received message to further processing */ 15 | export declare const cleanMessage: (message: proto.IWebMessageInfo, meId: string) => void; 16 | export declare const isRealMessage: (message: proto.IWebMessageInfo, meId: string) => boolean | undefined; 17 | export declare const shouldIncrementChatUnread: (message: proto.IWebMessageInfo) => boolean; 18 | /** 19 | * Get the ID of the chat from the given key. 20 | * Typically -- that'll be the remoteJid, but for broadcasts, it'll be the participant 21 | */ 22 | export declare const getChatId: ({ remoteJid, participant, fromMe }: proto.IMessageKey) => string; 23 | type PollContext = { 24 | /** normalised jid of the person that created the poll */ 25 | pollCreatorJid: string; 26 | /** ID of the poll creation message */ 27 | pollMsgId: string; 28 | /** poll creation message enc key */ 29 | pollEncKey: Uint8Array; 30 | /** jid of the person that voted */ 31 | voterJid: string; 32 | }; 33 | /** 34 | * Decrypt a poll vote 35 | * @param vote encrypted vote 36 | * @param ctx additional info about the poll required for decryption 37 | * @returns list of SHA256 options 38 | */ 39 | export declare function decryptPollVote({ encPayload, encIv }: proto.Message.IPollEncValue, { pollCreatorJid, pollMsgId, pollEncKey, voterJid, }: PollContext): proto.Message.PollVoteMessage; 40 | declare const processMessage: (message: proto.IWebMessageInfo, { shouldProcessHistoryMsg, ev, creds, keyStore, logger, options, getMessage }: ProcessMessageContext) => Promise; 41 | export default processMessage; 42 | -------------------------------------------------------------------------------- /lib/Socket/socket.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Boom } from '@hapi/boom'; 3 | import { SocketConfig } from '../Types'; 4 | import { BinaryNode } from '../WABinary'; 5 | /** 6 | * Connects to WA servers and performs: 7 | * - simple queries (no retry mechanism, wait for connection establishment) 8 | * - listen to messages and emit events 9 | * - query phone connection 10 | */ 11 | export declare const makeSocket: (config: SocketConfig) => { 12 | type: "md"; 13 | ws: any; 14 | ev: import("../Types").BaileysEventEmitter & { 15 | process(handler: (events: Partial) => void | Promise): () => void; 16 | buffer(): void; 17 | createBufferedFunction(work: (...args: A) => Promise): (...args: A) => Promise; 18 | flush(force?: boolean | undefined): boolean; 19 | isBuffering(): boolean; 20 | }; 21 | authState: { 22 | creds: import("../Types").AuthenticationCreds; 23 | keys: import("../Types").SignalKeyStoreWithTransaction; 24 | }; 25 | signalRepository: import("../Types").SignalRepository; 26 | readonly user: import("../Types").Contact | undefined; 27 | generateMessageTag: () => string; 28 | query: (node: BinaryNode, timeoutMs?: number) => Promise; 29 | waitForMessage: (msgId: string, timeoutMs?: number | undefined) => Promise; 30 | waitForSocketOpen: () => Promise; 31 | sendRawMessage: (data: Uint8Array | Buffer) => Promise; 32 | sendNode: (frame: BinaryNode) => Promise; 33 | logout: (msg?: string) => Promise; 34 | end: (error: Error | undefined) => void; 35 | onUnexpectedError: (err: Error | Boom, msg: string) => void; 36 | uploadPreKeys: (count?: number) => Promise; 37 | uploadPreKeysToServerIfRequired: () => Promise; 38 | requestPairingCode: (phoneNumber: string) => Promise; 39 | /** Waits for the connection to WA to reach a state */ 40 | waitForConnectionUpdate: (check: (u: Partial) => boolean | undefined, timeoutMs?: number | undefined) => Promise; 41 | sendWAMBuffer: (wamBuffer: Buffer) => Promise; 42 | }; 43 | export type Socket = ReturnType; 44 | -------------------------------------------------------------------------------- /WASignalGroup/queue_job.js: -------------------------------------------------------------------------------- 1 | // vim: ts=4:sw=4:expandtab 2 | 3 | /* 4 | * jobQueue manages multiple queues indexed by device to serialize 5 | * session io ops on the database. 6 | */ 7 | 'use strict'; 8 | 9 | 10 | const _queueAsyncBuckets = new Map(); 11 | const _gcLimit = 10000; 12 | 13 | async function _asyncQueueExecutor(queue, cleanup) { 14 | let offt = 0; 15 | while (true) { 16 | let limit = Math.min(queue.length, _gcLimit); // Break up thundering hurds for GC duty. 17 | for (let i = offt; i < limit; i++) { 18 | const job = queue[i]; 19 | try { 20 | job.resolve(await job.awaitable()); 21 | } catch (e) { 22 | job.reject(e); 23 | } 24 | } 25 | if (limit < queue.length) { 26 | /* Perform lazy GC of queue for faster iteration. */ 27 | if (limit >= _gcLimit) { 28 | queue.splice(0, limit); 29 | offt = 0; 30 | } else { 31 | offt = limit; 32 | } 33 | } else { 34 | break; 35 | } 36 | } 37 | cleanup(); 38 | } 39 | 40 | module.exports = function (bucket, awaitable) { 41 | /* Run the async awaitable only when all other async calls registered 42 | * here have completed (or thrown). The bucket argument is a hashable 43 | * key representing the task queue to use. */ 44 | if (!awaitable.name) { 45 | // Make debuging easier by adding a name to this function. 46 | Object.defineProperty(awaitable, 'name', { writable: true }); 47 | if (typeof bucket === 'string') { 48 | awaitable.name = bucket; 49 | } else { 50 | console.warn("Unhandled bucket type (for naming):", typeof bucket, bucket); 51 | } 52 | } 53 | let inactive; 54 | if (!_queueAsyncBuckets.has(bucket)) { 55 | _queueAsyncBuckets.set(bucket, []); 56 | inactive = true; 57 | } 58 | const queue = _queueAsyncBuckets.get(bucket); 59 | const job = new Promise((resolve, reject) => queue.push({ 60 | awaitable, 61 | resolve, 62 | reject 63 | })); 64 | if (inactive) { 65 | /* An executor is not currently active; Start one now. */ 66 | _asyncQueueExecutor(queue, () => _queueAsyncBuckets.delete(bucket)); 67 | } 68 | return job; 69 | }; -------------------------------------------------------------------------------- /lib/Utils/crypto.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { KeyPair } from '../Types'; 3 | /** prefix version byte to the pub keys, required for some curve crypto functions */ 4 | export declare const generateSignalPubKey: (pubKey: Uint8Array | Buffer) => Uint8Array | Buffer; 5 | export declare const Curve: { 6 | generateKeyPair: () => KeyPair; 7 | sharedKey: (privateKey: Uint8Array, publicKey: Uint8Array) => Buffer; 8 | sign: (privateKey: Uint8Array, buf: Uint8Array) => any; 9 | verify: (pubKey: Uint8Array, message: Uint8Array, signature: Uint8Array) => boolean; 10 | }; 11 | export declare const signedKeyPair: (identityKeyPair: KeyPair, keyId: number) => { 12 | keyPair: KeyPair; 13 | signature: any; 14 | keyId: number; 15 | }; 16 | /** 17 | * encrypt AES 256 GCM; 18 | * where the tag tag is suffixed to the ciphertext 19 | * */ 20 | export declare function aesEncryptGCM(plaintext: Uint8Array, key: Uint8Array, iv: Uint8Array, additionalData: Uint8Array): Buffer; 21 | /** 22 | * decrypt AES 256 GCM; 23 | * where the auth tag is suffixed to the ciphertext 24 | * */ 25 | export declare function aesDecryptGCM(ciphertext: Uint8Array, key: Uint8Array, iv: Uint8Array, additionalData: Uint8Array): Buffer; 26 | export declare function aesEncryptCTR(plaintext: Uint8Array, key: Uint8Array, iv: Uint8Array): Buffer; 27 | export declare function aesDecryptCTR(ciphertext: Uint8Array, key: Uint8Array, iv: Uint8Array): Buffer; 28 | /** decrypt AES 256 CBC; where the IV is prefixed to the buffer */ 29 | export declare function aesDecrypt(buffer: Buffer, key: Buffer): Buffer; 30 | /** decrypt AES 256 CBC */ 31 | export declare function aesDecryptWithIV(buffer: Buffer, key: Buffer, IV: Buffer): Buffer; 32 | export declare function aesEncrypt(buffer: Buffer | Uint8Array, key: Buffer): Buffer; 33 | export declare function aesEncrypWithIV(buffer: Buffer, key: Buffer, IV: Buffer): Buffer; 34 | export declare function hmacSign(buffer: Buffer | Uint8Array, key: Buffer | Uint8Array, variant?: 'sha256' | 'sha512'): Buffer; 35 | export declare function sha256(buffer: Buffer): Buffer; 36 | export declare function md5(buffer: Buffer): Buffer; 37 | export declare function hkdf(buffer: Uint8Array | Buffer, expandedLength: number, info: { 38 | salt?: Buffer; 39 | info?: string; 40 | }): Buffer; 41 | export declare function derivePairingCodeKey(pairingCode: string, salt: Buffer): Buffer; 42 | -------------------------------------------------------------------------------- /WASignalGroup/sender_key_distribution_message.js: -------------------------------------------------------------------------------- 1 | const CiphertextMessage = require('./ciphertext_message'); 2 | const protobufs = require('./protobufs'); 3 | 4 | class SenderKeyDistributionMessage extends CiphertextMessage { 5 | constructor( 6 | id = null, 7 | iteration = null, 8 | chainKey = null, 9 | signatureKey = null, 10 | serialized = null 11 | ) { 12 | super(); 13 | if (serialized) { 14 | try { 15 | const version = serialized[0]; 16 | const message = serialized.slice(1); 17 | 18 | const distributionMessage = protobufs.SenderKeyDistributionMessage.decode( 19 | message 20 | ).toJSON(); 21 | this.serialized = serialized; 22 | this.id = distributionMessage.id; 23 | this.iteration = distributionMessage.iteration; 24 | this.chainKey = distributionMessage.chainKey; 25 | this.signatureKey = distributionMessage.signingKey; 26 | } catch (e) { 27 | throw new Error(e); 28 | } 29 | } else { 30 | const version = this.intsToByteHighAndLow(this.CURRENT_VERSION, this.CURRENT_VERSION); 31 | this.id = id; 32 | this.iteration = iteration; 33 | this.chainKey = chainKey; 34 | this.signatureKey = signatureKey; 35 | const message = protobufs.SenderKeyDistributionMessage.encode( 36 | protobufs.SenderKeyDistributionMessage.create({ 37 | id, 38 | iteration, 39 | chainKey, 40 | signingKey: this.signatureKey, 41 | }) 42 | ).finish(); 43 | this.serialized = Buffer.concat([Buffer.from([version]), message]); 44 | } 45 | } 46 | 47 | intsToByteHighAndLow(highValue, lowValue) { 48 | return (((highValue << 4) | lowValue) & 0xff) % 256; 49 | } 50 | 51 | serialize() { 52 | return this.serialized; 53 | } 54 | 55 | getType() { 56 | return this.SENDERKEY_DISTRIBUTION_TYPE; 57 | } 58 | 59 | getIteration() { 60 | return this.iteration; 61 | } 62 | 63 | getChainKey() { 64 | return typeof this.chainKey === 'string' ? Buffer.from(this.chainKey, 'base64') : this.chainKey; 65 | } 66 | 67 | getSignatureKey() { 68 | return typeof this.signatureKey === 'string' 69 | ? Buffer.from(this.signatureKey, 'base64') 70 | : this.signatureKey; 71 | } 72 | 73 | getId() { 74 | return this.id; 75 | } 76 | } 77 | 78 | module.exports = SenderKeyDistributionMessage; -------------------------------------------------------------------------------- /lib/Types/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __exportStar = (this && this.__exportStar) || function(m, exports) { 14 | for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); 15 | }; 16 | Object.defineProperty(exports, "__esModule", { value: true }); 17 | exports.DisconnectReason = void 0; 18 | __exportStar(require("./Auth"), exports); 19 | __exportStar(require("./GroupMetadata"), exports); 20 | __exportStar(require("./Chat"), exports); 21 | __exportStar(require("./Contact"), exports); 22 | __exportStar(require("./State"), exports); 23 | __exportStar(require("./Message"), exports); 24 | __exportStar(require("./Newsletter"), exports); 25 | __exportStar(require("./Socket"), exports); 26 | __exportStar(require("./Events"), exports); 27 | __exportStar(require("./Product"), exports); 28 | __exportStar(require("./Call"), exports); 29 | __exportStar(require("./Signal"), exports); 30 | var DisconnectReason; 31 | (function (DisconnectReason) { 32 | DisconnectReason[DisconnectReason["connectionClosed"] = 428] = "connectionClosed"; 33 | DisconnectReason[DisconnectReason["connectionLost"] = 408] = "connectionLost"; 34 | DisconnectReason[DisconnectReason["connectionReplaced"] = 440] = "connectionReplaced"; 35 | DisconnectReason[DisconnectReason["timedOut"] = 408] = "timedOut"; 36 | DisconnectReason[DisconnectReason["loggedOut"] = 401] = "loggedOut"; 37 | DisconnectReason[DisconnectReason["badSession"] = 500] = "badSession"; 38 | DisconnectReason[DisconnectReason["restartRequired"] = 515] = "restartRequired"; 39 | DisconnectReason[DisconnectReason["multideviceMismatch"] = 411] = "multideviceMismatch"; 40 | DisconnectReason[DisconnectReason["forbidden"] = 403] = "forbidden"; 41 | DisconnectReason[DisconnectReason["unavailableService"] = 503] = "unavailableService"; 42 | })(DisconnectReason = exports.DisconnectReason || (exports.DisconnectReason = {})); 43 | -------------------------------------------------------------------------------- /lib/Store/make-ordered-dictionary.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | function makeOrderedDictionary(idGetter) { 4 | const array = []; 5 | const dict = {}; 6 | const get = (id) => dict[id]; 7 | const update = (item) => { 8 | const id = idGetter(item); 9 | const idx = array.findIndex(i => idGetter(i) === id); 10 | if (idx >= 0) { 11 | array[idx] = item; 12 | dict[id] = item; 13 | } 14 | return false; 15 | }; 16 | const upsert = (item, mode) => { 17 | const id = idGetter(item); 18 | if (get(id)) { 19 | update(item); 20 | } 21 | else { 22 | if (mode === 'append') { 23 | array.push(item); 24 | } 25 | else { 26 | array.splice(0, 0, item); 27 | } 28 | dict[id] = item; 29 | } 30 | }; 31 | const remove = (item) => { 32 | const id = idGetter(item); 33 | const idx = array.findIndex(i => idGetter(i) === id); 34 | if (idx >= 0) { 35 | array.splice(idx, 1); 36 | delete dict[id]; 37 | return true; 38 | } 39 | return false; 40 | }; 41 | return { 42 | array, 43 | get, 44 | upsert, 45 | update, 46 | remove, 47 | updateAssign: (id, update) => { 48 | const item = get(id); 49 | if (item) { 50 | Object.assign(item, update); 51 | delete dict[id]; 52 | dict[idGetter(item)] = item; 53 | return true; 54 | } 55 | return false; 56 | }, 57 | clear: () => { 58 | array.splice(0, array.length); 59 | Object.keys(dict).forEach(key => { 60 | delete dict[key]; 61 | }); 62 | }, 63 | filter: (contain) => { 64 | let i = 0; 65 | while (i < array.length) { 66 | if (!contain(array[i])) { 67 | delete dict[idGetter(array[i])]; 68 | array.splice(i, 1); 69 | } 70 | else { 71 | i += 1; 72 | } 73 | } 74 | }, 75 | toJSON: () => array, 76 | fromJSON: (newItems) => { 77 | array.splice(0, array.length, ...newItems); 78 | } 79 | }; 80 | } 81 | exports.default = makeOrderedDictionary; 82 | -------------------------------------------------------------------------------- /lib/Socket/Client/mobile-socket-client.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.MobileSocketClient = void 0; 4 | const net_1 = require("net"); 5 | const abstract_socket_client_1 = require("./abstract-socket-client"); 6 | class MobileSocketClient extends abstract_socket_client_1.AbstractSocketClient { 7 | constructor() { 8 | super(...arguments); 9 | this.socket = null; 10 | } 11 | get isOpen() { 12 | var _a; 13 | return ((_a = this.socket) === null || _a === void 0 ? void 0 : _a.readyState) === 'open'; 14 | } 15 | get isClosed() { 16 | var _a; 17 | return this.socket === null || ((_a = this.socket) === null || _a === void 0 ? void 0 : _a.readyState) === 'closed'; 18 | } 19 | get isClosing() { 20 | var _a; 21 | return this.socket === null || ((_a = this.socket) === null || _a === void 0 ? void 0 : _a.readyState) === 'closed'; 22 | } 23 | get isConnecting() { 24 | var _a; 25 | return ((_a = this.socket) === null || _a === void 0 ? void 0 : _a.readyState) === 'opening'; 26 | } 27 | async connect() { 28 | var _a; 29 | if (this.socket) { 30 | return; 31 | } 32 | if (this.config.agent) { 33 | throw new Error('There are not support for proxy agent for mobile connection'); 34 | } 35 | else { 36 | this.socket = (0, net_1.connect)({ 37 | host: this.url.hostname, 38 | port: Number(this.url.port) || 443 39 | }); 40 | } 41 | this.socket.setMaxListeners(0); 42 | const events = ['close', 'connect', 'data', 'drain', 'end', 'error', 'lookup', 'ready', 'timeout']; 43 | for (const event of events) { 44 | (_a = this.socket) === null || _a === void 0 ? void 0 : _a.on(event, (...args) => this.emit(event, ...args)); 45 | } 46 | this.socket.on('data', (...args) => this.emit('message', ...args)); 47 | this.socket.on('ready', (...args) => this.emit('open', ...args)); 48 | } 49 | async close() { 50 | if (!this.socket) { 51 | return; 52 | } 53 | return new Promise(resolve => { 54 | this.socket.end(resolve); 55 | this.socket = null; 56 | }); 57 | } 58 | send(str, cb) { 59 | if (this.socket === null) { 60 | return false; 61 | } 62 | return this.socket.write(str, undefined, cb); 63 | } 64 | } 65 | exports.MobileSocketClient = MobileSocketClient; 66 | -------------------------------------------------------------------------------- /lib/Socket/Client/web-socket-client.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.WebSocketClient = void 0; 7 | const ws_1 = __importDefault(require("ws")); 8 | const Defaults_1 = require("../../Defaults"); 9 | const abstract_socket_client_1 = require("./abstract-socket-client"); 10 | class WebSocketClient extends abstract_socket_client_1.AbstractSocketClient { 11 | constructor() { 12 | super(...arguments); 13 | this.socket = null; 14 | } 15 | get isOpen() { 16 | var _a; 17 | return ((_a = this.socket) === null || _a === void 0 ? void 0 : _a.readyState) === ws_1.default.OPEN; 18 | } 19 | get isClosed() { 20 | var _a; 21 | return this.socket === null || ((_a = this.socket) === null || _a === void 0 ? void 0 : _a.readyState) === ws_1.default.CLOSED; 22 | } 23 | get isClosing() { 24 | var _a; 25 | return this.socket === null || ((_a = this.socket) === null || _a === void 0 ? void 0 : _a.readyState) === ws_1.default.CLOSING; 26 | } 27 | get isConnecting() { 28 | var _a; 29 | return ((_a = this.socket) === null || _a === void 0 ? void 0 : _a.readyState) === ws_1.default.CONNECTING; 30 | } 31 | async connect() { 32 | var _a, _b; 33 | if (this.socket) { 34 | return; 35 | } 36 | this.socket = new ws_1.default(this.url, { 37 | origin: Defaults_1.DEFAULT_ORIGIN, 38 | headers: (_a = this.config.options) === null || _a === void 0 ? void 0 : _a.headers, 39 | handshakeTimeout: this.config.connectTimeoutMs, 40 | timeout: this.config.connectTimeoutMs, 41 | agent: this.config.agent, 42 | }); 43 | this.socket.setMaxListeners(0); 44 | const events = ['close', 'error', 'upgrade', 'message', 'open', 'ping', 'pong', 'unexpected-response']; 45 | for (const event of events) { 46 | (_b = this.socket) === null || _b === void 0 ? void 0 : _b.on(event, (...args) => this.emit(event, ...args)); 47 | } 48 | } 49 | async close() { 50 | if (!this.socket) { 51 | return; 52 | } 53 | this.socket.close(); 54 | this.socket = null; 55 | } 56 | send(str, cb) { 57 | var _a; 58 | (_a = this.socket) === null || _a === void 0 ? void 0 : _a.send(str, cb); 59 | return Boolean(this.socket); 60 | } 61 | } 62 | exports.WebSocketClient = WebSocketClient; 63 | -------------------------------------------------------------------------------- /lib/Utils/baileys-event-stream.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.readAndEmitEventStream = exports.captureEventStream = void 0; 7 | const events_1 = __importDefault(require("events")); 8 | const fs_1 = require("fs"); 9 | const promises_1 = require("fs/promises"); 10 | const readline_1 = require("readline"); 11 | const generics_1 = require("./generics"); 12 | const make_mutex_1 = require("./make-mutex"); 13 | /** 14 | * Captures events from a baileys event emitter & stores them in a file 15 | * @param ev The event emitter to read events from 16 | * @param filename File to save to 17 | */ 18 | const captureEventStream = (ev, filename) => { 19 | const oldEmit = ev.emit; 20 | // write mutex so data is appended in order 21 | const writeMutex = (0, make_mutex_1.makeMutex)(); 22 | // monkey patch eventemitter to capture all events 23 | ev.emit = function (...args) { 24 | const content = JSON.stringify({ timestamp: Date.now(), event: args[0], data: args[1] }) + '\n'; 25 | const result = oldEmit.apply(ev, args); 26 | writeMutex.mutex(async () => { 27 | await (0, promises_1.writeFile)(filename, content, { flag: 'a' }); 28 | }); 29 | return result; 30 | }; 31 | }; 32 | exports.captureEventStream = captureEventStream; 33 | /** 34 | * Read event file and emit events from there 35 | * @param filename filename containing event data 36 | * @param delayIntervalMs delay between each event emit 37 | */ 38 | const readAndEmitEventStream = (filename, delayIntervalMs = 0) => { 39 | const ev = new events_1.default(); 40 | const fireEvents = async () => { 41 | // from: https://stackoverflow.com/questions/6156501/read-a-file-one-line-at-a-time-in-node-js 42 | const fileStream = (0, fs_1.createReadStream)(filename); 43 | const rl = (0, readline_1.createInterface)({ 44 | input: fileStream, 45 | crlfDelay: Infinity 46 | }); 47 | // Note: we use the crlfDelay option to recognize all instances of CR LF 48 | // ('\r\n') in input.txt as a single line break. 49 | for await (const line of rl) { 50 | if (line) { 51 | const { event, data } = JSON.parse(line); 52 | ev.emit(event, data); 53 | delayIntervalMs && await (0, generics_1.delay)(delayIntervalMs); 54 | } 55 | } 56 | fileStream.close(); 57 | }; 58 | return { 59 | ev, 60 | task: fireEvents() 61 | }; 62 | }; 63 | exports.readAndEmitEventStream = readAndEmitEventStream; 64 | -------------------------------------------------------------------------------- /WASignalGroup/sender_key_message.js: -------------------------------------------------------------------------------- 1 | const CiphertextMessage = require('./ciphertext_message'); 2 | const curve = require('libsignal/src/curve'); 3 | const protobufs = require('./protobufs'); 4 | 5 | class SenderKeyMessage extends CiphertextMessage { 6 | SIGNATURE_LENGTH = 64; 7 | 8 | constructor( 9 | keyId = null, 10 | iteration = null, 11 | ciphertext = null, 12 | signatureKey = null, 13 | serialized = null 14 | ) { 15 | super(); 16 | if (serialized) { 17 | const version = serialized[0]; 18 | const message = serialized.slice(1, serialized.length - this.SIGNATURE_LENGTH); 19 | const signature = serialized.slice(-1 * this.SIGNATURE_LENGTH); 20 | const senderKeyMessage = protobufs.SenderKeyMessage.decode(message).toJSON(); 21 | senderKeyMessage.ciphertext = Buffer.from(senderKeyMessage.ciphertext, 'base64'); 22 | 23 | this.serialized = serialized; 24 | this.messageVersion = (version & 0xff) >> 4; 25 | 26 | this.keyId = senderKeyMessage.id; 27 | this.iteration = senderKeyMessage.iteration; 28 | this.ciphertext = senderKeyMessage.ciphertext; 29 | this.signature = signature; 30 | } else { 31 | const version = (((this.CURRENT_VERSION << 4) | this.CURRENT_VERSION) & 0xff) % 256; 32 | ciphertext = Buffer.from(ciphertext); // .toString('base64'); 33 | const message = protobufs.SenderKeyMessage.encode( 34 | protobufs.SenderKeyMessage.create({ 35 | id: keyId, 36 | iteration, 37 | ciphertext, 38 | }) 39 | ).finish(); 40 | 41 | const signature = this.getSignature( 42 | signatureKey, 43 | Buffer.concat([Buffer.from([version]), message]) 44 | ); 45 | this.serialized = Buffer.concat([Buffer.from([version]), message, Buffer.from(signature)]); 46 | this.messageVersion = this.CURRENT_VERSION; 47 | this.keyId = keyId; 48 | this.iteration = iteration; 49 | this.ciphertext = ciphertext; 50 | this.signature = signature; 51 | } 52 | } 53 | 54 | getKeyId() { 55 | return this.keyId; 56 | } 57 | 58 | getIteration() { 59 | return this.iteration; 60 | } 61 | 62 | getCipherText() { 63 | return this.ciphertext; 64 | } 65 | 66 | verifySignature(signatureKey) { 67 | const part1 = this.serialized.slice(0, this.serialized.length - this.SIGNATURE_LENGTH); 68 | const part2 = this.serialized.slice(-1 * this.SIGNATURE_LENGTH); 69 | const res = curve.verifySignature(signatureKey, part1, part2); 70 | if (!res) throw new Error('Invalid signature!'); 71 | } 72 | 73 | getSignature(signatureKey, serialized) { 74 | const signature = Buffer.from( 75 | curve.calculateSignature( 76 | signatureKey, 77 | serialized 78 | ) 79 | ); 80 | return signature; 81 | } 82 | 83 | serialize() { 84 | return this.serialized; 85 | } 86 | 87 | getType() { 88 | return 4; 89 | } 90 | } 91 | 92 | module.exports = SenderKeyMessage; -------------------------------------------------------------------------------- /lib/WABinary/jid-utils.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.jidNormalizedUser = exports.isJidNewsLetter = exports.isJidStatusBroadcast = exports.isJidGroup = exports.isJidBroadcast = exports.isLidUser = exports.isJidUser = exports.areJidsSameUser = exports.jidDecode = exports.jidEncode = exports.STORIES_JID = exports.PSA_WID = exports.SERVER_JID = exports.OFFICIAL_BIZ_JID = exports.S_WHATSAPP_NET = void 0; 4 | exports.S_WHATSAPP_NET = '@s.whatsapp.net'; 5 | exports.OFFICIAL_BIZ_JID = '16505361212@c.us'; 6 | exports.SERVER_JID = 'server@c.us'; 7 | exports.PSA_WID = '0@c.us'; 8 | exports.STORIES_JID = 'status@broadcast'; 9 | const jidEncode = (user, server, device, agent) => { 10 | return `${user || ''}${!!agent ? `_${agent}` : ''}${!!device ? `:${device}` : ''}@${server}`; 11 | }; 12 | exports.jidEncode = jidEncode; 13 | const jidDecode = (jid) => { 14 | const sepIdx = typeof jid === 'string' ? jid.indexOf('@') : -1; 15 | if (sepIdx < 0) { 16 | return undefined; 17 | } 18 | const server = jid.slice(sepIdx + 1); 19 | const userCombined = jid.slice(0, sepIdx); 20 | const [userAgent, device] = userCombined.split(':'); 21 | const user = userAgent.split('_')[0]; 22 | return { 23 | server, 24 | user, 25 | domainType: server === 'lid' ? 1 : 0, 26 | device: device ? +device : undefined 27 | }; 28 | }; 29 | exports.jidDecode = jidDecode; 30 | /** is the jid a user */ 31 | const areJidsSameUser = (jid1, jid2) => { 32 | var _a, _b; 33 | return (((_a = (0, exports.jidDecode)(jid1)) === null || _a === void 0 ? void 0 : _a.user) === ((_b = (0, exports.jidDecode)(jid2)) === null || _b === void 0 ? void 0 : _b.user)); 34 | }; 35 | exports.areJidsSameUser = areJidsSameUser; 36 | /** is the jid a user */ 37 | const isJidUser = (jid) => (jid === null || jid === void 0 ? void 0 : jid.endsWith('@s.whatsapp.net')); 38 | exports.isJidUser = isJidUser; 39 | /** is the jid a group */ 40 | const isLidUser = (jid) => (jid === null || jid === void 0 ? void 0 : jid.endsWith('@lid')); 41 | exports.isLidUser = isLidUser; 42 | /** is the jid a broadcast */ 43 | const isJidBroadcast = (jid) => (jid === null || jid === void 0 ? void 0 : jid.endsWith('@broadcast')); 44 | exports.isJidBroadcast = isJidBroadcast; 45 | /** is the jid a group */ 46 | const isJidGroup = (jid) => (jid === null || jid === void 0 ? void 0 : jid.endsWith('@g.us')); 47 | exports.isJidGroup = isJidGroup; 48 | /** is the jid the status broadcast */ 49 | const isJidStatusBroadcast = (jid) => jid === 'status@broadcast'; 50 | exports.isJidStatusBroadcast = isJidStatusBroadcast; 51 | /** is the jid the newsletter */ 52 | const isJidNewsLetter = (jid) => (jid === null || jid === void 0 ? void 0 : jid.endsWith('newsletter')); 53 | exports.isJidNewsLetter = isJidNewsLetter; 54 | const jidNormalizedUser = (jid) => { 55 | const result = (0, exports.jidDecode)(jid); 56 | if (!result) { 57 | return ''; 58 | } 59 | const { user, server } = result; 60 | return (0, exports.jidEncode)(user, server === 'c.us' ? 's.whatsapp.net' : server); 61 | }; 62 | exports.jidNormalizedUser = jidNormalizedUser; 63 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "baileys", 3 | "version": "6.7.4", 4 | "description": "WhatsApp API", 5 | "keywords": [ 6 | "whatsapp", 7 | "js-whatsapp", 8 | "whatsapp-api", 9 | "whatsapp-web", 10 | "whatsapp-chat", 11 | "whatsapp-group", 12 | "automation", 13 | "multi-device" 14 | ], 15 | "homepage": "https://github.com/WhiskeySockets/Baileys", 16 | "repository": { 17 | "url": "git@github.com:WhiskeySockets/Baileys.git" 18 | }, 19 | "license": "MIT", 20 | "author": "Adhiraj Singh", 21 | "main": "lib/index.js", 22 | "types": "lib/index.d.ts", 23 | "files": [ 24 | "lib/*", 25 | "WAProto/*", 26 | "WASignalGroup/*.js" 27 | ], 28 | "scripts": { 29 | "build:all": "tsc && typedoc", 30 | "build:docs": "typedoc", 31 | "build:tsc": "tsc", 32 | "changelog:last": "conventional-changelog -p angular -r 2", 33 | "changelog:preview": "conventional-changelog -p angular -u", 34 | "changelog:update": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0", 35 | "example": "node --inspect -r ts-node/register Example/example.ts", 36 | "example:mobile": "node --inspect -r ts-node/register Example/example.ts --mobile", 37 | "gen:protobuf": "sh WAProto/GenerateStatics.sh", 38 | "lint": "eslint src --ext .js,.ts,.jsx,.tsx", 39 | "lint:fix": "eslint src --fix --ext .js,.ts,.jsx,.tsx", 40 | "prepack": "tsc", 41 | "prepare": "tsc", 42 | "release": "release-it", 43 | "test": "jest" 44 | }, 45 | "dependencies": { 46 | "@adiwajshing/keyed-db": "^0.2.4", 47 | "@hapi/boom": "^9.1.3", 48 | "audio-decode": "^2.1.3", 49 | "axios": "^1.3.3", 50 | "cache-manager": "4.0.1", 51 | "futoin-hkdf": "^1.5.1", 52 | "libphonenumber-js": "^1.10.20", 53 | "libsignal": "github:adiwajshing/libsignal-node", 54 | "music-metadata": "^7.12.3", 55 | "node-cache": "^5.1.2", 56 | "pino": "^7.0.0", 57 | "protobufjs": "^7.2.4", 58 | "uuid": "^9.0.0", 59 | "ws": "^8.13.0" 60 | }, 61 | "devDependencies": { 62 | "@adiwajshing/eslint-config": "github:adiwajshing/eslint-config", 63 | "@types/got": "^9.6.11", 64 | "@types/jest": "^27.5.1", 65 | "@types/node": "^16.0.0", 66 | "@types/sharp": "^0.29.4", 67 | "@types/ws": "^8.0.0", 68 | "conventional-changelog-cli": "^2.2.2", 69 | "eslint": "^8.0.0", 70 | "jest": "^27.0.6", 71 | "jimp": "^0.16.1", 72 | "link-preview-js": "^3.0.0", 73 | "open": "^8.4.2", 74 | "qrcode-terminal": "^0.12.0", 75 | "release-it": "^15.10.3", 76 | "sharp": "^0.30.5", 77 | "ts-jest": "^27.0.3", 78 | "ts-node": "^10.8.1", 79 | "typedoc": "^0.24.7", 80 | "typescript": "^4.6.4", 81 | "json": "^11.0.0" 82 | }, 83 | "peerDependencies": { 84 | "jimp": "^0.16.1", 85 | "link-preview-js": "^3.0.0", 86 | "qrcode-terminal": "^0.12.0", 87 | "sharp": "^0.32.2" 88 | }, 89 | "peerDependenciesMeta": { 90 | "jimp": { 91 | "optional": true 92 | }, 93 | "link-preview-js": { 94 | "optional": true 95 | }, 96 | "qrcode-terminal": { 97 | "optional": true 98 | }, 99 | "sharp": { 100 | "optional": true 101 | } 102 | }, 103 | "packageManager": "yarn@1.22.19" 104 | } 105 | -------------------------------------------------------------------------------- /lib/Store/make-cache-manager-store.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | const cache_manager_1 = require("cache-manager"); 7 | const WAProto_1 = require("../../WAProto"); 8 | const Utils_1 = require("../Utils"); 9 | const logger_1 = __importDefault(require("../Utils/logger")); 10 | const makeCacheManagerAuthState = async (store, sessionKey) => { 11 | const defaultKey = (file) => `${sessionKey}:${file}`; 12 | const databaseConn = await (0, cache_manager_1.caching)(store); 13 | const writeData = async (file, data) => { 14 | let ttl = undefined; 15 | if (file === 'creds') { 16 | ttl = 63115200; // 2 years 17 | } 18 | await databaseConn.set(defaultKey(file), JSON.stringify(data, Utils_1.BufferJSON.replacer), ttl); 19 | }; 20 | const readData = async (file) => { 21 | try { 22 | const data = await databaseConn.get(defaultKey(file)); 23 | if (data) { 24 | return JSON.parse(data, Utils_1.BufferJSON.reviver); 25 | } 26 | return null; 27 | } 28 | catch (error) { 29 | logger_1.default.error(error); 30 | return null; 31 | } 32 | }; 33 | const removeData = async (file) => { 34 | try { 35 | return await databaseConn.del(defaultKey(file)); 36 | } 37 | catch (_a) { 38 | logger_1.default.error(`Error removing ${file} from session ${sessionKey}`); 39 | } 40 | }; 41 | const clearState = async () => { 42 | try { 43 | const result = await databaseConn.store.keys(`${sessionKey}*`); 44 | await Promise.all(result.map(async (key) => await databaseConn.del(key))); 45 | } 46 | catch (err) { 47 | } 48 | }; 49 | const creds = (await readData('creds')) || (0, Utils_1.initAuthCreds)(); 50 | return { 51 | clearState, 52 | saveCreds: () => writeData('creds', creds), 53 | state: { 54 | creds, 55 | keys: { 56 | get: async (type, ids) => { 57 | const data = {}; 58 | await Promise.all(ids.map(async (id) => { 59 | let value = await readData(`${type}-${id}`); 60 | if (type === 'app-state-sync-key' && value) { 61 | value = WAProto_1.proto.Message.AppStateSyncKeyData.fromObject(value); 62 | } 63 | data[id] = value; 64 | })); 65 | return data; 66 | }, 67 | set: async (data) => { 68 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 69 | const tasks = []; 70 | for (const category in data) { 71 | for (const id in data[category]) { 72 | const value = data[category][id]; 73 | const key = `${category}-${id}`; 74 | tasks.push(value ? writeData(key, value) : removeData(key)); 75 | } 76 | } 77 | await Promise.all(tasks); 78 | }, 79 | } 80 | } 81 | }; 82 | }; 83 | exports.default = makeCacheManagerAuthState; 84 | -------------------------------------------------------------------------------- /lib/Types/Newsletter.d.ts: -------------------------------------------------------------------------------- 1 | import { proto } from '../../WAProto'; 2 | export type NewsletterReactionMode = 'ALL' | 'BASIC' | 'NONE'; 3 | export type NewsletterState = 'ACTIVE' | 'GEOSUSPENDED' | 'SUSPENDED'; 4 | export type NewsletterVerification = 'VERIFIED' | 'UNVERIFIED'; 5 | export type NewsletterMute = 'ON' | 'OFF' | 'UNDEFINED'; 6 | export type NewsletterViewRole = 'ADMIN' | 'GUEST' | 'OWNER' | 'SUBSCRIBER'; 7 | export type NewsletterViewerMetadata = { 8 | mute: NewsletterMute; 9 | view_role: NewsletterViewRole; 10 | }; 11 | export type NewsletterMetadata = { 12 | /**jid of newsletter */ 13 | id: string; 14 | /**state of newsletter */ 15 | state: NewsletterState; 16 | /**creation timestamp of newsletter */ 17 | creation_time: number; 18 | /**name of newsletter */ 19 | name: string; 20 | /**timestamp of last name modification of newsletter */ 21 | nameTime: number; 22 | /**description of newsletter */ 23 | description: string; 24 | /**timestamp of last description modification of newsletter */ 25 | descriptionTime: number; 26 | /**invite code of newsletter */ 27 | invite: string; 28 | /**i dont know */ 29 | handle: null; 30 | /**direct path of picture */ 31 | picture: string | null; 32 | /**direct path of picture preview (lower quality) */ 33 | preview: string | null; 34 | /**reaction mode of newsletter */ 35 | reaction_codes?: NewsletterReactionMode; 36 | /**subscribers count of newsletter */ 37 | subscribers: number; 38 | /**verification state of newsletter */ 39 | verification: NewsletterVerification; 40 | /**viewer metadata */ 41 | viewer_metadata: NewsletterViewerMetadata; 42 | }; 43 | export type SubscriberAction = 'promote' | 'demote'; 44 | export type ReactionModeUpdate = { 45 | reaction_codes: { 46 | blocked_codes: null; 47 | enabled_ts_sec: null; 48 | value: NewsletterReactionMode; 49 | }; 50 | }; 51 | /**only exists reaction mode update */ 52 | export type NewsletterSettingsUpdate = ReactionModeUpdate; 53 | export type NewsletterReaction = { 54 | count: number; 55 | code: string; 56 | }; 57 | export type NewsletterFetchedUpdate = { 58 | /**id of message in newsletter, starts from 100 */ 59 | server_id: string; 60 | /**count of views in this message */ 61 | views?: number; 62 | /**reactions in this message */ 63 | reactions: NewsletterReaction[]; 64 | /**the message, if you requested only updates, you will not receive message */ 65 | message?: proto.IWebMessageInfo; 66 | }; 67 | export declare enum MexOperations { 68 | PROMOTE = "NotificationNewsletterAdminPromote", 69 | DEMOTE = "NotificationNewsletterAdminDemote", 70 | UPDATE = "NotificationNewsletterUpdate" 71 | } 72 | export declare enum XWAPaths { 73 | PROMOTE = "xwa2_notify_newsletter_admin_promote", 74 | DEMOTE = "xwa2_notify_newsletter_admin_demote", 75 | ADMIN_COUNT = "xwa2_newsletter_admin", 76 | CREATE = "xwa2_newsletter_create", 77 | NEWSLETTER = "xwa2_newsletter", 78 | METADATA_UPDATE = "xwa2_notify_newsletter_on_metadata_update" 79 | } 80 | export declare enum QueryIds { 81 | JOB_MUTATION = "7150902998257522", 82 | METADATA = "6620195908089573", 83 | UNFOLLOW = "7238632346214362", 84 | FOLLOW = "7871414976211147", 85 | UNMUTE = "7337137176362961", 86 | MUTE = "25151904754424642", 87 | CREATE = "6996806640408138", 88 | ADMIN_COUNT = "7130823597031706", 89 | CHANGE_OWNER = "7341777602580933", 90 | DELETE = "8316537688363079", 91 | DEMOTE = "6551828931592903" 92 | } 93 | -------------------------------------------------------------------------------- /lib/Utils/use-multi-file-auth-state.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.useMultiFileAuthState = void 0; 4 | const promises_1 = require("fs/promises"); 5 | const path_1 = require("path"); 6 | const WAProto_1 = require("../../WAProto"); 7 | const auth_utils_1 = require("./auth-utils"); 8 | const generics_1 = require("./generics"); 9 | /** 10 | * stores the full authentication state in a single folder. 11 | * Far more efficient than singlefileauthstate 12 | * 13 | * Again, I wouldn't endorse this for any production level use other than perhaps a bot. 14 | * Would recommend writing an auth state for use with a proper SQL or No-SQL DB 15 | * */ 16 | const useMultiFileAuthState = async (folder) => { 17 | const writeData = (data, file) => { 18 | return (0, promises_1.writeFile)((0, path_1.join)(folder, fixFileName(file)), JSON.stringify(data, generics_1.BufferJSON.replacer)); 19 | }; 20 | const readData = async (file) => { 21 | try { 22 | const data = await (0, promises_1.readFile)((0, path_1.join)(folder, fixFileName(file)), { encoding: 'utf-8' }); 23 | return JSON.parse(data, generics_1.BufferJSON.reviver); 24 | } 25 | catch (error) { 26 | return null; 27 | } 28 | }; 29 | const removeData = async (file) => { 30 | try { 31 | await (0, promises_1.unlink)((0, path_1.join)(folder, fixFileName(file))); 32 | } 33 | catch (_a) { 34 | } 35 | }; 36 | const folderInfo = await (0, promises_1.stat)(folder).catch(() => { }); 37 | if (folderInfo) { 38 | if (!folderInfo.isDirectory()) { 39 | throw new Error(`found something that is not a directory at ${folder}, either delete it or specify a different location`); 40 | } 41 | } 42 | else { 43 | await (0, promises_1.mkdir)(folder, { recursive: true }); 44 | } 45 | const fixFileName = (file) => { var _a; return (_a = file === null || file === void 0 ? void 0 : file.replace(/\//g, '__')) === null || _a === void 0 ? void 0 : _a.replace(/:/g, '-'); }; 46 | const creds = await readData('creds.json') || (0, auth_utils_1.initAuthCreds)(); 47 | return { 48 | state: { 49 | creds, 50 | keys: { 51 | get: async (type, ids) => { 52 | const data = {}; 53 | await Promise.all(ids.map(async (id) => { 54 | let value = await readData(`${type}-${id}.json`); 55 | if (type === 'app-state-sync-key' && value) { 56 | value = WAProto_1.proto.Message.AppStateSyncKeyData.fromObject(value); 57 | } 58 | data[id] = value; 59 | })); 60 | return data; 61 | }, 62 | set: async (data) => { 63 | const tasks = []; 64 | for (const category in data) { 65 | for (const id in data[category]) { 66 | const value = data[category][id]; 67 | const file = `${category}-${id}.json`; 68 | tasks.push(value ? writeData(value, file) : removeData(file)); 69 | } 70 | } 71 | await Promise.all(tasks); 72 | } 73 | } 74 | }, 75 | saveCreds: () => { 76 | return writeData(creds, 'creds.json'); 77 | } 78 | }; 79 | }; 80 | exports.useMultiFileAuthState = useMultiFileAuthState; 81 | -------------------------------------------------------------------------------- /lib/Types/Auth.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import type { proto } from '../../WAProto'; 3 | import { RegistrationOptions } from '../Socket/registration'; 4 | import type { Contact } from './Contact'; 5 | import type { MinimalMessage } from './Message'; 6 | export type KeyPair = { 7 | public: Uint8Array; 8 | private: Uint8Array; 9 | }; 10 | export type SignedKeyPair = { 11 | keyPair: KeyPair; 12 | signature: Uint8Array; 13 | keyId: number; 14 | timestampS?: number; 15 | }; 16 | export type ProtocolAddress = { 17 | name: string; 18 | deviceId: number; 19 | }; 20 | export type SignalIdentity = { 21 | identifier: ProtocolAddress; 22 | identifierKey: Uint8Array; 23 | }; 24 | export type LTHashState = { 25 | version: number; 26 | hash: Buffer; 27 | indexValueMap: { 28 | [indexMacBase64: string]: { 29 | valueMac: Uint8Array | Buffer; 30 | }; 31 | }; 32 | }; 33 | export type SignalCreds = { 34 | readonly signedIdentityKey: KeyPair; 35 | readonly signedPreKey: SignedKeyPair; 36 | readonly registrationId: number; 37 | }; 38 | export type AccountSettings = { 39 | /** unarchive chats when a new message is received */ 40 | unarchiveChats: boolean; 41 | /** the default mode to start new conversations with */ 42 | defaultDisappearingMode?: Pick; 43 | }; 44 | export type AuthenticationCreds = SignalCreds & { 45 | readonly noiseKey: KeyPair; 46 | readonly pairingEphemeralKeyPair: KeyPair; 47 | advSecretKey: string; 48 | me?: Contact; 49 | account?: proto.IADVSignedDeviceIdentity; 50 | signalIdentities?: SignalIdentity[]; 51 | myAppStateKeyId?: string; 52 | firstUnuploadedPreKeyId: number; 53 | nextPreKeyId: number; 54 | lastAccountSyncTimestamp?: number; 55 | platform?: string; 56 | processedHistoryMessages: MinimalMessage[]; 57 | /** number of times history & app state has been synced */ 58 | accountSyncCounter: number; 59 | accountSettings: AccountSettings; 60 | deviceId: string; 61 | phoneId: string; 62 | identityId: Buffer; 63 | registered: boolean; 64 | backupToken: Buffer; 65 | registration: RegistrationOptions; 66 | pairingCode: string | undefined; 67 | lastPropHash: string | undefined; 68 | routingInfo: Buffer | undefined; 69 | }; 70 | export type SignalDataTypeMap = { 71 | 'pre-key': KeyPair; 72 | 'session': Uint8Array; 73 | 'sender-key': Uint8Array; 74 | 'sender-key-memory': { 75 | [jid: string]: boolean; 76 | }; 77 | 'app-state-sync-key': proto.Message.IAppStateSyncKeyData; 78 | 'app-state-sync-version': LTHashState; 79 | }; 80 | export type SignalDataSet = { 81 | [T in keyof SignalDataTypeMap]?: { 82 | [id: string]: SignalDataTypeMap[T] | null; 83 | }; 84 | }; 85 | type Awaitable = T | Promise; 86 | export type SignalKeyStore = { 87 | get(type: T, ids: string[]): Awaitable<{ 88 | [id: string]: SignalDataTypeMap[T]; 89 | }>; 90 | set(data: SignalDataSet): Awaitable; 91 | /** clear all the data in the store */ 92 | clear?(): Awaitable; 93 | }; 94 | export type SignalKeyStoreWithTransaction = SignalKeyStore & { 95 | isInTransaction: () => boolean; 96 | transaction(exec: () => Promise): Promise; 97 | }; 98 | export type TransactionCapabilityOptions = { 99 | maxCommitRetries: number; 100 | delayBetweenTriesMs: number; 101 | }; 102 | export type SignalAuthState = { 103 | creds: SignalCreds; 104 | keys: SignalKeyStore | SignalKeyStoreWithTransaction; 105 | }; 106 | export type AuthenticationState = { 107 | creds: AuthenticationCreds; 108 | keys: SignalKeyStore; 109 | }; 110 | export {}; 111 | -------------------------------------------------------------------------------- /lib/Utils/chat-utils.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { AxiosRequestConfig } from 'axios'; 3 | import type { Logger } from 'pino'; 4 | import { proto } from '../../WAProto'; 5 | import { BaileysEventEmitter, ChatModification, ChatMutation, Contact, InitialAppStateSyncOptions, LTHashState, WAPatchCreate, WAPatchName } from '../Types'; 6 | import { BinaryNode } from '../WABinary'; 7 | type FetchAppStateSyncKey = (keyId: string) => Promise; 8 | export type ChatMutationMap = { 9 | [index: string]: ChatMutation; 10 | }; 11 | export declare const newLTHashState: () => LTHashState; 12 | export declare const encodeSyncdPatch: ({ type, index, syncAction, apiVersion, operation }: WAPatchCreate, myAppStateKeyId: string, state: LTHashState, getAppStateSyncKey: FetchAppStateSyncKey) => Promise<{ 13 | patch: proto.ISyncdPatch; 14 | state: LTHashState; 15 | }>; 16 | export declare const decodeSyncdMutations: (msgMutations: (proto.ISyncdMutation | proto.ISyncdRecord)[], initialState: LTHashState, getAppStateSyncKey: FetchAppStateSyncKey, onMutation: (mutation: ChatMutation) => void, validateMacs: boolean) => Promise<{ 17 | hash: Buffer; 18 | indexValueMap: { 19 | [indexMacBase64: string]: { 20 | valueMac: Uint8Array | Buffer; 21 | }; 22 | }; 23 | }>; 24 | export declare const decodeSyncdPatch: (msg: proto.ISyncdPatch, name: WAPatchName, initialState: LTHashState, getAppStateSyncKey: FetchAppStateSyncKey, onMutation: (mutation: ChatMutation) => void, validateMacs: boolean) => Promise<{ 25 | hash: Buffer; 26 | indexValueMap: { 27 | [indexMacBase64: string]: { 28 | valueMac: Uint8Array | Buffer; 29 | }; 30 | }; 31 | }>; 32 | export declare const extractSyncdPatches: (result: BinaryNode, options: AxiosRequestConfig) => Promise<{ 33 | critical_block: { 34 | patches: proto.ISyncdPatch[]; 35 | hasMorePatches: boolean; 36 | snapshot?: proto.ISyncdSnapshot | undefined; 37 | }; 38 | critical_unblock_low: { 39 | patches: proto.ISyncdPatch[]; 40 | hasMorePatches: boolean; 41 | snapshot?: proto.ISyncdSnapshot | undefined; 42 | }; 43 | regular_high: { 44 | patches: proto.ISyncdPatch[]; 45 | hasMorePatches: boolean; 46 | snapshot?: proto.ISyncdSnapshot | undefined; 47 | }; 48 | regular_low: { 49 | patches: proto.ISyncdPatch[]; 50 | hasMorePatches: boolean; 51 | snapshot?: proto.ISyncdSnapshot | undefined; 52 | }; 53 | regular: { 54 | patches: proto.ISyncdPatch[]; 55 | hasMorePatches: boolean; 56 | snapshot?: proto.ISyncdSnapshot | undefined; 57 | }; 58 | }>; 59 | export declare const downloadExternalBlob: (blob: proto.IExternalBlobReference, options: AxiosRequestConfig) => Promise; 60 | export declare const downloadExternalPatch: (blob: proto.IExternalBlobReference, options: AxiosRequestConfig) => Promise; 61 | export declare const decodeSyncdSnapshot: (name: WAPatchName, snapshot: proto.ISyncdSnapshot, getAppStateSyncKey: FetchAppStateSyncKey, minimumVersionNumber: number | undefined, validateMacs?: boolean) => Promise<{ 62 | state: LTHashState; 63 | mutationMap: ChatMutationMap; 64 | }>; 65 | export declare const decodePatches: (name: WAPatchName, syncds: proto.ISyncdPatch[], initial: LTHashState, getAppStateSyncKey: FetchAppStateSyncKey, options: AxiosRequestConfig, minimumVersionNumber?: number, logger?: Logger, validateMacs?: boolean) => Promise<{ 66 | state: LTHashState; 67 | mutationMap: ChatMutationMap; 68 | }>; 69 | export declare const chatModificationToAppPatch: (mod: ChatModification, jid: string) => WAPatchCreate; 70 | export declare const processSyncAction: (syncAction: ChatMutation, ev: BaileysEventEmitter, me: Contact, initialSyncOpts?: InitialAppStateSyncOptions, logger?: Logger) => void; 71 | export {}; 72 | -------------------------------------------------------------------------------- /lib/Types/Chat.d.ts: -------------------------------------------------------------------------------- 1 | import type { proto } from '../../WAProto'; 2 | import type { AccountSettings } from './Auth'; 3 | import type { BufferedEventData } from './Events'; 4 | import type { ChatLabelAssociationActionBody } from './LabelAssociation'; 5 | import type { MessageLabelAssociationActionBody } from './LabelAssociation'; 6 | import type { MinimalMessage } from './Message'; 7 | /** privacy settings in WhatsApp Web */ 8 | export type WAPrivacyValue = 'all' | 'contacts' | 'contact_blacklist' | 'none'; 9 | export type WAPrivacyOnlineValue = 'all' | 'match_last_seen'; 10 | export type WAReadReceiptsValue = 'all' | 'none'; 11 | /** set of statuses visible to other people; see updatePresence() in WhatsAppWeb.Send */ 12 | export type WAPresence = 'unavailable' | 'available' | 'composing' | 'recording' | 'paused'; 13 | export declare const ALL_WA_PATCH_NAMES: readonly ["critical_block", "critical_unblock_low", "regular_high", "regular_low", "regular"]; 14 | export type WAPatchName = typeof ALL_WA_PATCH_NAMES[number]; 15 | export interface PresenceData { 16 | lastKnownPresence: WAPresence; 17 | lastSeen?: number; 18 | } 19 | export type ChatMutation = { 20 | syncAction: proto.ISyncActionData; 21 | index: string[]; 22 | }; 23 | export type WAPatchCreate = { 24 | syncAction: proto.ISyncActionValue; 25 | index: string[]; 26 | type: WAPatchName; 27 | apiVersion: number; 28 | operation: proto.SyncdMutation.SyncdOperation; 29 | }; 30 | export type Chat = proto.IConversation & { 31 | /** unix timestamp of when the last message was received in the chat */ 32 | lastMessageRecvTimestamp?: number; 33 | }; 34 | export type ChatUpdate = Partial boolean | undefined; 45 | }>; 46 | /** 47 | * the last messages in a chat, sorted reverse-chronologically. That is, the latest message should be first in the chat 48 | * for MD modifications, the last message in the array (i.e. the earlist message) must be the last message recv in the chat 49 | * */ 50 | export type LastMessageList = MinimalMessage[] | proto.SyncActionValue.ISyncActionMessageRange; 51 | export type ChatModification = { 52 | archive: boolean; 53 | lastMessages: LastMessageList; 54 | } | { 55 | pushNameSetting: string; 56 | } | { 57 | pin: boolean; 58 | } | { 59 | /** mute for duration, or provide timestamp of mute to remove*/ 60 | mute: number | null; 61 | } | { 62 | clear: 'all' | { 63 | messages: { 64 | id: string; 65 | fromMe?: boolean; 66 | timestamp: number; 67 | }[]; 68 | }; 69 | } | { 70 | star: { 71 | messages: { 72 | id: string; 73 | fromMe?: boolean; 74 | }[]; 75 | star: boolean; 76 | }; 77 | } | { 78 | markRead: boolean; 79 | lastMessages: LastMessageList; 80 | } | { 81 | delete: true; 82 | lastMessages: LastMessageList; 83 | } | { 84 | addChatLabel: ChatLabelAssociationActionBody; 85 | } | { 86 | removeChatLabel: ChatLabelAssociationActionBody; 87 | } | { 88 | addMessageLabel: MessageLabelAssociationActionBody; 89 | } | { 90 | removeMessageLabel: MessageLabelAssociationActionBody; 91 | }; 92 | export type InitialReceivedChatsState = { 93 | [jid: string]: { 94 | /** the last message received from the other party */ 95 | lastMsgRecvTimestamp?: number; 96 | /** the absolute last message in the chat */ 97 | lastMsgTimestamp: number; 98 | }; 99 | }; 100 | export type InitialAppStateSyncOptions = { 101 | accountSettings: AccountSettings; 102 | }; 103 | -------------------------------------------------------------------------------- /lib/Utils/link-preview.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.getUrlInfo = void 0; 4 | const messages_1 = require("./messages"); 5 | const messages_media_1 = require("./messages-media"); 6 | const THUMBNAIL_WIDTH_PX = 192; 7 | /** Fetches an image and generates a thumbnail for it */ 8 | const getCompressedJpegThumbnail = async (url, { thumbnailWidth, fetchOpts }) => { 9 | const stream = await (0, messages_media_1.getHttpStream)(url, fetchOpts); 10 | const result = await (0, messages_media_1.extractImageThumb)(stream, thumbnailWidth); 11 | return result; 12 | }; 13 | /** 14 | * Given a piece of text, checks for any URL present, generates link preview for the same and returns it 15 | * Return undefined if the fetch failed or no URL was found 16 | * @param text first matched URL in text 17 | * @returns the URL info required to generate link preview 18 | */ 19 | const getUrlInfo = async (text, opts = { 20 | thumbnailWidth: THUMBNAIL_WIDTH_PX, 21 | fetchOpts: { timeout: 3000 } 22 | }) => { 23 | var _a; 24 | try { 25 | // retries 26 | const retries = 0; 27 | const maxRetry = 5; 28 | const { getLinkPreview } = await import('link-preview-js'); 29 | let previewLink = text; 30 | if (!text.startsWith('https://') && !text.startsWith('http://')) { 31 | previewLink = 'https://' + previewLink; 32 | } 33 | const info = await getLinkPreview(previewLink, { 34 | ...opts.fetchOpts, 35 | followRedirects: 'follow', 36 | handleRedirects: (baseURL, forwardedURL) => { 37 | const urlObj = new URL(baseURL); 38 | const forwardedURLObj = new URL(forwardedURL); 39 | if (retries >= maxRetry) { 40 | return false; 41 | } 42 | if (forwardedURLObj.hostname === urlObj.hostname 43 | || forwardedURLObj.hostname === 'www.' + urlObj.hostname 44 | || 'www.' + forwardedURLObj.hostname === urlObj.hostname) { 45 | retries + 1; 46 | return true; 47 | } 48 | else { 49 | return false; 50 | } 51 | }, 52 | headers: opts.fetchOpts 53 | }); 54 | if (info && 'title' in info && info.title) { 55 | const [image] = info.images; 56 | const urlInfo = { 57 | 'canonical-url': info.url, 58 | 'matched-text': text, 59 | title: info.title, 60 | description: info.description, 61 | originalThumbnailUrl: image 62 | }; 63 | if (opts.uploadImage) { 64 | const { imageMessage } = await (0, messages_1.prepareWAMessageMedia)({ image: { url: image } }, { 65 | upload: opts.uploadImage, 66 | mediaTypeOverride: 'thumbnail-link', 67 | options: opts.fetchOpts 68 | }); 69 | urlInfo.jpegThumbnail = (imageMessage === null || imageMessage === void 0 ? void 0 : imageMessage.jpegThumbnail) 70 | ? Buffer.from(imageMessage.jpegThumbnail) 71 | : undefined; 72 | urlInfo.highQualityThumbnail = imageMessage || undefined; 73 | } 74 | else { 75 | try { 76 | urlInfo.jpegThumbnail = image 77 | ? (await getCompressedJpegThumbnail(image, opts)).buffer 78 | : undefined; 79 | } 80 | catch (error) { 81 | (_a = opts.logger) === null || _a === void 0 ? void 0 : _a.debug({ err: error.stack, url: previewLink }, 'error in generating thumbnail'); 82 | } 83 | } 84 | return urlInfo; 85 | } 86 | } 87 | catch (error) { 88 | if (!error.message.includes('receive a valid')) { 89 | throw error; 90 | } 91 | } 92 | }; 93 | exports.getUrlInfo = getUrlInfo; 94 | -------------------------------------------------------------------------------- /WASignalGroup/group_cipher.js: -------------------------------------------------------------------------------- 1 | const queue_job = require('./queue_job'); 2 | const SenderKeyMessage = require('./sender_key_message'); 3 | const crypto = require('libsignal/src/crypto'); 4 | 5 | class GroupCipher { 6 | constructor(senderKeyStore, senderKeyName) { 7 | this.senderKeyStore = senderKeyStore; 8 | this.senderKeyName = senderKeyName; 9 | } 10 | 11 | queueJob(awaitable) { 12 | return queue_job(this.senderKeyName.toString(), awaitable) 13 | } 14 | 15 | async encrypt(paddedPlaintext) { 16 | return await this.queueJob(async () => { 17 | const record = await this.senderKeyStore.loadSenderKey(this.senderKeyName); 18 | if (!record) { 19 | throw new Error("No SenderKeyRecord found for encryption") 20 | } 21 | const senderKeyState = record.getSenderKeyState(); 22 | if (!senderKeyState) { 23 | throw new Error("No session to encrypt message"); 24 | } 25 | const iteration = senderKeyState.getSenderChainKey().getIteration() 26 | const senderKey = this.getSenderKey(senderKeyState, iteration === 0 ? 0 : iteration + 1) 27 | 28 | const ciphertext = await this.getCipherText( 29 | senderKey.getIv(), 30 | senderKey.getCipherKey(), 31 | paddedPlaintext 32 | ); 33 | 34 | const senderKeyMessage = new SenderKeyMessage( 35 | senderKeyState.getKeyId(), 36 | senderKey.getIteration(), 37 | ciphertext, 38 | senderKeyState.getSigningKeyPrivate() 39 | ); 40 | await this.senderKeyStore.storeSenderKey(this.senderKeyName, record); 41 | return senderKeyMessage.serialize() 42 | }) 43 | } 44 | 45 | async decrypt(senderKeyMessageBytes) { 46 | return await this.queueJob(async () => { 47 | const record = await this.senderKeyStore.loadSenderKey(this.senderKeyName); 48 | if (!record) { 49 | throw new Error("No SenderKeyRecord found for decryption") 50 | } 51 | const senderKeyMessage = new SenderKeyMessage(null, null, null, null, senderKeyMessageBytes); 52 | const senderKeyState = record.getSenderKeyState(senderKeyMessage.getKeyId()); 53 | if (!senderKeyState) { 54 | throw new Error("No session found to decrypt message") 55 | } 56 | 57 | senderKeyMessage.verifySignature(senderKeyState.getSigningKeyPublic()); 58 | const senderKey = this.getSenderKey(senderKeyState, senderKeyMessage.getIteration()); 59 | // senderKeyState.senderKeyStateStructure.senderSigningKey.private = 60 | 61 | const plaintext = await this.getPlainText( 62 | senderKey.getIv(), 63 | senderKey.getCipherKey(), 64 | senderKeyMessage.getCipherText() 65 | ); 66 | 67 | await this.senderKeyStore.storeSenderKey(this.senderKeyName, record); 68 | 69 | return plaintext; 70 | }) 71 | } 72 | 73 | getSenderKey(senderKeyState, iteration) { 74 | let senderChainKey = senderKeyState.getSenderChainKey(); 75 | if (senderChainKey.getIteration() > iteration) { 76 | if (senderKeyState.hasSenderMessageKey(iteration)) { 77 | return senderKeyState.removeSenderMessageKey(iteration); 78 | } 79 | throw new Error( 80 | `Received message with old counter: ${senderChainKey.getIteration()}, ${iteration}` 81 | ); 82 | } 83 | 84 | if (iteration - senderChainKey.getIteration() > 2000) { 85 | throw new Error('Over 2000 messages into the future!'); 86 | } 87 | 88 | while (senderChainKey.getIteration() < iteration) { 89 | senderKeyState.addSenderMessageKey(senderChainKey.getSenderMessageKey()); 90 | senderChainKey = senderChainKey.getNext(); 91 | } 92 | 93 | senderKeyState.setSenderChainKey(senderChainKey.getNext()); 94 | return senderChainKey.getSenderMessageKey(); 95 | } 96 | 97 | getPlainText(iv, key, ciphertext) { 98 | try { 99 | const plaintext = crypto.decrypt(key, ciphertext, iv); 100 | return plaintext; 101 | } catch (e) { 102 | //console.log(e.stack); 103 | throw new Error('InvalidMessageException'); 104 | } 105 | } 106 | 107 | getCipherText(iv, key, plaintext) { 108 | try { 109 | iv = typeof iv === 'string' ? Buffer.from(iv, 'base64') : iv; 110 | key = typeof key === 'string' ? Buffer.from(key, 'base64') : key; 111 | const crypted = crypto.encrypt(key, Buffer.from(plaintext), iv); 112 | return crypted; 113 | } catch (e) { 114 | //console.log(e.stack); 115 | throw new Error('InvalidMessageException'); 116 | } 117 | } 118 | } 119 | 120 | module.exports = GroupCipher; -------------------------------------------------------------------------------- /lib/Utils/history.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.getHistoryMsg = exports.downloadAndProcessHistorySyncNotification = exports.processHistoryMessage = exports.downloadHistory = void 0; 4 | const util_1 = require("util"); 5 | const zlib_1 = require("zlib"); 6 | const WAProto_1 = require("../../WAProto"); 7 | const Types_1 = require("../Types"); 8 | const WABinary_1 = require("../WABinary"); 9 | const generics_1 = require("./generics"); 10 | const messages_1 = require("./messages"); 11 | const messages_media_1 = require("./messages-media"); 12 | const inflatePromise = (0, util_1.promisify)(zlib_1.inflate); 13 | const downloadHistory = async (msg, options) => { 14 | const stream = await (0, messages_media_1.downloadContentFromMessage)(msg, 'md-msg-hist', { options }); 15 | const bufferArray = []; 16 | for await (const chunk of stream) { 17 | bufferArray.push(chunk); 18 | } 19 | let buffer = Buffer.concat(bufferArray); 20 | // decompress buffer 21 | buffer = await inflatePromise(buffer); 22 | const syncData = WAProto_1.proto.HistorySync.decode(buffer); 23 | return syncData; 24 | }; 25 | exports.downloadHistory = downloadHistory; 26 | const processHistoryMessage = (item) => { 27 | var _a, _b, _c; 28 | const messages = []; 29 | const contacts = []; 30 | const chats = []; 31 | switch (item.syncType) { 32 | case WAProto_1.proto.HistorySync.HistorySyncType.INITIAL_BOOTSTRAP: 33 | case WAProto_1.proto.HistorySync.HistorySyncType.RECENT: 34 | case WAProto_1.proto.HistorySync.HistorySyncType.FULL: 35 | for (const chat of item.conversations) { 36 | contacts.push({ id: chat.id, name: chat.name || undefined }); 37 | const msgs = chat.messages || []; 38 | delete chat.messages; 39 | delete chat.archived; 40 | delete chat.muteEndTime; 41 | delete chat.pinned; 42 | for (const item of msgs) { 43 | const message = item.message; 44 | messages.push(message); 45 | if (!((_a = chat.messages) === null || _a === void 0 ? void 0 : _a.length)) { 46 | // keep only the most recent message in the chat array 47 | chat.messages = [{ message }]; 48 | } 49 | if (!message.key.fromMe && !chat.lastMessageRecvTimestamp) { 50 | chat.lastMessageRecvTimestamp = (0, generics_1.toNumber)(message.messageTimestamp); 51 | } 52 | if ((message.messageStubType === Types_1.WAMessageStubType.BIZ_PRIVACY_MODE_TO_BSP 53 | || message.messageStubType === Types_1.WAMessageStubType.BIZ_PRIVACY_MODE_TO_FB) 54 | && ((_b = message.messageStubParameters) === null || _b === void 0 ? void 0 : _b[0])) { 55 | contacts.push({ 56 | id: message.key.participant || message.key.remoteJid, 57 | verifiedName: (_c = message.messageStubParameters) === null || _c === void 0 ? void 0 : _c[0], 58 | }); 59 | } 60 | } 61 | if ((0, WABinary_1.isJidUser)(chat.id) && chat.readOnly && chat.archived) { 62 | delete chat.readOnly; 63 | } 64 | chats.push({ ...chat }); 65 | } 66 | break; 67 | case WAProto_1.proto.HistorySync.HistorySyncType.PUSH_NAME: 68 | for (const c of item.pushnames) { 69 | contacts.push({ id: c.id, notify: c.pushname }); 70 | } 71 | break; 72 | } 73 | return { 74 | chats, 75 | contacts, 76 | messages, 77 | }; 78 | }; 79 | exports.processHistoryMessage = processHistoryMessage; 80 | const downloadAndProcessHistorySyncNotification = async (msg, options) => { 81 | const historyMsg = await (0, exports.downloadHistory)(msg, options); 82 | return (0, exports.processHistoryMessage)(historyMsg); 83 | }; 84 | exports.downloadAndProcessHistorySyncNotification = downloadAndProcessHistorySyncNotification; 85 | const getHistoryMsg = (message) => { 86 | var _a; 87 | const normalizedContent = !!message ? (0, messages_1.normalizeMessageContent)(message) : undefined; 88 | const anyHistoryMsg = (_a = normalizedContent === null || normalizedContent === void 0 ? void 0 : normalizedContent.protocolMessage) === null || _a === void 0 ? void 0 : _a.historySyncNotification; 89 | return anyHistoryMsg; 90 | }; 91 | exports.getHistoryMsg = getHistoryMsg; 92 | -------------------------------------------------------------------------------- /lib/Defaults/phonenumber-mcc.json: -------------------------------------------------------------------------------- 1 | { 2 | "93": 412, 3 | "355": 276, 4 | "213": 603, 5 | "1-684": 544, 6 | "376": 213, 7 | "244": 631, 8 | "1-264": 365, 9 | "1-268": 344, 10 | "54": 722, 11 | "374": 283, 12 | "297": 363, 13 | "61": 505, 14 | "43": 232, 15 | "994": 400, 16 | "1-242": 364, 17 | "973": 426, 18 | "880": 470, 19 | "1-246": 342, 20 | "375": 257, 21 | "32": 206, 22 | "501": 702, 23 | "229": 616, 24 | "1-441": 350, 25 | "975": 402, 26 | "591": 736, 27 | "387": 218, 28 | "267": 652, 29 | "55": 724, 30 | "1-284": 348, 31 | "673": 528, 32 | "359": 284, 33 | "226": 613, 34 | "257": 642, 35 | "855": 456, 36 | "237": 624, 37 | "238": 625, 38 | "1-345": 346, 39 | "236": 623, 40 | "235": 622, 41 | "56": 730, 42 | "86": 454, 43 | "57": 732, 44 | "269": 654, 45 | "682": 548, 46 | "506": 712, 47 | "385": 219, 48 | "53": 368, 49 | "357": 280, 50 | "420": 230, 51 | "243": 630, 52 | "45": 238, 53 | "253": 638, 54 | "1-767": 366, 55 | "1-809": 370, 56 | "1-849": 370, 57 | "1-829": 370, 58 | "593": 740, 59 | "20": 602, 60 | "503": 706, 61 | "240": 627, 62 | "291": 657, 63 | "372": 248, 64 | "251": 636, 65 | "500": 750, 66 | "298": 288, 67 | "679": 542, 68 | "358": 244, 69 | "33": 208, 70 | "689": 547, 71 | "241": 628, 72 | "220": 607, 73 | "995": 282, 74 | "49": 262, 75 | "233": 620, 76 | "350": 266, 77 | "30": 202, 78 | "299": 290, 79 | "1-473": 352, 80 | "1-671": 535, 81 | "502": 704, 82 | "224": 537, 83 | "592": 738, 84 | "509": 372, 85 | "504": 708, 86 | "852": 454, 87 | "36": 216, 88 | "354": 274, 89 | "91": 404, 90 | "62": 510, 91 | "98": 432, 92 | "964": 418, 93 | "353": 234, 94 | "972": 425, 95 | "39": 222, 96 | "225": 612, 97 | "1-876": 338, 98 | "81": 440, 99 | "962": 416, 100 | "254": 639, 101 | "686": 545, 102 | "383": 221, 103 | "965": 419, 104 | "371": 247, 105 | "961": 415, 106 | "266": 651, 107 | "231": 618, 108 | "218": 606, 109 | "423": 295, 110 | "370": 246, 111 | "352": 270, 112 | "389": 294, 113 | "261": 646, 114 | "265": 650, 115 | "60": 502, 116 | "960": 472, 117 | "223": 610, 118 | "356": 278, 119 | "692": 551, 120 | "222": 609, 121 | "230": 617, 122 | "52": 334, 123 | "691": 550, 124 | "373": 259, 125 | "377": 212, 126 | "976": 428, 127 | "382": 297, 128 | "1-664": 354, 129 | "212": 604, 130 | "258": 643, 131 | "95": 414, 132 | "264": 649, 133 | "674": 536, 134 | "977": 429, 135 | "31": 204, 136 | "687": 546, 137 | "64": 530, 138 | "505": 710, 139 | "227": 614, 140 | "234": 621, 141 | "683": 555, 142 | "1-670": 534, 143 | "47": 242, 144 | "968": 226, 145 | "92": 410, 146 | "680": 552, 147 | "970": 423, 148 | "507": 714, 149 | "675": 537, 150 | "595": 744, 151 | "51": 716, 152 | "63": 515, 153 | "48": 260, 154 | "351": 268, 155 | "1-787, 1-939": 330, 156 | "974": 427, 157 | "242": 630, 158 | "40": 226, 159 | "7": 250, 160 | "250": 635, 161 | "290": 658, 162 | "1-869": 356, 163 | "1-758": 358, 164 | "508": 308, 165 | "1-784": 360, 166 | "685": 544, 167 | "378": 292, 168 | "239": 626, 169 | "966": 420, 170 | "221": 608, 171 | "381": 220, 172 | "248": 633, 173 | "232": 619, 174 | "65": 525, 175 | "386": 293, 176 | "677": 540, 177 | "27": 655, 178 | "211": 659, 179 | "34": 214, 180 | "94": 413, 181 | "249": 634, 182 | "597": 746, 183 | "268": 653, 184 | "46": 240, 185 | "41": 228, 186 | "963": 417, 187 | "886": 466, 188 | "992": 436, 189 | "255": 640, 190 | "66": 520, 191 | "228": 615, 192 | "690": 554, 193 | "676": 539, 194 | "1-868": 374, 195 | "216": 605, 196 | "90": 286, 197 | "993": 438, 198 | "1-649": 376, 199 | "688": 553, 200 | "1-340": 332, 201 | "256": 641, 202 | "380": 255, 203 | "971": 424, 204 | "44": 234, 205 | "1": 310, 206 | "598": 748, 207 | "998": 434, 208 | "678": 541, 209 | "379": 225, 210 | "58": 734, 211 | "681": 543, 212 | "967": 421, 213 | "260": 645, 214 | "263": 648, 215 | "670": 514, 216 | "245": 632, 217 | "856": 457, 218 | "599": 362, 219 | "850": 467, 220 | "262": 647, 221 | "82": 450, 222 | "84": 452 223 | } 224 | -------------------------------------------------------------------------------- /lib/WABinary/generic-utils.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.binaryNodeToString = exports.getBinaryNodeMessages = exports.reduceBinaryNodeToDictionary = exports.assertNodeErrorFree = exports.getBinaryNodeChildUInt = exports.getBinaryNodeChildString = exports.getBinaryNodeChildBuffer = exports.getBinaryNodeChild = exports.getAllBinaryNodeChildren = exports.getBinaryNodeChildren = void 0; 4 | const boom_1 = require("@hapi/boom"); 5 | const WAProto_1 = require("../../WAProto"); 6 | // some extra useful utilities 7 | const getBinaryNodeChildren = (node, childTag) => { 8 | if (Array.isArray(node === null || node === void 0 ? void 0 : node.content)) { 9 | return node.content.filter(item => item.tag === childTag); 10 | } 11 | return []; 12 | }; 13 | exports.getBinaryNodeChildren = getBinaryNodeChildren; 14 | const getAllBinaryNodeChildren = ({ content }) => { 15 | if (Array.isArray(content)) { 16 | return content; 17 | } 18 | return []; 19 | }; 20 | exports.getAllBinaryNodeChildren = getAllBinaryNodeChildren; 21 | const getBinaryNodeChild = (node, childTag) => { 22 | if (Array.isArray(node === null || node === void 0 ? void 0 : node.content)) { 23 | return node === null || node === void 0 ? void 0 : node.content.find(item => item.tag === childTag); 24 | } 25 | }; 26 | exports.getBinaryNodeChild = getBinaryNodeChild; 27 | const getBinaryNodeChildBuffer = (node, childTag) => { 28 | var _a; 29 | const child = (_a = (0, exports.getBinaryNodeChild)(node, childTag)) === null || _a === void 0 ? void 0 : _a.content; 30 | if (Buffer.isBuffer(child) || child instanceof Uint8Array) { 31 | return child; 32 | } 33 | }; 34 | exports.getBinaryNodeChildBuffer = getBinaryNodeChildBuffer; 35 | const getBinaryNodeChildString = (node, childTag) => { 36 | var _a; 37 | const child = (_a = (0, exports.getBinaryNodeChild)(node, childTag)) === null || _a === void 0 ? void 0 : _a.content; 38 | if (Buffer.isBuffer(child) || child instanceof Uint8Array) { 39 | return Buffer.from(child).toString('utf-8'); 40 | } 41 | else if (typeof child === 'string') { 42 | return child; 43 | } 44 | }; 45 | exports.getBinaryNodeChildString = getBinaryNodeChildString; 46 | const getBinaryNodeChildUInt = (node, childTag, length) => { 47 | const buff = (0, exports.getBinaryNodeChildBuffer)(node, childTag); 48 | if (buff) { 49 | return bufferToUInt(buff, length); 50 | } 51 | }; 52 | exports.getBinaryNodeChildUInt = getBinaryNodeChildUInt; 53 | const assertNodeErrorFree = (node) => { 54 | const errNode = (0, exports.getBinaryNodeChild)(node, 'error'); 55 | if (errNode) { 56 | throw new boom_1.Boom(errNode.attrs.text || 'Unknown error', { data: +errNode.attrs.code }); 57 | } 58 | }; 59 | exports.assertNodeErrorFree = assertNodeErrorFree; 60 | const reduceBinaryNodeToDictionary = (node, tag) => { 61 | const nodes = (0, exports.getBinaryNodeChildren)(node, tag); 62 | const dict = nodes.reduce((dict, { attrs }) => { 63 | dict[attrs.name || attrs.config_code] = attrs.value || attrs.config_value; 64 | return dict; 65 | }, {}); 66 | return dict; 67 | }; 68 | exports.reduceBinaryNodeToDictionary = reduceBinaryNodeToDictionary; 69 | const getBinaryNodeMessages = ({ content }) => { 70 | const msgs = []; 71 | if (Array.isArray(content)) { 72 | for (const item of content) { 73 | if (item.tag === 'message') { 74 | msgs.push(WAProto_1.proto.WebMessageInfo.decode(item.content)); 75 | } 76 | } 77 | } 78 | return msgs; 79 | }; 80 | exports.getBinaryNodeMessages = getBinaryNodeMessages; 81 | function bufferToUInt(e, t) { 82 | let a = 0; 83 | for (let i = 0; i < t; i++) { 84 | a = 256 * a + e[i]; 85 | } 86 | return a; 87 | } 88 | const tabs = (n) => '\t'.repeat(n); 89 | function binaryNodeToString(node, i = 0) { 90 | if (!node) { 91 | return node; 92 | } 93 | if (typeof node === 'string') { 94 | return tabs(i) + node; 95 | } 96 | if (node instanceof Uint8Array) { 97 | return tabs(i) + Buffer.from(node).toString('hex'); 98 | } 99 | if (Array.isArray(node)) { 100 | return node.map((x) => tabs(i + 1) + binaryNodeToString(x, i + 1)).join('\n'); 101 | } 102 | const children = binaryNodeToString(node.content, i + 1); 103 | const tag = `<${node.tag} ${Object.entries(node.attrs || {}) 104 | .filter(([, v]) => v !== undefined) 105 | .map(([k, v]) => `${k}='${v}'`) 106 | .join(' ')}`; 107 | const content = children ? `>\n${children}\n${tabs(i)}` : '/>'; 108 | return tag + content; 109 | } 110 | exports.binaryNodeToString = binaryNodeToString; 111 | -------------------------------------------------------------------------------- /lib/Utils/generics.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { AxiosRequestConfig } from 'axios'; 3 | import { Logger } from 'pino'; 4 | import { proto } from '../../WAProto'; 5 | import { BaileysEventEmitter, BaileysEventMap, WACallUpdateType, WAVersion } from '../Types'; 6 | import { BinaryNode } from '../WABinary'; 7 | export declare const Browsers: { 8 | ubuntu: (browser: any) => [string, string, string]; 9 | macOS: (browser: any) => [string, string, string]; 10 | baileys: (browser: any) => [string, string, string]; 11 | windows: (browser: any) => [string, string, string]; 12 | /** The appropriate browser based on your OS & release */ 13 | appropriate: (browser: any) => [string, string, string]; 14 | }; 15 | export declare const BufferJSON: { 16 | replacer: (k: any, value: any) => any; 17 | reviver: (_: any, value: any) => any; 18 | }; 19 | export declare const getKeyAuthor: (key: proto.IMessageKey | undefined | null, meId?: string) => string; 20 | export declare const writeRandomPadMax16: (msg: Uint8Array) => Buffer; 21 | export declare const unpadRandomMax16: (e: Uint8Array | Buffer) => Uint8Array; 22 | export declare const encodeWAMessage: (message: proto.IMessage) => Buffer; 23 | export declare const generateRegistrationId: () => number; 24 | export declare const encodeBigEndian: (e: number, t?: number) => Uint8Array; 25 | export declare const toNumber: (t: Long | number | null | undefined) => number; 26 | /** unix timestamp of a date in seconds */ 27 | export declare const unixTimestampSeconds: (date?: Date) => number; 28 | export type DebouncedTimeout = ReturnType; 29 | export declare const debouncedTimeout: (intervalMs?: number, task?: () => void) => { 30 | start: (newIntervalMs?: number, newTask?: () => void) => void; 31 | cancel: () => void; 32 | setTask: (newTask: () => void) => () => void; 33 | setInterval: (newInterval: number) => number; 34 | }; 35 | export declare const delay: (ms: number) => Promise; 36 | export declare const delayCancellable: (ms: number) => { 37 | delay: Promise; 38 | cancel: () => void; 39 | }; 40 | export declare function promiseTimeout(ms: number | undefined, promise: (resolve: (v: T) => void, reject: (error: any) => void) => void): Promise; 41 | export declare const generateMessageIDV2: (userId?: string) => string; 42 | export declare const generateMessageID: () => string; 43 | export declare function bindWaitForEvent(ev: BaileysEventEmitter, event: T): (check: (u: BaileysEventMap[T]) => boolean | undefined, timeoutMs?: number) => Promise; 44 | export declare const bindWaitForConnectionUpdate: (ev: BaileysEventEmitter) => (check: (u: Partial) => boolean | undefined, timeoutMs?: number) => Promise; 45 | export declare const printQRIfNecessaryListener: (ev: BaileysEventEmitter, logger: Logger) => void; 46 | /** 47 | * utility that fetches latest baileys version from the master branch. 48 | * Use to ensure your WA connection is always on the latest version 49 | */ 50 | export declare const fetchLatestBaileysVersion: (options?: AxiosRequestConfig) => Promise<{ 51 | version: WAVersion; 52 | isLatest: boolean; 53 | error?: undefined; 54 | } | { 55 | version: WAVersion; 56 | isLatest: boolean; 57 | error: any; 58 | }>; 59 | /** 60 | * A utility that fetches the latest web version of whatsapp. 61 | * Use to ensure your WA connection is always on the latest version 62 | */ 63 | export declare const fetchLatestWaWebVersion: (options: AxiosRequestConfig) => Promise<{ 64 | version: WAVersion; 65 | isLatest: boolean; 66 | error?: undefined; 67 | } | { 68 | version: WAVersion; 69 | isLatest: boolean; 70 | error: any; 71 | }>; 72 | /** unique message tag prefix for MD clients */ 73 | export declare const generateMdTagPrefix: () => string; 74 | /** 75 | * Given a type of receipt, returns what the new status of the message should be 76 | * @param type type from receipt 77 | */ 78 | export declare const getStatusFromReceiptType: (type: string | undefined) => proto.WebMessageInfo.Status; 79 | /** 80 | * Stream errors generally provide a reason, map that to a baileys DisconnectReason 81 | * @param reason the string reason given, eg. "conflict" 82 | */ 83 | export declare const getErrorCodeFromStreamError: (node: BinaryNode) => { 84 | reason: string; 85 | statusCode: number; 86 | }; 87 | export declare const getCallStatusFromNode: ({ tag, attrs }: BinaryNode) => WACallUpdateType; 88 | export declare const getCodeFromWSError: (error: Error) => number; 89 | /** 90 | * Is the given platform WA business 91 | * @param platform AuthenticationCreds.platform 92 | */ 93 | export declare const isWABusinessPlatform: (platform: string) => boolean; 94 | export declare function trimUndefined(obj: any): any; 95 | export declare function bytesToCrockford(buffer: Buffer): string; 96 | -------------------------------------------------------------------------------- /lib/Socket/chats.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Boom } from '@hapi/boom'; 3 | import { proto } from '../../WAProto'; 4 | import { ChatModification, MessageUpsertType, SocketConfig, WABusinessProfile, WAMediaUpload, WAPatchCreate, WAPresence, WAPrivacyOnlineValue, WAPrivacyValue, WAReadReceiptsValue } from '../Types'; 5 | import { BinaryNode } from '../WABinary'; 6 | export declare const makeChatsSocket: (config: SocketConfig) => { 7 | processingMutex: { 8 | mutex(code: () => T | Promise): Promise; 9 | }; 10 | fetchPrivacySettings: (force?: boolean) => Promise<{ 11 | [_: string]: string; 12 | }>; 13 | upsertMessage: (msg: proto.IWebMessageInfo, type: MessageUpsertType) => Promise; 14 | appPatch: (patchCreate: WAPatchCreate) => Promise; 15 | sendPresenceUpdate: (type: WAPresence, toJid?: string) => Promise; 16 | presenceSubscribe: (toJid: string, tcToken?: Buffer) => Promise; 17 | profilePictureUrl: (jid: string, type?: 'preview' | 'image', timeoutMs?: number) => Promise; 18 | onWhatsApp: (...jids: string[]) => Promise<{ 19 | exists: boolean; 20 | jid: string; 21 | }[]>; 22 | fetchBlocklist: () => Promise; 23 | fetchStatus: (jid: string) => Promise<{ 24 | status: string | undefined; 25 | setAt: Date; 26 | } | undefined>; 27 | updateProfilePicture: (jid: string, content: WAMediaUpload) => Promise; 28 | removeProfilePicture: (jid: string) => Promise; 29 | updateProfileStatus: (status: string) => Promise; 30 | updateProfileName: (name: string) => Promise; 31 | updateBlockStatus: (jid: string, action: 'block' | 'unblock') => Promise; 32 | updateLastSeenPrivacy: (value: WAPrivacyValue) => Promise; 33 | updateOnlinePrivacy: (value: WAPrivacyOnlineValue) => Promise; 34 | updateProfilePicturePrivacy: (value: WAPrivacyValue) => Promise; 35 | updateStatusPrivacy: (value: WAPrivacyValue) => Promise; 36 | updateReadReceiptsPrivacy: (value: WAReadReceiptsValue) => Promise; 37 | updateGroupsAddPrivacy: (value: WAPrivacyValue) => Promise; 38 | updateDefaultDisappearingMode: (duration: number) => Promise; 39 | getBusinessProfile: (jid: string) => Promise; 40 | resyncAppState: (collections: readonly ("critical_block" | "critical_unblock_low" | "regular_high" | "regular_low" | "regular")[], isInitialSync: boolean) => Promise; 41 | chatModify: (mod: ChatModification, jid: string) => Promise; 42 | cleanDirtyBits: (type: 'account_sync' | 'groups', fromTimestamp?: number | string) => Promise; 43 | addChatLabel: (jid: string, labelId: string) => Promise; 44 | removeChatLabel: (jid: string, labelId: string) => Promise; 45 | addMessageLabel: (jid: string, messageId: string, labelId: string) => Promise; 46 | removeMessageLabel: (jid: string, messageId: string, labelId: string) => Promise; 47 | star: (jid: string, messages: { 48 | id: string; 49 | fromMe?: boolean; 50 | }[], star: boolean) => Promise; 51 | type: "md"; 52 | ws: any; 53 | ev: import("../Types").BaileysEventEmitter & { 54 | process(handler: (events: Partial) => void | Promise): () => void; 55 | buffer(): void; 56 | createBufferedFunction(work: (...args: A) => Promise): (...args: A) => Promise; 57 | flush(force?: boolean | undefined): boolean; 58 | isBuffering(): boolean; 59 | }; 60 | authState: { 61 | creds: import("../Types").AuthenticationCreds; 62 | keys: import("../Types").SignalKeyStoreWithTransaction; 63 | }; 64 | signalRepository: import("../Types").SignalRepository; 65 | user: import("../Types").Contact | undefined; 66 | generateMessageTag: () => string; 67 | query: (node: BinaryNode, timeoutMs?: number | undefined) => Promise; 68 | waitForMessage: (msgId: string, timeoutMs?: number | undefined) => Promise; 69 | waitForSocketOpen: () => Promise; 70 | sendRawMessage: (data: Uint8Array | Buffer) => Promise; 71 | sendNode: (frame: BinaryNode) => Promise; 72 | logout: (msg?: string | undefined) => Promise; 73 | end: (error: Error | undefined) => void; 74 | onUnexpectedError: (err: Error | Boom, msg: string) => void; 75 | uploadPreKeys: (count?: number) => Promise; 76 | uploadPreKeysToServerIfRequired: () => Promise; 77 | requestPairingCode: (phoneNumber: string) => Promise; 78 | waitForConnectionUpdate: (check: (u: Partial) => boolean | undefined, timeoutMs?: number | undefined) => Promise; 79 | sendWAMBuffer: (wamBuffer: Buffer) => Promise; 80 | }; 81 | -------------------------------------------------------------------------------- /lib/Utils/messages.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | import { Logger } from 'pino'; 4 | import { type Transform } from 'stream'; 5 | import { proto } from '../../WAProto'; 6 | import { AnyMediaMessageContent, AnyMessageContent, MediaGenerationOptions, MessageContentGenerationOptions, MessageGenerationOptions, MessageGenerationOptionsFromContent, MessageUserReceipt, WAMessage, WAMessageContent, WAProto } from '../Types'; 7 | import { MediaDownloadOptions } from './messages-media'; 8 | /** 9 | * Uses a regex to test whether the string contains a URL, and returns the URL if it does. 10 | * @param text eg. hello https://google.com 11 | * @returns the URL, eg. https://google.com 12 | */ 13 | export declare const extractUrlFromText: (text: string) => string | undefined; 14 | export declare const generateLinkPreviewIfRequired: (text: string, getUrlInfo: MessageGenerationOptions['getUrlInfo'], logger: MessageGenerationOptions['logger']) => Promise; 15 | export declare const prepareWAMessageMedia: (message: AnyMediaMessageContent, options: MediaGenerationOptions) => Promise; 16 | export declare const prepareDisappearingMessageSettingContent: (ephemeralExpiration?: number) => proto.Message; 17 | /** 18 | * Generate forwarded message content like WA does 19 | * @param message the message to forward 20 | * @param options.forceForward will show the message as forwarded even if it is from you 21 | */ 22 | export declare const generateForwardMessageContent: (message: WAMessage, forceForward?: boolean) => proto.IMessage; 23 | export declare const generateWAMessageContent: (message: AnyMessageContent, options: MessageContentGenerationOptions) => Promise; 24 | export declare const generateWAMessageFromContent: (jid: string, message: WAMessageContent, options: MessageGenerationOptionsFromContent) => proto.WebMessageInfo; 25 | export declare const generateWAMessage: (jid: string, content: AnyMessageContent, options: MessageGenerationOptions) => Promise; 26 | /** Get the key to access the true type of content */ 27 | export declare const getContentType: (content: WAProto.IMessage | undefined) => keyof proto.IMessage | undefined; 28 | /** 29 | * Normalizes ephemeral, view once messages to regular message content 30 | * Eg. image messages in ephemeral messages, in view once messages etc. 31 | * @param content 32 | * @returns 33 | */ 34 | export declare const normalizeMessageContent: (content: WAMessageContent | null | undefined) => WAMessageContent | undefined; 35 | /** 36 | * Extract the true message content from a message 37 | * Eg. extracts the inner message from a disappearing message/view once message 38 | */ 39 | export declare const extractMessageContent: (content: WAMessageContent | undefined | null) => WAMessageContent | undefined; 40 | /** 41 | * Returns the device predicted by message ID 42 | */ 43 | export declare const getDevice: (id: string) => "android" | "unknown" | "web" | "ios" | "desktop"; 44 | /** Upserts a receipt in the message */ 45 | export declare const updateMessageWithReceipt: (msg: Pick, receipt: MessageUserReceipt) => void; 46 | /** Update the message with a new reaction */ 47 | export declare const updateMessageWithReaction: (msg: Pick, reaction: proto.IReaction) => void; 48 | /** Update the message with a new poll update */ 49 | export declare const updateMessageWithPollUpdate: (msg: Pick, update: proto.IPollUpdate) => void; 50 | type VoteAggregation = { 51 | name: string; 52 | voters: string[]; 53 | }; 54 | /** 55 | * Aggregates all poll updates in a poll. 56 | * @param msg the poll creation message 57 | * @param meId your jid 58 | * @returns A list of options & their voters 59 | */ 60 | export declare function getAggregateVotesInPollMessage({ message, pollUpdates }: Pick, meId?: string): VoteAggregation[]; 61 | /** Given a list of message keys, aggregates them by chat & sender. Useful for sending read receipts in bulk */ 62 | export declare const aggregateMessageKeysNotFromMe: (keys: proto.IMessageKey[]) => { 63 | jid: string; 64 | participant: string | undefined; 65 | messageIds: string[]; 66 | }[]; 67 | type DownloadMediaMessageContext = { 68 | reuploadRequest: (msg: WAMessage) => Promise; 69 | logger: Logger; 70 | }; 71 | /** 72 | * Downloads the given message. Throws an error if it's not a media message 73 | */ 74 | export declare const downloadMediaMessage: (message: WAMessage, type: Type, options: MediaDownloadOptions, ctx?: DownloadMediaMessageContext) => Promise; 75 | /** Checks whether the given message is a media message; if it is returns the inner content */ 76 | export declare const assertMediaContent: (content: proto.IMessage | null | undefined) => proto.Message.IVideoMessage | proto.Message.IImageMessage | proto.Message.IAudioMessage | proto.Message.IDocumentMessage | proto.Message.IStickerMessage; 77 | export {}; 78 | -------------------------------------------------------------------------------- /lib/Types/Socket.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | import { AxiosRequestConfig } from 'axios'; 4 | import type { Agent } from 'https'; 5 | import type { Logger } from 'pino'; 6 | import type { URL } from 'url'; 7 | import { proto } from '../../WAProto'; 8 | import { AuthenticationState, SignalAuthState, TransactionCapabilityOptions } from './Auth'; 9 | import { MediaConnInfo } from './Message'; 10 | import { SignalRepository } from './Signal'; 11 | export type WAVersion = [number, number, number]; 12 | export type WABrowserDescription = [string, string, string]; 13 | export type CacheStore = { 14 | /** get a cached key and change the stats */ 15 | get(key: string): T | undefined; 16 | /** set a key in the cache */ 17 | set(key: string, value: T): void; 18 | /** delete a key from the cache */ 19 | del(key: string): void; 20 | /** flush all data */ 21 | flushAll(): void; 22 | }; 23 | export type SocketConfig = { 24 | /** the WS url to connect to WA */ 25 | waWebSocketUrl: string | URL; 26 | /** Fails the connection if the socket times out in this interval */ 27 | connectTimeoutMs: number; 28 | /** Default timeout for queries, undefined for no timeout */ 29 | defaultQueryTimeoutMs: number | undefined; 30 | /** ping-pong interval for WS connection */ 31 | keepAliveIntervalMs: number; 32 | /** should baileys use the mobile api instead of the multi device api */ 33 | mobile?: boolean; 34 | /** proxy agent */ 35 | agent?: Agent; 36 | /** pino logger */ 37 | logger: Logger; 38 | /** version to connect with */ 39 | version: WAVersion; 40 | /** override browser config */ 41 | browser: WABrowserDescription; 42 | /** agent used for fetch requests -- uploading/downloading media */ 43 | fetchAgent?: Agent; 44 | /** should the QR be printed in the terminal */ 45 | printQRInTerminal: boolean; 46 | /** should events be emitted for actions done by this socket connection */ 47 | emitOwnEvents: boolean; 48 | /** custom upload hosts to upload media to */ 49 | customUploadHosts: MediaConnInfo['hosts']; 50 | /** time to wait between sending new retry requests */ 51 | retryRequestDelayMs: number; 52 | /** max retry count */ 53 | maxMsgRetryCount: number; 54 | /** time to wait for the generation of the next QR in ms */ 55 | qrTimeout?: number; 56 | /** provide an auth state object to maintain the auth state */ 57 | auth: AuthenticationState; 58 | /** manage history processing with this control; by default will sync up everything */ 59 | shouldSyncHistoryMessage: (msg: proto.Message.IHistorySyncNotification) => boolean; 60 | /** transaction capability options for SignalKeyStore */ 61 | transactionOpts: TransactionCapabilityOptions; 62 | /** marks the client as online whenever the socket successfully connects */ 63 | markOnlineOnConnect: boolean; 64 | /** provide a cache to store media, so does not have to be re-uploaded */ 65 | mediaCache?: CacheStore; 66 | /** 67 | * map to store the retry counts for failed messages; 68 | * used to determine whether to retry a message or not */ 69 | msgRetryCounterCache?: CacheStore; 70 | /** provide a cache to store a user's device list */ 71 | userDevicesCache?: CacheStore; 72 | /** cache to store call offers */ 73 | callOfferCache?: CacheStore; 74 | /** width for link preview images */ 75 | linkPreviewImageThumbnailWidth: number; 76 | /** Should Baileys ask the phone for full history, will be received async */ 77 | syncFullHistory: boolean; 78 | /** Should baileys fire init queries automatically, default true */ 79 | fireInitQueries: boolean; 80 | /** 81 | * generate a high quality link preview, 82 | * entails uploading the jpegThumbnail to WA 83 | * */ 84 | generateHighQualityLinkPreview: boolean; 85 | /** 86 | * Returns if a jid should be ignored, 87 | * no event for that jid will be triggered. 88 | * Messages from that jid will also not be decrypted 89 | * */ 90 | shouldIgnoreJid: (jid: string) => boolean | undefined; 91 | /** 92 | * Optionally patch the message before sending out 93 | * */ 94 | patchMessageBeforeSending: (msg: proto.IMessage, recipientJids: string[]) => Promise | proto.IMessage; 95 | /** verify app state MACs */ 96 | appStateMacVerification: { 97 | patch: boolean; 98 | snapshot: boolean; 99 | }; 100 | /** options for axios */ 101 | options: AxiosRequestConfig<{}>; 102 | /** 103 | * fetch a message from your store 104 | * implement this so that messages failed to send 105 | * (solves the "this message can take a while" issue) can be retried 106 | * */ 107 | getMessage: (key: proto.IMessageKey) => Promise; 108 | makeSignalRepository: (auth: SignalAuthState) => SignalRepository; 109 | /** Socket passthrough */ 110 | socket?: any; 111 | }; 112 | -------------------------------------------------------------------------------- /lib/Store/make-in-memory-store.d.ts: -------------------------------------------------------------------------------- 1 | import type KeyedDB from '@adiwajshing/keyed-db'; 2 | import type { Comparable } from '@adiwajshing/keyed-db/lib/Types'; 3 | import type { Logger } from 'pino'; 4 | import { proto } from '../../WAProto'; 5 | import type makeMDSocket from '../Socket'; 6 | import type { BaileysEventEmitter, Chat, ConnectionState, Contact, GroupMetadata, PresenceData, WAMessage, WAMessageCursor, WAMessageKey } from '../Types'; 7 | import { Label } from '../Types/Label'; 8 | import { LabelAssociation } from '../Types/LabelAssociation'; 9 | import { ObjectRepository } from './object-repository'; 10 | type WASocket = ReturnType; 11 | export declare const waChatKey: (pin: boolean) => { 12 | key: (c: Chat) => string; 13 | compare: (k1: string, k2: string) => number; 14 | }; 15 | export declare const waMessageID: (m: WAMessage) => string; 16 | export declare const waLabelAssociationKey: Comparable; 17 | export type BaileysInMemoryStoreConfig = { 18 | chatKey?: Comparable; 19 | labelAssociationKey?: Comparable; 20 | logger?: Logger; 21 | socket?: WASocket; 22 | }; 23 | declare const _default: (config: BaileysInMemoryStoreConfig) => { 24 | chats: KeyedDB; 25 | contacts: { 26 | [_: string]: Contact; 27 | }; 28 | messages: { 29 | [_: string]: { 30 | array: proto.IWebMessageInfo[]; 31 | get: (id: string) => proto.IWebMessageInfo | undefined; 32 | upsert: (item: proto.IWebMessageInfo, mode: "append" | "prepend") => void; 33 | update: (item: proto.IWebMessageInfo) => boolean; 34 | remove: (item: proto.IWebMessageInfo) => boolean; 35 | updateAssign: (id: string, update: Partial) => boolean; 36 | clear: () => void; 37 | filter: (contain: (item: proto.IWebMessageInfo) => boolean) => void; 38 | toJSON: () => proto.IWebMessageInfo[]; 39 | fromJSON: (newItems: proto.IWebMessageInfo[]) => void; 40 | }; 41 | }; 42 | groupMetadata: { 43 | [_: string]: GroupMetadata; 44 | }; 45 | state: ConnectionState; 46 | presences: { 47 | [id: string]: { 48 | [participant: string]: PresenceData; 49 | }; 50 | }; 51 | labels: ObjectRepository(work: (...args: A) => Promise): (...args: A) => Promise; 90 | flush(force?: boolean | undefined): boolean; 91 | isBuffering(): boolean; 92 | }; 93 | authState: { 94 | creds: import("../Types").AuthenticationCreds; 95 | keys: import("../Types").SignalKeyStoreWithTransaction; 96 | }; 97 | signalRepository: import("../Types").SignalRepository; 98 | user: import("../Types").Contact | undefined; 99 | generateMessageTag: () => string; 100 | query: (node: BinaryNode, timeoutMs?: number | undefined) => Promise; 101 | waitForMessage: (msgId: string, timeoutMs?: number | undefined) => Promise; 102 | waitForSocketOpen: () => Promise; 103 | sendRawMessage: (data: Uint8Array | Buffer) => Promise; 104 | sendNode: (frame: BinaryNode) => Promise; 105 | logout: (msg?: string | undefined) => Promise; 106 | end: (error: Error | undefined) => void; 107 | onUnexpectedError: (err: Error | import("@hapi/boom").Boom, msg: string) => void; 108 | uploadPreKeys: (count?: number) => Promise; 109 | uploadPreKeysToServerIfRequired: () => Promise; 110 | requestPairingCode: (phoneNumber: string) => Promise; 111 | waitForConnectionUpdate: (check: (u: Partial) => boolean | undefined, timeoutMs?: number | undefined) => Promise; 112 | sendWAMBuffer: (wamBuffer: Buffer) => Promise; 113 | }; 114 | export declare const extractGroupMetadata: (result: BinaryNode) => GroupMetadata; 115 | --------------------------------------------------------------------------------