whalibmob 5.26.1 → 5.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +204 -0
- package/index.d.ts +156 -2
- package/index.js +7 -0
- package/lib/Client.js +531 -11
- package/lib/CompanionPairing.js +1 -1
- package/lib/HistorySyncHandler.js +2 -2
- package/lib/MediaService.js +2 -2
- package/lib/PairingCode.js +4 -6
- package/lib/Registration.js +1 -1
- package/lib/Store.js +1 -1
- package/lib/appstate/AppStateSync.js +3 -3
- package/lib/appstate/LTHash.js +2 -5
- package/lib/curve.js +148 -0
- package/lib/hkdf.js +65 -0
- package/lib/messages/MediaRetry.js +2 -3
- package/lib/messages/MessageSender.js +1 -1
- package/lib/messages/ReportingToken.js +2 -2
- package/lib/noise.js +3 -3
- package/lib/proto/MessageProto.js +83 -1
- package/lib/signal/SenderKey.js +3 -3
- package/lib/signal/libsignal/curve.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -262,6 +262,10 @@ npm install -g whalibmob
|
|
|
262
262
|
- [Read Privacy Settings](#read-privacy-settings)
|
|
263
263
|
- [Update Privacy Settings](#update-privacy-settings)
|
|
264
264
|
- [Update Default Disappearing Mode](#update-default-disappearing-mode)
|
|
265
|
+
- [Account State](#account-state)
|
|
266
|
+
- [AB Props](#ab-props)
|
|
267
|
+
- [Contact Sync](#contact-sync)
|
|
268
|
+
- [Terms-of-Service Notices](#terms-of-service-notices)
|
|
265
269
|
- [Communities](#communities)
|
|
266
270
|
- [Create a Community](#create-a-community)
|
|
267
271
|
- [Deactivate / Delete a Community](#deactivate--delete-a-community)
|
|
@@ -4605,6 +4609,206 @@ await client.changeNewChatsEphemeralTimer(86400) // 1 day
|
|
|
4605
4609
|
await client.changeNewChatsEphemeralTimer(0) // off
|
|
4606
4610
|
```
|
|
4607
4611
|
|
|
4612
|
+
## Account State
|
|
4613
|
+
|
|
4614
|
+
Three things the app speaks on every account and whalibmob did not: the
|
|
4615
|
+
server's own feature flags, the address book, and the legal notices an account
|
|
4616
|
+
is asked to accept. Each is one IQ family; together they are part of what makes
|
|
4617
|
+
a session look like an app rather than a script.
|
|
4618
|
+
|
|
4619
|
+
### AB Props
|
|
4620
|
+
|
|
4621
|
+
Every WhatsApp client asks the server which experiments and configuration
|
|
4622
|
+
values apply to *this* account, then gates behaviour on the answer — how many
|
|
4623
|
+
bytes an identity hash is truncated to, whether the LID migration has started
|
|
4624
|
+
here, what sampling weight each telemetry event carries. A client that never
|
|
4625
|
+
asks runs on guessed defaults wherever the server has an opinion.
|
|
4626
|
+
|
|
4627
|
+
This is synced automatically on every connect. You do not have to call it.
|
|
4628
|
+
|
|
4629
|
+
```js
|
|
4630
|
+
const client = new WhalibmobClient({ sessionDir: './auth' })
|
|
4631
|
+
await client.connect()
|
|
4632
|
+
|
|
4633
|
+
// Already synced by the time 'connected' fires. Read a value:
|
|
4634
|
+
client.abProp(4405) // '16' — always a string on the wire
|
|
4635
|
+
client.abPropInt(4405, 8) // 16 — parsed, or 8 if unset/unparseable
|
|
4636
|
+
client.abPropBool(5010, false) // true — understands "1"/"0" and "true"/"false"
|
|
4637
|
+
```
|
|
4638
|
+
|
|
4639
|
+
Reading a prop before the first sync gives the fallback rather than throwing,
|
|
4640
|
+
so gating on a flag never needs a guard:
|
|
4641
|
+
|
|
4642
|
+
```js
|
|
4643
|
+
// Safe even on a client that has not connected yet.
|
|
4644
|
+
const hashLen = client.abPropInt(4405, 8)
|
|
4645
|
+
```
|
|
4646
|
+
|
|
4647
|
+
To re-sync by hand, or to look at the whole set:
|
|
4648
|
+
|
|
4649
|
+
```js
|
|
4650
|
+
const props = await client.queryAbProps({ force: true })
|
|
4651
|
+
|
|
4652
|
+
console.log(props.hash) // 'A1B2…' — rides on the next sync, asking for a delta
|
|
4653
|
+
console.log(props.refresh) // 86400 — seconds the server suggests waiting
|
|
4654
|
+
console.log(props.delta) // false — this reply was the whole table
|
|
4655
|
+
console.log(props.props) // { '4405': '16', '5010': 'true', … }
|
|
4656
|
+
console.log(props.sampling) // { '1200': 100, … } telemetry weights
|
|
4657
|
+
```
|
|
4658
|
+
|
|
4659
|
+
The hash is what turns the next request into a delta. A delta is **merged**
|
|
4660
|
+
onto what is already held rather than replacing it — otherwise every prop the
|
|
4661
|
+
server saw no reason to repeat would be dropped. The hash lives for the session
|
|
4662
|
+
only: a fresh process asks for the full set again, which is what a fresh
|
|
4663
|
+
install does.
|
|
4664
|
+
|
|
4665
|
+
Turn the automatic sync off if you do not want the extra IQ on a short session:
|
|
4666
|
+
|
|
4667
|
+
```js
|
|
4668
|
+
new WhalibmobClient({ sessionDir: './auth', syncAbPropsOnConnect: false })
|
|
4669
|
+
```
|
|
4670
|
+
|
|
4671
|
+
Being straight about the scope: nothing inside the library consumes these
|
|
4672
|
+
values yet. What you get today is the ability to see what the server thinks
|
|
4673
|
+
about an account — useful when one number behaves differently from another and
|
|
4674
|
+
you would otherwise be guessing — plus one more request a real client makes.
|
|
4675
|
+
|
|
4676
|
+
### Contact Sync
|
|
4677
|
+
|
|
4678
|
+
The address-book upload a phone does on first launch, and the delta syncs after
|
|
4679
|
+
it. It answers the question worth asking before a first message: **is this
|
|
4680
|
+
number on WhatsApp at all?**
|
|
4681
|
+
|
|
4682
|
+
```js
|
|
4683
|
+
const out = await client.syncContacts([
|
|
4684
|
+
'40712345678',
|
|
4685
|
+
'+55 11 91234-5678',
|
|
4686
|
+
'40799999999'
|
|
4687
|
+
])
|
|
4688
|
+
|
|
4689
|
+
out.registered // ['40712345678', '+55 11 91234-5678'] — on WhatsApp
|
|
4690
|
+
out.unregistered // ['40799999999'] — not on WhatsApp
|
|
4691
|
+
out.jids // { '40712345678': '40712345678@s.whatsapp.net', … }
|
|
4692
|
+
```
|
|
4693
|
+
|
|
4694
|
+
Numbers come back in the spelling you passed in, however they were written —
|
|
4695
|
+
spaces, dashes and a leading `+` are all normalised before sending and restored
|
|
4696
|
+
in the answer.
|
|
4697
|
+
|
|
4698
|
+
**A number the server did not answer about appears in neither list.** That is
|
|
4699
|
+
deliberate. Reporting a timeout as "not on WhatsApp" is the one wrong answer
|
|
4700
|
+
available here, because a caller acts on it — skipping the number, or deleting
|
|
4701
|
+
it. Silence is not a verdict:
|
|
4702
|
+
|
|
4703
|
+
```js
|
|
4704
|
+
const asked = phones.length
|
|
4705
|
+
const known = out.registered.length + out.unregistered.length
|
|
4706
|
+
if (known < asked) {
|
|
4707
|
+
console.log(`${asked - known} numbers went unanswered — try them again later`)
|
|
4708
|
+
}
|
|
4709
|
+
```
|
|
4710
|
+
|
|
4711
|
+
Large books are chunked automatically, and one unanswered chunk does not cost
|
|
4712
|
+
the others their answers:
|
|
4713
|
+
|
|
4714
|
+
```js
|
|
4715
|
+
await client.syncContacts(bigList, { chunkSize: 200 }) // default is 500
|
|
4716
|
+
```
|
|
4717
|
+
|
|
4718
|
+
The mode says what the sync claims about your address book. `full` is the
|
|
4719
|
+
whole book — what the app sends on first launch — and carries the
|
|
4720
|
+
`registration` context by default. `delta` is what changed since. `query` is a
|
|
4721
|
+
plain lookup that claims nothing:
|
|
4722
|
+
|
|
4723
|
+
```js
|
|
4724
|
+
await client.syncContacts(phones) // mode 'full', context 'registration'
|
|
4725
|
+
await client.syncContacts(phones, { mode: 'delta' }) // mode 'delta', context 'interactive'
|
|
4726
|
+
await client.syncContacts(phones, { mode: 'query' }) // a lookup, nothing claimed
|
|
4727
|
+
```
|
|
4728
|
+
|
|
4729
|
+
This is **not** called automatically on connect. Uploading an address book is
|
|
4730
|
+
your decision, not a side effect of connecting.
|
|
4731
|
+
|
|
4732
|
+
Where it earns its place is in front of a batch of first messages, together
|
|
4733
|
+
with the token path described under
|
|
4734
|
+
[tcToken](#tctoken--error-463-defense):
|
|
4735
|
+
|
|
4736
|
+
```js
|
|
4737
|
+
// 1. Which of these actually exist?
|
|
4738
|
+
const { registered } = await client.syncContacts(numbers)
|
|
4739
|
+
|
|
4740
|
+
// 2. Warm a trusted-contact token for each, so the first message carries one.
|
|
4741
|
+
for (const n of registered) {
|
|
4742
|
+
const jid = `${n.replace(/\D/g, '')}@s.whatsapp.net`
|
|
4743
|
+
await client.ensureTcTokenBeforeSend(jid, jid)
|
|
4744
|
+
await new Promise(r => setTimeout(r, 300))
|
|
4745
|
+
}
|
|
4746
|
+
|
|
4747
|
+
// 3. Send. No wasted sends to dead numbers, and no anonymous reach-outs.
|
|
4748
|
+
for (const n of registered) {
|
|
4749
|
+
await client.sendText(`${n.replace(/\D/g, '')}@s.whatsapp.net`, 'Hello')
|
|
4750
|
+
await new Promise(r => setTimeout(r, 1000))
|
|
4751
|
+
}
|
|
4752
|
+
```
|
|
4753
|
+
|
|
4754
|
+
### Terms-of-Service Notices
|
|
4755
|
+
|
|
4756
|
+
WhatsApp gates some surfaces on the account having accepted a given legal
|
|
4757
|
+
notice — a Terms update, a privacy-policy change, a regional disclosure. The
|
|
4758
|
+
app pulls the acceptance state, shows what is outstanding, and posts back what
|
|
4759
|
+
the user accepted.
|
|
4760
|
+
|
|
4761
|
+
```js
|
|
4762
|
+
const out = await client.queryTosNotices(['20230324', '20240101'])
|
|
4763
|
+
|
|
4764
|
+
out.refresh // 86400 — seconds the server suggests waiting before asking again
|
|
4765
|
+
out.notices // [ { id: '20230324', accepted: true },
|
|
4766
|
+
// { id: '20240101', accepted: false } ]
|
|
4767
|
+
|
|
4768
|
+
// Anything still outstanding:
|
|
4769
|
+
const pending = out.notices.filter(n => !n.accepted).map(n => n.id)
|
|
4770
|
+
if (pending.length) await client.acceptTosNotices(pending)
|
|
4771
|
+
```
|
|
4772
|
+
|
|
4773
|
+
Reading one back without asking again:
|
|
4774
|
+
|
|
4775
|
+
```js
|
|
4776
|
+
client.isTosAccepted('20230324') // true
|
|
4777
|
+
client.isTosAccepted('20240101') // false
|
|
4778
|
+
client.isTosAccepted('unknown-id') // null — this session has not asked
|
|
4779
|
+
```
|
|
4780
|
+
|
|
4781
|
+
`null` matters: it means *unknown*, not *not accepted*. Code deciding whether
|
|
4782
|
+
to accept something needs to be able to tell those apart.
|
|
4783
|
+
|
|
4784
|
+
Clearing an acceptance, so the server asks for it again:
|
|
4785
|
+
|
|
4786
|
+
```js
|
|
4787
|
+
await client.clearTosNotice('20230324')
|
|
4788
|
+
```
|
|
4789
|
+
|
|
4790
|
+
An acceptance made on another device arrives on its own, inside the same
|
|
4791
|
+
`account_sync` notification that carries device and privacy changes:
|
|
4792
|
+
|
|
4793
|
+
```js
|
|
4794
|
+
client.on('tos_notices', ({ notices }) => {
|
|
4795
|
+
for (const n of notices) {
|
|
4796
|
+
console.log(n.id, n.accepted ? 'accepted' : 'outstanding')
|
|
4797
|
+
}
|
|
4798
|
+
})
|
|
4799
|
+
```
|
|
4800
|
+
|
|
4801
|
+
A note on the wire, because it reads backwards from how it looks: the `state`
|
|
4802
|
+
attribute is present and `"false"` for a notice that has **not** been accepted,
|
|
4803
|
+
and **absent** for one that has. whalibmob reads it that way. If you parse these
|
|
4804
|
+
stanzas yourself, treating a missing attribute as "unknown" would report every
|
|
4805
|
+
accepted notice as outstanding.
|
|
4806
|
+
|
|
4807
|
+
Scope, honestly: no specific feature has been shown to be blocked by an
|
|
4808
|
+
unaccepted notice on a headless account. What this gives you is something to
|
|
4809
|
+
check rather than guess at — if a freshly registered number will not do
|
|
4810
|
+
something, you can now ask whether it has a notice pending.
|
|
4811
|
+
|
|
4608
4812
|
## Groups
|
|
4609
4813
|
|
|
4610
4814
|
### Create a Group
|
package/index.d.ts
CHANGED
|
@@ -123,6 +123,23 @@ export interface WhalibmobClientOptions {
|
|
|
123
123
|
autoFixNumber?: boolean;
|
|
124
124
|
/** Send read receipts for incoming messages. Default `true`. */
|
|
125
125
|
autoRead?: boolean;
|
|
126
|
+
/**
|
|
127
|
+
* Refuse every incoming call. Default `true`.
|
|
128
|
+
*
|
|
129
|
+
* Turning it off does not answer calls — nothing here can — it leaves the
|
|
130
|
+
* refusal to you, which is the only way to let some calls ring and reject the
|
|
131
|
+
* rest with `rejectCall()`.
|
|
132
|
+
*/
|
|
133
|
+
autoRejectCalls?: boolean;
|
|
134
|
+
/**
|
|
135
|
+
* Sync the account's AB props on every connect. Default `true`, because the
|
|
136
|
+
* app does it on every login and a client that never asks runs on guessed
|
|
137
|
+
* defaults wherever the server has an opinion.
|
|
138
|
+
*
|
|
139
|
+
* Turning it off saves one IQ per connect and costs nothing else: every
|
|
140
|
+
* reader of these has a fallback.
|
|
141
|
+
*/
|
|
142
|
+
syncAbPropsOnConnect?: boolean;
|
|
126
143
|
/** Refresh the announced build from the platform's store before every handshake. Default `true`. */
|
|
127
144
|
refreshVersion?: boolean;
|
|
128
145
|
/** `true` enables debug logging; an object is handed to `pino` as-is. */
|
|
@@ -227,8 +244,24 @@ export interface PollSendResult extends SendResult {
|
|
|
227
244
|
messageSecret: Buffer;
|
|
228
245
|
}
|
|
229
246
|
|
|
247
|
+
/** What a message was a reply to, and who it mentioned. */
|
|
248
|
+
export interface DecodedContextInfo {
|
|
249
|
+
/** Id of the quoted message. */
|
|
250
|
+
stanzaId?: string;
|
|
251
|
+
/** Who wrote the quoted message. */
|
|
252
|
+
participant?: Jid;
|
|
253
|
+
remoteJid?: Jid;
|
|
254
|
+
mentionedJid?: Jid[];
|
|
255
|
+
/** The quoted message, decoded the same way as any other. */
|
|
256
|
+
quotedMessage?: DecodedMessage;
|
|
257
|
+
/** The quoted message's raw protobuf bytes, for re-encoding it verbatim. */
|
|
258
|
+
quotedMessageRaw?: Buffer;
|
|
259
|
+
}
|
|
260
|
+
|
|
230
261
|
export interface DecodedBase {
|
|
231
262
|
type: string;
|
|
263
|
+
/** Present when the message quoted another or carried mentions. */
|
|
264
|
+
contextInfo?: DecodedContextInfo;
|
|
232
265
|
/**
|
|
233
266
|
* The message arrived inside a view-once envelope. The content is decoded
|
|
234
267
|
* normally — media included — this only records how it was sent.
|
|
@@ -454,6 +487,36 @@ export type PrivacyValue =
|
|
|
454
487
|
| 'on_standard'
|
|
455
488
|
| 'off';
|
|
456
489
|
|
|
490
|
+
export interface AbProps {
|
|
491
|
+
/** Hash of the returned set. Sent back on the next sync to ask for a delta. */
|
|
492
|
+
hash: string | null;
|
|
493
|
+
abKey: string | null;
|
|
494
|
+
/** Seconds the server suggests waiting before syncing again. */
|
|
495
|
+
refresh: number | null;
|
|
496
|
+
refreshId: string | null;
|
|
497
|
+
/** Whether this reply named only what changed, rather than the whole table. */
|
|
498
|
+
delta: boolean;
|
|
499
|
+
/** Experiment values, keyed by their numeric config code. */
|
|
500
|
+
props: { [configCode: string]: string };
|
|
501
|
+
/** Telemetry sampling weights, keyed by their numeric event code. */
|
|
502
|
+
sampling: { [eventCode: string]: number };
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
export interface ContactSyncResult {
|
|
506
|
+
/** Numbers on WhatsApp, in the spelling they were passed in. */
|
|
507
|
+
registered: string[];
|
|
508
|
+
/** Numbers the server said are not on WhatsApp. */
|
|
509
|
+
unregistered: string[];
|
|
510
|
+
/** Each registered number mapped to the JID the server gave it. */
|
|
511
|
+
jids: { [phone: string]: string };
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
export interface TosNoticesResult {
|
|
515
|
+
/** Seconds the server suggests waiting before asking again. */
|
|
516
|
+
refresh: number | null;
|
|
517
|
+
notices: Array<{ id: string; accepted: boolean }>;
|
|
518
|
+
}
|
|
519
|
+
|
|
457
520
|
export interface PrivacySettings {
|
|
458
521
|
lastSeen: string | null;
|
|
459
522
|
profile: string | null;
|
|
@@ -632,7 +695,7 @@ export interface WhalibmobEvents {
|
|
|
632
695
|
message: (msg: IncomingMessage) => void;
|
|
633
696
|
receipt: (r: { type: string; id: string; from: Jid }) => void;
|
|
634
697
|
presence: (p: { from: Jid; available: boolean }) => void;
|
|
635
|
-
call: (c: { from: Jid }) => void;
|
|
698
|
+
call: (c: { from: Jid; id: string | null; status: 'offer' | 'ringing' | 'terminate' | 'unknown'; node: any }) => void;
|
|
636
699
|
notification: (node: any) => void;
|
|
637
700
|
decrypt_error: (e: { id: string; from: Jid; participant?: Jid; err: Error }) => void;
|
|
638
701
|
session_refresh: (e: { node: any }) => void;
|
|
@@ -796,6 +859,46 @@ export declare class WhalibmobClient extends EventEmitter {
|
|
|
796
859
|
|
|
797
860
|
// ─── Privacy ─────────────────────────────────────────────────────────────
|
|
798
861
|
queryPrivacySettings(opts?: { force?: boolean }): Promise<PrivacySettings>;
|
|
862
|
+
|
|
863
|
+
// ─── AB props ────────────────────────────────────────────────────────────
|
|
864
|
+
//
|
|
865
|
+
// The per-account feature flags the server hands out. Synced on connect
|
|
866
|
+
// unless `syncAbPropsOnConnect: false` was passed to the constructor, and
|
|
867
|
+
// held for the session — a fresh process asks for the full set again, which
|
|
868
|
+
// is what a fresh install does.
|
|
869
|
+
//
|
|
870
|
+
// Values are strings because that is what the wire carries; abPropInt and
|
|
871
|
+
// abPropBool are the two readings worth having, and both fall back rather
|
|
872
|
+
// than coerce.
|
|
873
|
+
queryAbProps(opts?: { force?: boolean; refreshId?: string }): Promise<AbProps>;
|
|
874
|
+
abProp(code: number | string, fallback?: string | null): string | null;
|
|
875
|
+
abPropInt(code: number | string, fallback?: number | null): number | null;
|
|
876
|
+
abPropBool(code: number | string, fallback?: boolean | null): boolean | null;
|
|
877
|
+
|
|
878
|
+
// ─── Contact sync ────────────────────────────────────────────────────────
|
|
879
|
+
//
|
|
880
|
+
// The address-book upload a phone does on first launch, and the delta syncs
|
|
881
|
+
// after it. Numbers the server did not answer about appear in neither list:
|
|
882
|
+
// silence is not a verdict, and reporting a timeout as "not on WhatsApp"
|
|
883
|
+
// is the one wrong answer available here.
|
|
884
|
+
syncContacts(
|
|
885
|
+
phones: string[],
|
|
886
|
+
opts?: {
|
|
887
|
+
mode?: 'full' | 'delta' | 'query';
|
|
888
|
+
context?: string;
|
|
889
|
+
chunkSize?: number;
|
|
890
|
+
}
|
|
891
|
+
): Promise<ContactSyncResult>;
|
|
892
|
+
|
|
893
|
+
// ─── Terms-of-Service notices ────────────────────────────────────────────
|
|
894
|
+
//
|
|
895
|
+
// `isTosAccepted` answers `null` for a notice this session has not asked
|
|
896
|
+
// about, which is not the same as "not accepted".
|
|
897
|
+
queryTosNotices(noticeIds: string[]): Promise<TosNoticesResult>;
|
|
898
|
+
acceptTosNotices(noticeIds: string[]): Promise<{ ok: true; raw: any }>;
|
|
899
|
+
clearTosNotice(noticeId: string): Promise<{ ok: true; raw: any }>;
|
|
900
|
+
isTosAccepted(noticeId: string): boolean | null;
|
|
901
|
+
|
|
799
902
|
changePrivacySetting(type: PrivacyType, value: PrivacyValue, excluded?: Jid[]): Promise<PrivacySettings>;
|
|
800
903
|
queryStatusPrivacy(): Promise<StatusPrivacyEntry[]>;
|
|
801
904
|
blockContact(jid: Jid): Promise<Jid[]>;
|
|
@@ -831,6 +934,12 @@ export declare class WhalibmobClient extends EventEmitter {
|
|
|
831
934
|
*/
|
|
832
935
|
requestAppStateKeys(keyIds: string[]): Promise<string | null>;
|
|
833
936
|
|
|
937
|
+
/**
|
|
938
|
+
* Refuse one incoming call. Only reachable when the client was built with
|
|
939
|
+
* `autoRejectCalls: false`; the id and caller come off the `call` event.
|
|
940
|
+
*/
|
|
941
|
+
rejectCall(callId: string, from: Jid): boolean;
|
|
942
|
+
|
|
834
943
|
// ─── Account restriction ─────────────────────────────────────────────────
|
|
835
944
|
fetchReachoutTimelock(): Promise<ReachoutTimelockState>;
|
|
836
945
|
/** The last known state, recomputed; does not ask the server again. */
|
|
@@ -903,7 +1012,20 @@ export declare class WhalibmobClient extends EventEmitter {
|
|
|
903
1012
|
getLIDForPN(pn: Jid): Jid | null;
|
|
904
1013
|
|
|
905
1014
|
// ─── Lower level ─────────────────────────────────────────────────────────
|
|
906
|
-
|
|
1015
|
+
/**
|
|
1016
|
+
* Put a trusted-contact token on file *before* the next message is built, so
|
|
1017
|
+
* that message carries a `<tctoken>` like every later one.
|
|
1018
|
+
*
|
|
1019
|
+
* The token comes from the server, not from the contact: nothing here waits
|
|
1020
|
+
* on them replying, on having you in their address book, or on a conversation
|
|
1021
|
+
* existing. Called automatically by every send, so you rarely need it — reach
|
|
1022
|
+
* for it to warm a token ahead of time, before a burst of first messages.
|
|
1023
|
+
*
|
|
1024
|
+
* Returns whether a usable token is on file now. `false` is not a failure to
|
|
1025
|
+
* act on: the send goes ahead without one and the issuance continues in the
|
|
1026
|
+
* background for the next message.
|
|
1027
|
+
*/
|
|
1028
|
+
ensureTcTokenBeforeSend(tcJid: Jid, routingToJid: Jid): Promise<boolean>;
|
|
907
1029
|
sendPeerDataOperationMessage(pdo: any): Promise<any>;
|
|
908
1030
|
requestPlaceholderResend(messageKey: any, msgData?: any): Promise<any>;
|
|
909
1031
|
fetchMessageHistory(count: number, oldestMsgKey: any, oldestMsgTimestampMs: number): Promise<any>;
|
|
@@ -1314,6 +1436,38 @@ export declare const PushClient: LibModule;
|
|
|
1314
1436
|
export declare const Fcm: LibModule;
|
|
1315
1437
|
export declare const FcmMcs: LibModule;
|
|
1316
1438
|
|
|
1439
|
+
/**
|
|
1440
|
+
* X25519 through Node's own OpenSSL — a drop-in for `curve25519-js`, roughly
|
|
1441
|
+
* 19x faster on `sharedKey` and byte-identical to it.
|
|
1442
|
+
*
|
|
1443
|
+
* `sign` and `verify` are XEdDSA and stay on the JavaScript implementation:
|
|
1444
|
+
* Node's Ed25519 is a different scheme and would produce different bytes.
|
|
1445
|
+
*/
|
|
1446
|
+
export declare const Curve: LibModule & {
|
|
1447
|
+
generateKeyPair(seed: Buffer | Uint8Array): { private: Buffer; public: Buffer };
|
|
1448
|
+
sharedKey(priv: Buffer | Uint8Array, pub: Buffer | Uint8Array): Buffer;
|
|
1449
|
+
sign(priv: Buffer | Uint8Array, message: Buffer | Uint8Array): Buffer;
|
|
1450
|
+
verify(pub: Buffer | Uint8Array, message: Buffer | Uint8Array, signature: Buffer | Uint8Array): boolean;
|
|
1451
|
+
/** Whether Node's X25519 is in use; `false` means the JavaScript fallback is. */
|
|
1452
|
+
NATIVE: boolean;
|
|
1453
|
+
};
|
|
1454
|
+
|
|
1455
|
+
/**
|
|
1456
|
+
* HKDF-SHA256 through Node's own OpenSSL — roughly 2.2x faster than the
|
|
1457
|
+
* JavaScript implementation and byte-identical to it. Returns a `Buffer`,
|
|
1458
|
+
* not the `ArrayBuffer` Node's own `hkdfSync` hands back.
|
|
1459
|
+
*/
|
|
1460
|
+
export declare const Hkdf: LibModule & {
|
|
1461
|
+
hkdfSha256(
|
|
1462
|
+
ikm: Buffer | Uint8Array,
|
|
1463
|
+
salt: Buffer | Uint8Array | string,
|
|
1464
|
+
info: Buffer | Uint8Array | string,
|
|
1465
|
+
length: number
|
|
1466
|
+
): Buffer;
|
|
1467
|
+
/** Whether Node's HKDF is in use; `false` means the JavaScript fallback is. */
|
|
1468
|
+
NATIVE: boolean;
|
|
1469
|
+
};
|
|
1470
|
+
|
|
1317
1471
|
/** Linking to an account that already exists. */
|
|
1318
1472
|
export declare const PairingCode: LibModule;
|
|
1319
1473
|
export declare const CompanionPairing: LibModule;
|
package/index.js
CHANGED
|
@@ -129,6 +129,8 @@ const WebVersion = require('./lib/WebVersion');
|
|
|
129
129
|
const WebProto = require('./lib/webproto');
|
|
130
130
|
|
|
131
131
|
const BinaryNode = require('./lib/BinaryNode');
|
|
132
|
+
const Curve = require('./lib/curve');
|
|
133
|
+
const Hkdf = require('./lib/hkdf');
|
|
132
134
|
const Noise = require('./lib/noise');
|
|
133
135
|
const WebSocketStream = require('./lib/WebSocketStream');
|
|
134
136
|
const Socks = require('./lib/socks');
|
|
@@ -348,6 +350,11 @@ module.exports = {
|
|
|
348
350
|
FcmMcs,
|
|
349
351
|
|
|
350
352
|
// Linking to an account that already exists
|
|
353
|
+
// X25519, through Node's own OpenSSL. Drop-in for curve25519-js.
|
|
354
|
+
Curve,
|
|
355
|
+
// HKDF-SHA256, through Node's own OpenSSL.
|
|
356
|
+
Hkdf,
|
|
357
|
+
|
|
351
358
|
PairingCode,
|
|
352
359
|
CompanionPairing,
|
|
353
360
|
QrPairing,
|