@kangwifi-pro/waliwa 1.1.0 → 1.1.1
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/dist/core/noise.d.ts +9 -4
- package/dist/core/noise.d.ts.map +1 -1
- package/dist/core/noise.js +27 -21
- package/dist/core/noise.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/socket/ws-socket.d.ts +12 -2
- package/dist/socket/ws-socket.d.ts.map +1 -1
- package/dist/socket/ws-socket.js +46 -36
- package/dist/socket/ws-socket.js.map +1 -1
- package/docs/COMMUNITY.md +613 -0
- package/package.json +1 -1
- package/src/core/noise.ts +26 -22
- package/src/index.ts +1 -1
- package/src/socket/ws-socket.ts +48 -37
package/dist/core/noise.d.ts
CHANGED
|
@@ -48,14 +48,17 @@ export declare class NoiseHandshake {
|
|
|
48
48
|
writeEphemeral(): Uint8Array;
|
|
49
49
|
/**
|
|
50
50
|
* Step 2: Receive ephemeral + static + EE + ES from responder
|
|
51
|
+
* Server sends: [32-byte ephemeral] [48-byte encrypted static] [N-byte encrypted payload]
|
|
51
52
|
*/
|
|
52
53
|
readResponderHandshake(payload: Uint8Array): {
|
|
53
54
|
plaintext: Uint8Array;
|
|
54
55
|
};
|
|
55
56
|
/**
|
|
56
|
-
* Step 3: Send our static +
|
|
57
|
+
* Step 3: Send our static + SE + payload (initiator -> responder)
|
|
58
|
+
* Returns: [48-byte encrypted static] [N-byte encrypted payload]
|
|
59
|
+
* MUST be called AFTER readResponderHandshake (needs remote ephemeral)
|
|
57
60
|
*/
|
|
58
|
-
|
|
61
|
+
writeClientResponse(payload: Uint8Array): Uint8Array;
|
|
59
62
|
/**
|
|
60
63
|
* Finalize handshake - split prk into send/recv keys
|
|
61
64
|
*/
|
|
@@ -81,9 +84,11 @@ export declare class NoiseHandshake {
|
|
|
81
84
|
*/
|
|
82
85
|
static encodeClientHello(ephemeralPub: Uint8Array, encryptedStatic: Uint8Array, encryptedPayload: Uint8Array): Uint8Array;
|
|
83
86
|
/**
|
|
84
|
-
* Build client hello
|
|
87
|
+
* Build initial client hello - ONLY the ephemeral key for message 1
|
|
88
|
+
* The encrypted static + payload (message 3) is sent separately
|
|
89
|
+
* after receiving the server's response (message 2)
|
|
85
90
|
*/
|
|
86
|
-
buildClientHello(
|
|
91
|
+
buildClientHello(): Uint8Array;
|
|
87
92
|
}
|
|
88
93
|
/**
|
|
89
94
|
* Traffic cipher untuk encrypt/decrypt frames setelah handshake done
|
package/dist/core/noise.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"noise.d.ts","sourceRoot":"","sources":["../../src/core/noise.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAUL,OAAO,EAER,MAAM,aAAa,CAAC;AAyCrB,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAM;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAM;gBAEnB,SAAS,CAAC,EAAE,OAAO,EAAE,SAAS,GAAE,OAAc;IAe1D,OAAO,CAAC,mBAAmB;IAS3B;;OAEG;IACH,OAAO,CAAC,MAAM;IAad;;OAEG;IACH,OAAO,CAAC,OAAO;IAIf;;OAEG;IACH,OAAO,CAAC,eAAe;IAcvB;;OAEG;IACH,OAAO,CAAC,eAAe;IAevB;;OAEG;IACH,OAAO,CAAC,aAAa;IAWrB;;;OAGG;IACI,cAAc,IAAI,UAAU;IAQnC
|
|
1
|
+
{"version":3,"file":"noise.d.ts","sourceRoot":"","sources":["../../src/core/noise.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAUL,OAAO,EAER,MAAM,aAAa,CAAC;AAyCrB,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAiB;IAC9B,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAM;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAM;gBAEnB,SAAS,CAAC,EAAE,OAAO,EAAE,SAAS,GAAE,OAAc;IAe1D,OAAO,CAAC,mBAAmB;IAS3B;;OAEG;IACH,OAAO,CAAC,MAAM;IAad;;OAEG;IACH,OAAO,CAAC,OAAO;IAIf;;OAEG;IACH,OAAO,CAAC,eAAe;IAcvB;;OAEG;IACH,OAAO,CAAC,eAAe;IAevB;;OAEG;IACH,OAAO,CAAC,aAAa;IAWrB;;;OAGG;IACI,cAAc,IAAI,UAAU;IAQnC;;;OAGG;IACI,sBAAsB,CAAC,OAAO,EAAE,UAAU,GAAG;QAAE,SAAS,EAAE,UAAU,CAAA;KAAE;IAiC7E;;;;OAIG;IACI,mBAAmB,CAAC,OAAO,EAAE,UAAU,GAAG,UAAU;IAgB3D;;OAEG;IACI,QAAQ,IAAI;QAAE,OAAO,EAAE,UAAU,CAAC;QAAC,OAAO,EAAE,UAAU,CAAA;KAAE;IAe/D;;OAEG;WACW,YAAY,CACxB,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,UAAU,GACpB,UAAU;IAUb;;OAEG;WACW,YAAY,CACxB,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,UAAU,GACrB,UAAU;IAcb;;OAEG;WACW,WAAW,CAAC,OAAO,EAAE,UAAU,GAAG,UAAU;IAkB1D;;;OAGG;WACW,iBAAiB,CAC7B,YAAY,EAAE,UAAU,EACxB,eAAe,EAAE,UAAU,EAC3B,gBAAgB,EAAE,UAAU,GAC3B,UAAU;IAIb;;;;OAIG;IACI,gBAAgB,IAAI,UAAU;CAItC;AAID;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,WAAW,CAAa;gBAEpB,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU;IAKpD,OAAO,CAAC,SAAS,EAAE,UAAU,GAAG,UAAU;IAM1C,OAAO,CAAC,UAAU,EAAE,UAAU,GAAG,UAAU;IAM3C,KAAK;CAIN;AAID;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,UAAU,CA4BhF"}
|
package/dist/core/noise.js
CHANGED
|
@@ -126,6 +126,7 @@ class NoiseHandshake {
|
|
|
126
126
|
}
|
|
127
127
|
/**
|
|
128
128
|
* Step 2: Receive ephemeral + static + EE + ES from responder
|
|
129
|
+
* Server sends: [32-byte ephemeral] [48-byte encrypted static] [N-byte encrypted payload]
|
|
129
130
|
*/
|
|
130
131
|
readResponderHandshake(payload) {
|
|
131
132
|
// First 32 bytes = ephemeral key
|
|
@@ -138,31 +139,36 @@ class NoiseHandshake {
|
|
|
138
139
|
// Ephemeral-ephemeral DH
|
|
139
140
|
const ee = (0, crypto_js_1.curveSharedSecret)(this.state.e.private, re);
|
|
140
141
|
this.mixKey(ee);
|
|
141
|
-
// Next
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
142
|
+
// Next 48 bytes = encrypted static (32-byte ct + 16-byte GCM tag)
|
|
143
|
+
if (payload.length < 80)
|
|
144
|
+
throw new Error('Handshake too short for static');
|
|
145
|
+
const encryptedStatic = payload.subarray(32, 80);
|
|
146
|
+
const remoteStatic = this.decryptWithHash(encryptedStatic); // 32 bytes
|
|
147
|
+
this.state.rs = remoteStatic;
|
|
145
148
|
this.mixHash(remoteStatic);
|
|
146
149
|
// Ephemeral-static DH
|
|
147
150
|
const es = (0, crypto_js_1.curveSharedSecret)(this.state.e.private, remoteStatic);
|
|
148
151
|
this.mixKey(es);
|
|
149
|
-
// Remaining
|
|
150
|
-
const encryptedPayload =
|
|
151
|
-
|
|
152
|
-
|
|
152
|
+
// Remaining = encrypted payload (may be empty)
|
|
153
|
+
const encryptedPayload = payload.subarray(80);
|
|
154
|
+
let plaintext = new Uint8Array(0);
|
|
155
|
+
if (encryptedPayload.length > 0) {
|
|
156
|
+
plaintext = this.decryptWithHash(encryptedPayload);
|
|
157
|
+
}
|
|
158
|
+
return { plaintext };
|
|
153
159
|
}
|
|
154
160
|
/**
|
|
155
|
-
* Step 3: Send our static +
|
|
161
|
+
* Step 3: Send our static + SE + payload (initiator -> responder)
|
|
162
|
+
* Returns: [48-byte encrypted static] [N-byte encrypted payload]
|
|
163
|
+
* MUST be called AFTER readResponderHandshake (needs remote ephemeral)
|
|
156
164
|
*/
|
|
157
|
-
|
|
158
|
-
//
|
|
159
|
-
// Now send static + ES + payload, all encrypted with current handshake key
|
|
160
|
-
// Encrypt our static key
|
|
165
|
+
writeClientResponse(payload) {
|
|
166
|
+
// Encrypt our static key (32 bytes → 48 bytes with GCM tag)
|
|
161
167
|
const encryptedStatic = this.encryptWithHash(this.state.s.public);
|
|
162
168
|
this.mixHash(this.state.s.public);
|
|
163
|
-
// Static-ephemeral DH (
|
|
169
|
+
// Static-ephemeral DH (our static private, their ephemeral public)
|
|
164
170
|
if (!this.state.re)
|
|
165
|
-
throw new Error('No remote ephemeral');
|
|
171
|
+
throw new Error('No remote ephemeral - call readResponderHandshake first');
|
|
166
172
|
const se = (0, crypto_js_1.curveSharedSecret)(this.state.s.private, this.state.re);
|
|
167
173
|
this.mixKey(se);
|
|
168
174
|
// Encrypt payload
|
|
@@ -234,13 +240,13 @@ class NoiseHandshake {
|
|
|
234
240
|
return (0, crypto_js_1.concatBytes)(ephemeralPub, encryptedStatic, encryptedPayload);
|
|
235
241
|
}
|
|
236
242
|
/**
|
|
237
|
-
* Build client hello
|
|
243
|
+
* Build initial client hello - ONLY the ephemeral key for message 1
|
|
244
|
+
* The encrypted static + payload (message 3) is sent separately
|
|
245
|
+
* after receiving the server's response (message 2)
|
|
238
246
|
*/
|
|
239
|
-
buildClientHello(
|
|
240
|
-
//
|
|
241
|
-
|
|
242
|
-
const encrypted = this.writeInitiatorHandshake(clientPayload);
|
|
243
|
-
return (0, crypto_js_1.concatBytes)(ephemeral, encrypted);
|
|
247
|
+
buildClientHello() {
|
|
248
|
+
// Message 1: just the ephemeral public key
|
|
249
|
+
return this.writeEphemeral();
|
|
244
250
|
}
|
|
245
251
|
}
|
|
246
252
|
exports.NoiseHandshake = NoiseHandshake;
|
package/dist/core/noise.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"noise.js","sourceRoot":"","sources":["../../src/core/noise.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;
|
|
1
|
+
{"version":3,"file":"noise.js","sourceRoot":"","sources":["../../src/core/noise.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -53,7 +53,7 @@ export { RecoveryManager, mapCodeToReason, getActionDescription, getReasonDescri
|
|
|
53
53
|
export { ProfileManager, PrivacyManager, NewsletterManagerExtended, StatusExtended, ContactsManager, BulkOperations, MessageExtras, DisappearingManager, LiveLocationManager, AudioTranscriptionManager, StickerManager, TypingIndicatorTracker, LastSeenTracker, MessageStatusTracker, SelfMessageFilter, ChatStateManager, DeviceInfoTracker, GroupEventsTracker, parseGroupInviteInfo, createCommunityManagers, type ProfileInfo, type PrivacyValue, type PrivacyCategory, type PrivacySettings, type NewsletterMetadata, type NewsletterPost, type StatusView, type StatusInfo, type StatusPrivacyValue, type StatusPrivacy, type ContactInfo, type BulkSendItem, type BulkSendResult, type BulkSendOptions, type AlbumItem, type MessageInfo, type DisappearingTimer, type TIMER_TO_SECONDS, type LiveLocation, type TranscriptionResult, type TranscriptionProvider, type StickerMetadata, type StickerPack, type ChatState, type GroupInviteInfo, type CommunityManagers, type CommunityTrackers } from './community/index.js';
|
|
54
54
|
export { TIMER_TO_SECONDS as DISAPPEARING_TIMERS, SECONDS_TO_TIMER as SECONDS_TO_TIMER, detectLanguageFromText } from './community/index.js';
|
|
55
55
|
export * from './types/index.js';
|
|
56
|
-
export declare const VERSION = "1.1.
|
|
56
|
+
export declare const VERSION = "1.1.1";
|
|
57
57
|
export declare const LIBRARY_NAME = "waliwa";
|
|
58
58
|
export declare const DEFAULT_CONFIG: {
|
|
59
59
|
wsURL: string;
|
package/dist/index.js
CHANGED
|
@@ -252,7 +252,7 @@ Object.defineProperty(exports, "detectLanguageFromText", { enumerable: true, get
|
|
|
252
252
|
// ============== All Types ==============
|
|
253
253
|
__exportStar(require("./types/index.js"), exports);
|
|
254
254
|
// ============== Version ==============
|
|
255
|
-
exports.VERSION = '1.1.
|
|
255
|
+
exports.VERSION = '1.1.1';
|
|
256
256
|
exports.LIBRARY_NAME = 'waliwa';
|
|
257
257
|
// ============== Default Config ==============
|
|
258
258
|
exports.DEFAULT_CONFIG = {
|
|
@@ -50,12 +50,20 @@ export declare class WAWebSocket extends EventEmitter {
|
|
|
50
50
|
connect(): Promise<void>;
|
|
51
51
|
/**
|
|
52
52
|
* Start Noise Protocol XX handshake
|
|
53
|
+
*
|
|
54
|
+
* Noise XX pattern requires 3 messages:
|
|
55
|
+
* 1. Client -> Server: ephemeral only (32 bytes)
|
|
56
|
+
* 2. Server -> Client: ephemeral + encrypted static + encrypted payload
|
|
57
|
+
* 3. Client -> Server: encrypted static + encrypted payload
|
|
58
|
+
*
|
|
59
|
+
* The WA protocol wraps message 1 with a WA header ("WA" + version),
|
|
60
|
+
* but messages 2 and 3 are sent as raw Noise data.
|
|
53
61
|
*/
|
|
54
62
|
private startHandshake;
|
|
55
63
|
/**
|
|
56
|
-
*
|
|
64
|
+
* Wait for a single WebSocket message with timeout
|
|
57
65
|
*/
|
|
58
|
-
private
|
|
66
|
+
private waitForMessage;
|
|
59
67
|
/**
|
|
60
68
|
* Build client payload - browser info + pairing static key
|
|
61
69
|
*/
|
|
@@ -63,10 +71,12 @@ export declare class WAWebSocket extends EventEmitter {
|
|
|
63
71
|
private generatePairingKey;
|
|
64
72
|
/**
|
|
65
73
|
* Handle incoming message - decrypt jika handshake done
|
|
74
|
+
* After handshake, messages are raw encrypted Noise data (NO WA header)
|
|
66
75
|
*/
|
|
67
76
|
private handleMessage;
|
|
68
77
|
/**
|
|
69
78
|
* Send encrypted frame ke server
|
|
79
|
+
* After handshake, messages are sent as raw encrypted Noise data (NO WA header)
|
|
70
80
|
*/
|
|
71
81
|
send(plaintext: Uint8Array): void;
|
|
72
82
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws-socket.d.ts","sourceRoot":"","sources":["../../src/socket/ws-socket.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAEL,aAAa,EACd,MAAM,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAGlD,MAAM,MAAM,gBAAgB,GACxB,MAAM,GACN,SAAS,GACT,OAAO,GACP,OAAO,GACP,gBAAgB,GAChB,iBAAiB,CAAC;AAEtB,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,gDAAgD;IAChD,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,yBAAyB;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6BAA6B;IAC7B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,+DAA+D;IAC/D,QAAQ,CAAC,EAAE;QAAE,OAAO,EAAE,UAAU,CAAC;QAAC,MAAM,EAAE,UAAU,CAAA;KAAE,CAAC;IACvD,mCAAmC;IACnC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;CACtB;AAmCD,qBAAa,WAAY,SAAQ,YAAY;IAC3C,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,CAA8C;IAC/D,OAAO,CAAC,QAAQ,CAAY;IAE5B,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,SAAS,CAA+B;IAChD,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,YAAY,CAA+B;IACnD,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,UAAU,CAAgB;IAClC,OAAO,CAAC,UAAU,CAAa;gBAEnB,IAAI,EAAE,kBAAkB;IAYpC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA8D9B
|
|
1
|
+
{"version":3,"file":"ws-socket.d.ts","sourceRoot":"","sources":["../../src/socket/ws-socket.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAEL,aAAa,EACd,MAAM,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAGlD,MAAM,MAAM,gBAAgB,GACxB,MAAM,GACN,SAAS,GACT,OAAO,GACP,OAAO,GACP,gBAAgB,GAChB,iBAAiB,CAAC;AAEtB,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,gDAAgD;IAChD,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,yBAAyB;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6BAA6B;IAC7B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,+DAA+D;IAC/D,QAAQ,CAAC,EAAE;QAAE,OAAO,EAAE,UAAU,CAAC;QAAC,MAAM,EAAE,UAAU,CAAA;KAAE,CAAC;IACvD,mCAAmC;IACnC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;CACtB;AAmCD,qBAAa,WAAY,SAAQ,YAAY;IAC3C,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,CAA8C;IAC/D,OAAO,CAAC,QAAQ,CAAY;IAE5B,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,SAAS,CAA+B;IAChD,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,YAAY,CAA+B;IACnD,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,UAAU,CAAgB;IAClC,OAAO,CAAC,UAAU,CAAa;gBAEnB,IAAI,EAAE,kBAAkB;IAYpC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA8D9B;;;;;;;;;;OAUG;YACW,cAAc;IA8B5B;;OAEG;IACH,OAAO,CAAC,cAAc;IAgBtB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAqB1B,OAAO,CAAC,kBAAkB;IAK1B;;;OAGG;IACH,OAAO,CAAC,aAAa;IAerB;;;OAGG;IACH,IAAI,CAAC,SAAS,EAAE,UAAU,GAAG,IAAI;IASjC;;OAEG;IACH,OAAO,CAAC,cAAc;IAetB,OAAO,CAAC,aAAa;IAOrB;;OAEG;IACH,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,UAAU;IAIlB;;OAEG;IACH,KAAK,CAAC,IAAI,GAAE,MAAa,EAAE,MAAM,GAAE,MAAiB,GAAG,IAAI;IAa3D;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACH,gBAAgB,IAAI,aAAa,GAAG,IAAI;CAGzC;AAED,eAAe,WAAW,CAAC"}
|
package/dist/socket/ws-socket.js
CHANGED
|
@@ -14,6 +14,7 @@ exports.WAWebSocket = void 0;
|
|
|
14
14
|
const ws_1 = __importDefault(require("ws"));
|
|
15
15
|
const events_1 = require("events");
|
|
16
16
|
const noise_js_1 = require("../core/noise.js");
|
|
17
|
+
const crypto_js_1 = require("../core/crypto.js");
|
|
17
18
|
const logger_js_1 = require("../utils/logger.js");
|
|
18
19
|
const DEFAULT_WA_URL = 'wss://web.whatsapp.com/ws/chat';
|
|
19
20
|
const DEFAULT_BROWSER = ['Waliwa', 'WA', '1.0.0'];
|
|
@@ -132,48 +133,56 @@ class WAWebSocket extends events_1.EventEmitter {
|
|
|
132
133
|
}
|
|
133
134
|
/**
|
|
134
135
|
* Start Noise Protocol XX handshake
|
|
136
|
+
*
|
|
137
|
+
* Noise XX pattern requires 3 messages:
|
|
138
|
+
* 1. Client -> Server: ephemeral only (32 bytes)
|
|
139
|
+
* 2. Server -> Client: ephemeral + encrypted static + encrypted payload
|
|
140
|
+
* 3. Client -> Server: encrypted static + encrypted payload
|
|
141
|
+
*
|
|
142
|
+
* The WA protocol wraps message 1 with a WA header ("WA" + version),
|
|
143
|
+
* but messages 2 and 3 are sent as raw Noise data.
|
|
135
144
|
*/
|
|
136
145
|
async startHandshake() {
|
|
137
146
|
this.handshake = new noise_js_1.NoiseHandshake(this.noiseKey, true);
|
|
138
|
-
//
|
|
147
|
+
// === Message 1: Send client ephemeral only ===
|
|
148
|
+
// Format: [0x57, 0x41] (WA magic) + [version 2 bytes] + [32-byte ephemeral]
|
|
149
|
+
const ephemeralPub = this.handshake.buildClientHello();
|
|
150
|
+
const waMagic = new Uint8Array([0x57, 0x41, 0x05, 0x2d]); // "WA" + version 5.45
|
|
151
|
+
const clientHello = (0, crypto_js_1.concatBytes)(waMagic, ephemeralPub);
|
|
152
|
+
this.logger.debug(`Sending client hello (${clientHello.length} bytes)`);
|
|
153
|
+
this.ws.send(Buffer.from(clientHello));
|
|
154
|
+
// === Message 2: Wait for server response ===
|
|
155
|
+
const serverData = await this.waitForMessage(15000);
|
|
156
|
+
// Process server response (raw Noise data, NO WA header to strip)
|
|
157
|
+
this.handshake.readResponderHandshake(new Uint8Array(serverData));
|
|
158
|
+
this.logger.debug('Server handshake response processed');
|
|
159
|
+
// === Message 3: Send encrypted static + payload ===
|
|
139
160
|
const clientPayload = this.buildClientPayload();
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
161
|
+
const clientResponse = this.handshake.writeClientResponse(clientPayload);
|
|
162
|
+
this.logger.debug(`Sending client response (${clientResponse.length} bytes)`);
|
|
163
|
+
this.ws.send(Buffer.from(clientResponse));
|
|
164
|
+
// === Finalize: derive traffic keys ===
|
|
165
|
+
const { sendKey, recvKey } = this.handshake.finalize();
|
|
166
|
+
this.trafficCipher = new noise_js_1.TrafficCipher(sendKey, recvKey);
|
|
167
|
+
this.logger.debug('Noise handshake completed, traffic keys derived');
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Wait for a single WebSocket message with timeout
|
|
171
|
+
*/
|
|
172
|
+
waitForMessage(timeoutMs) {
|
|
145
173
|
return new Promise((resolve, reject) => {
|
|
146
174
|
const timeout = setTimeout(() => {
|
|
175
|
+
this.ws.off('message', handler);
|
|
147
176
|
reject(new Error('Handshake response timeout'));
|
|
148
|
-
},
|
|
149
|
-
const
|
|
177
|
+
}, timeoutMs);
|
|
178
|
+
const handler = (data) => {
|
|
150
179
|
clearTimeout(timeout);
|
|
151
|
-
this.ws.off('message',
|
|
152
|
-
|
|
153
|
-
this.processHandshakeResponse(data);
|
|
154
|
-
resolve();
|
|
155
|
-
}
|
|
156
|
-
catch (err) {
|
|
157
|
-
reject(err);
|
|
158
|
-
}
|
|
180
|
+
this.ws.off('message', handler);
|
|
181
|
+
resolve(data);
|
|
159
182
|
};
|
|
160
|
-
this.ws.once('message',
|
|
183
|
+
this.ws.once('message', handler);
|
|
161
184
|
});
|
|
162
185
|
}
|
|
163
|
-
/**
|
|
164
|
-
* Process handshake response dari server
|
|
165
|
-
*/
|
|
166
|
-
processHandshakeResponse(data) {
|
|
167
|
-
if (!this.handshake)
|
|
168
|
-
throw new Error('No handshake state');
|
|
169
|
-
// Strip WA header (7 bytes: WA + version + length)
|
|
170
|
-
const payload = data.subarray(7);
|
|
171
|
-
this.handshake.readResponderHandshake(payload);
|
|
172
|
-
// Finalize - dapatkan traffic keys
|
|
173
|
-
const { sendKey, recvKey } = this.handshake.finalize();
|
|
174
|
-
this.trafficCipher = new noise_js_1.TrafficCipher(sendKey, recvKey);
|
|
175
|
-
this.logger.debug('Noise handshake completed, traffic keys derived');
|
|
176
|
-
}
|
|
177
186
|
/**
|
|
178
187
|
* Build client payload - browser info + pairing static key
|
|
179
188
|
*/
|
|
@@ -201,6 +210,7 @@ class WAWebSocket extends events_1.EventEmitter {
|
|
|
201
210
|
}
|
|
202
211
|
/**
|
|
203
212
|
* Handle incoming message - decrypt jika handshake done
|
|
213
|
+
* After handshake, messages are raw encrypted Noise data (NO WA header)
|
|
204
214
|
*/
|
|
205
215
|
handleMessage(data) {
|
|
206
216
|
if (!this.isHandshakeDone) {
|
|
@@ -208,9 +218,8 @@ class WAWebSocket extends events_1.EventEmitter {
|
|
|
208
218
|
return;
|
|
209
219
|
}
|
|
210
220
|
try {
|
|
211
|
-
//
|
|
212
|
-
const
|
|
213
|
-
const plaintext = this.trafficCipher.decrypt(payload);
|
|
221
|
+
// Raw encrypted data - no WA header to strip
|
|
222
|
+
const plaintext = this.trafficCipher.decrypt(new Uint8Array(data));
|
|
214
223
|
this.emit('message', plaintext);
|
|
215
224
|
}
|
|
216
225
|
catch (err) {
|
|
@@ -220,14 +229,15 @@ class WAWebSocket extends events_1.EventEmitter {
|
|
|
220
229
|
}
|
|
221
230
|
/**
|
|
222
231
|
* Send encrypted frame ke server
|
|
232
|
+
* After handshake, messages are sent as raw encrypted Noise data (NO WA header)
|
|
223
233
|
*/
|
|
224
234
|
send(plaintext) {
|
|
225
235
|
if (!this.isHandshakeDone || !this.trafficCipher) {
|
|
226
236
|
throw new Error('Cannot send before handshake complete');
|
|
227
237
|
}
|
|
228
238
|
const ciphertext = this.trafficCipher.encrypt(plaintext);
|
|
229
|
-
|
|
230
|
-
this.ws.send(Buffer.from(
|
|
239
|
+
// Send raw encrypted data - no WA frame header needed
|
|
240
|
+
this.ws.send(Buffer.from(ciphertext));
|
|
231
241
|
}
|
|
232
242
|
/**
|
|
233
243
|
* Start keep-alive ping
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws-socket.js","sourceRoot":"","sources":["../../src/socket/ws-socket.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;;;;AAEH,4CAA2B;AAC3B,mCAAsC;AACtC,+CAG0B;
|
|
1
|
+
{"version":3,"file":"ws-socket.js","sourceRoot":"","sources":["../../src/socket/ws-socket.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,613 @@
|
|
|
1
|
+
# Community Features & Fixes (v1.1.0)
|
|
2
|
+
|
|
3
|
+
Module `community/` berisi fitur-fitur yang sering diminta komunitas Baileys + fix untuk issue-issue yang dilaporkan.
|
|
4
|
+
|
|
5
|
+
## 📋 Daftar Lengkap
|
|
6
|
+
|
|
7
|
+
### Fitur Baru (10 managers)
|
|
8
|
+
|
|
9
|
+
#### 1. ProfileManager (`sock.profileManager`)
|
|
10
|
+
Update profile picture, about text, display name. Get profile info dengan caching.
|
|
11
|
+
|
|
12
|
+
**Fix issues:**
|
|
13
|
+
- Baileys: profile picture URL tidak bisa didapat
|
|
14
|
+
- Baileys: about text tidak bisa di-get
|
|
15
|
+
- Baileys: business account detection missing
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
// Update profile picture
|
|
19
|
+
await sock.profileManager.updateProfilePicture(jid, imageBuffer);
|
|
20
|
+
|
|
21
|
+
// Update about text
|
|
22
|
+
await sock.profileManager.updateAbout("Hey there! I'm using Waliwa");
|
|
23
|
+
|
|
24
|
+
// Update display name
|
|
25
|
+
await sock.profileManager.updateName("My Name");
|
|
26
|
+
|
|
27
|
+
// Get profile info (cached)
|
|
28
|
+
const info = await sock.profileManager.getProfileInfo(jid);
|
|
29
|
+
console.log(info.name, info.about, info.profilePictureUrl, info.isBusiness);
|
|
30
|
+
|
|
31
|
+
// Download profile picture
|
|
32
|
+
await sock.profileManager.downloadProfilePicture(jid, './profile.jpg');
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
#### 2. PrivacyManager (`sock.privacyManager`)
|
|
36
|
+
Block/unblock users, privacy settings (last seen, profile photo, about, status, read receipts).
|
|
37
|
+
|
|
38
|
+
**Fix issues:**
|
|
39
|
+
- Baileys: block/unblock tidak ada
|
|
40
|
+
- Baileys: privacy settings tidak bisa diubah
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
// Block/unblock
|
|
44
|
+
await sock.privacyManager.block('user@s.whatsapp.net');
|
|
45
|
+
await sock.privacyManager.unblock('user@s.whatsapp.net');
|
|
46
|
+
|
|
47
|
+
// Get blocklist
|
|
48
|
+
const blocked = await sock.privacyManager.getBlocklist();
|
|
49
|
+
|
|
50
|
+
// Set privacy settings
|
|
51
|
+
await sock.privacyManager.setLastSeenPrivacy('contacts'); // all | contacts | contact_blacklist | none
|
|
52
|
+
await sock.privacyManager.setProfilePhotoPrivacy('contacts');
|
|
53
|
+
await sock.privacyManager.setAboutPrivacy('contacts');
|
|
54
|
+
await sock.privacyManager.setStatusPrivacy('contacts');
|
|
55
|
+
await sock.privacyManager.setReadReceiptsPrivacy('none'); // Disable blue ticks
|
|
56
|
+
|
|
57
|
+
// Get current privacy
|
|
58
|
+
const privacy = await sock.privacyManager.getPrivacySettings();
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
#### 3. NewsletterManagerExtended (`sock.newsletterManager`)
|
|
62
|
+
Full newsletter support - create, post, mute, metadata, subscribers, verification.
|
|
63
|
+
|
|
64
|
+
**Fix issues:**
|
|
65
|
+
- Baileys: newsletter support sangat terbatas
|
|
66
|
+
- Baileys: newsletter mute tidak ada
|
|
67
|
+
- Baileys: subscriber count tidak bisa di-get
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
// Create newsletter
|
|
71
|
+
const nl = await sock.newsletterManager.create('My Channel', 'Description');
|
|
72
|
+
|
|
73
|
+
// Subscribe/unsubscribe
|
|
74
|
+
await sock.newsletterManager.subscribe(nl.id);
|
|
75
|
+
await sock.newsletterManager.unsubscribe(nl.id);
|
|
76
|
+
|
|
77
|
+
// Mute/unmute
|
|
78
|
+
await sock.newsletterManager.mute(nl.id);
|
|
79
|
+
await sock.newsletterManager.unmute(nl.id);
|
|
80
|
+
|
|
81
|
+
// Get metadata (subscriber count, verification, dll)
|
|
82
|
+
const meta = await sock.newsletterManager.getMetadata(nl.id);
|
|
83
|
+
console.log(meta.subscribersCount, meta.verification, meta.isOwner);
|
|
84
|
+
|
|
85
|
+
// Post to newsletter
|
|
86
|
+
await sock.newsletterManager.postText(nl.id, 'Hello channel!');
|
|
87
|
+
await sock.newsletterManager.postMedia(nl.id, 'image', 'https://...', 'caption');
|
|
88
|
+
|
|
89
|
+
// React to post
|
|
90
|
+
await sock.newsletterManager.reactToPost(nl.id, postId, '👍');
|
|
91
|
+
|
|
92
|
+
// Get posts
|
|
93
|
+
const posts = await sock.newsletterManager.getPosts(nl.id, 20);
|
|
94
|
+
|
|
95
|
+
// Admin: mute user
|
|
96
|
+
await sock.newsletterManager.muteUser(nl.id, userJid, 3600000);
|
|
97
|
+
|
|
98
|
+
// Owner: transfer ownership
|
|
99
|
+
await sock.newsletterManager.transferOwnership(nl.id, newOwnerJid);
|
|
100
|
+
|
|
101
|
+
// Delete newsletter
|
|
102
|
+
await sock.newsletterManager.delete(nl.id);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
#### 4. StatusExtended (`sock.statusManager`)
|
|
106
|
+
Status/Stories reply, view tracking, privacy settings, album upload.
|
|
107
|
+
|
|
108
|
+
**Fix issues:**
|
|
109
|
+
- Baileys: status reply tidak support
|
|
110
|
+
- Baileys: status view tracking missing
|
|
111
|
+
- Baileys: status privacy settings tidak ada
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
// Reply ke status
|
|
115
|
+
await sock.statusManager.replyToStatus(authorJid, statusId, 'Nice status!');
|
|
116
|
+
|
|
117
|
+
// React to status
|
|
118
|
+
await sock.statusManager.reactToStatus(authorJid, statusId, '❤️');
|
|
119
|
+
|
|
120
|
+
// Get who viewed your status
|
|
121
|
+
const views = await sock.statusManager.getStatusViews(statusId);
|
|
122
|
+
console.log(`${views.length} people viewed your status`);
|
|
123
|
+
|
|
124
|
+
// Get recent statuses dari contacts
|
|
125
|
+
const statuses = await sock.statusManager.getRecentStatuses(50);
|
|
126
|
+
|
|
127
|
+
// Upload text status with background
|
|
128
|
+
await sock.statusManager.sendTextStatus('Hello!', { backgroundColor: '#FF0000' });
|
|
129
|
+
|
|
130
|
+
// Upload status album (multiple items sekaligus)
|
|
131
|
+
await sock.statusManager.sendStatusAlbum([
|
|
132
|
+
{ type: 'image', mediaUrl: 'https://...', caption: 'Photo 1' },
|
|
133
|
+
{ type: 'text', text: 'Caption', backgroundColor: '#0000FF' },
|
|
134
|
+
{ type: 'video', mediaUrl: 'https://...' }
|
|
135
|
+
]);
|
|
136
|
+
|
|
137
|
+
// Get/Set status privacy
|
|
138
|
+
const privacy = await sock.statusManager.getPrivacy();
|
|
139
|
+
await sock.statusManager.setPrivacy({
|
|
140
|
+
whoCanSee: 'whitelist',
|
|
141
|
+
whitelist: ['user1@s.whatsapp.net', 'user2@s.whatsapp.net']
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// Forward status to contacts
|
|
145
|
+
await sock.statusManager.forwardStatus(authorJid, statusId, [user1, user2]);
|
|
146
|
+
|
|
147
|
+
// Mark status as seen
|
|
148
|
+
await sock.statusManager.markAsSeen(authorJid, [statusId1, statusId2]);
|
|
149
|
+
|
|
150
|
+
// Delete own status
|
|
151
|
+
await sock.statusManager.deleteStatus(statusId);
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
#### 5. ContactsManager (`sock.contactsManager`)
|
|
155
|
+
Sync contacts, check if registered, search.
|
|
156
|
+
|
|
157
|
+
**Fix issues:**
|
|
158
|
+
- Baileys: contact sync tidak reliable
|
|
159
|
+
- Baileys: tidak bisa check jika nomor terdaftar di WhatsApp
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
// Sync multiple contacts (check if registered)
|
|
163
|
+
const contacts = await sock.contactsManager.syncContacts([
|
|
164
|
+
'6281234567890',
|
|
165
|
+
'6289876543210',
|
|
166
|
+
'621234567890'
|
|
167
|
+
]);
|
|
168
|
+
|
|
169
|
+
for (const [phone, info] of contacts.entries()) {
|
|
170
|
+
console.log(`${phone}: ${info.isRegistered ? '✓ registered' : '✗ not registered'}`);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Check single number
|
|
174
|
+
const isRegistered = await sock.contactsManager.checkRegistered('6281234567890');
|
|
175
|
+
|
|
176
|
+
// Get contact info
|
|
177
|
+
const info = await sock.contactsManager.getContactInfo('6281234567890');
|
|
178
|
+
|
|
179
|
+
// Search contacts by name/number
|
|
180
|
+
const results = sock.contactsManager.searchContacts('John', 20);
|
|
181
|
+
|
|
182
|
+
// Get all cached contacts
|
|
183
|
+
const all = sock.contactsManager.getAllContacts();
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
#### 6. BulkOperations (`sock.bulkOps`)
|
|
187
|
+
Bulk send, broadcast, album send dengan rate limiting.
|
|
188
|
+
|
|
189
|
+
**Fix issues:**
|
|
190
|
+
- Baileys: bulk send tidak ada
|
|
191
|
+
- Baileys: broadcast tidak ada delay control
|
|
192
|
+
- Baileys: multi-file send tidak support
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
// Bulk send multiple messages dengan delay
|
|
196
|
+
const items = [
|
|
197
|
+
{ jid: 'user1@s.whatsapp.net', content: { text: 'Hello 1' } },
|
|
198
|
+
{ jid: 'user2@s.whatsapp.net', content: { text: 'Hello 2' } },
|
|
199
|
+
{ jid: 'user3@s.whatsapp.net', content: { text: 'Hello 3' } }
|
|
200
|
+
];
|
|
201
|
+
|
|
202
|
+
const results = await sock.bulkOps.bulkSend(items, {
|
|
203
|
+
delayMs: 1000, // 1s delay between sends
|
|
204
|
+
concurrency: 5, // Max 5 concurrent
|
|
205
|
+
stopOnError: false, // Continue on failure
|
|
206
|
+
onProgress: (current, total) => console.log(`${current}/${total}`)
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// Broadcast same message to multiple recipients
|
|
210
|
+
await sock.bulkOps.broadcast(
|
|
211
|
+
{ text: 'Announcement!' },
|
|
212
|
+
['user1@s.whatsapp.net', 'user2@s.whatsapp.net'],
|
|
213
|
+
{ delayMs: 2000 }
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
// Send album (multiple media files)
|
|
217
|
+
await sock.bulkOps.sendAlbum(jid, [
|
|
218
|
+
{ type: 'image', stream: image1, mimetype: 'image/jpeg', caption: 'Photo 1' },
|
|
219
|
+
{ type: 'image', stream: image2, mimetype: 'image/jpeg', caption: 'Photo 2' },
|
|
220
|
+
{ type: 'video', stream: video, mimetype: 'video/mp4' }
|
|
221
|
+
]);
|
|
222
|
+
|
|
223
|
+
// Send with retry
|
|
224
|
+
const result = await sock.bulkOps.sendWithRetry(jid, content, 3, 2000);
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
#### 7. MessageExtras (`sock.messageExtras`)
|
|
228
|
+
Edit message, star/unstar, pin, view-once download, message info.
|
|
229
|
+
|
|
230
|
+
**Fix issues:**
|
|
231
|
+
- Baileys: edit message tidak support
|
|
232
|
+
- Baileys: star messages tidak ada
|
|
233
|
+
- Baileys: view once media tidak bisa didownload
|
|
234
|
+
- Baileys: message read/delivery info missing
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
// Edit message yang sudah dikirim
|
|
238
|
+
await sock.messageExtras.editMessage(jid, key, 'Edited text');
|
|
239
|
+
|
|
240
|
+
// Star/unstar message
|
|
241
|
+
await sock.messageExtras.starMessage(key, true); // star
|
|
242
|
+
await sock.messageExtras.starMessage(key, false); // unstar
|
|
243
|
+
|
|
244
|
+
// Get starred messages in a chat
|
|
245
|
+
const starred = await sock.messageExtras.getStarredMessages(jid, 50);
|
|
246
|
+
|
|
247
|
+
// Pin message in chat
|
|
248
|
+
await sock.messageExtras.pinMessage(key, 24 * 60 * 60 * 1000); // pin for 24h
|
|
249
|
+
await sock.messageExtras.unpinMessage(key);
|
|
250
|
+
|
|
251
|
+
// Mark chat as unread
|
|
252
|
+
await sock.messageExtras.markChatAsUnread(jid);
|
|
253
|
+
|
|
254
|
+
// Get message info (read by, delivered to)
|
|
255
|
+
const info = await sock.messageExtras.getMessageInfo(key);
|
|
256
|
+
console.log('Status:', info.status);
|
|
257
|
+
console.log('Delivered to:', info.deliveredTo);
|
|
258
|
+
console.log('Read by:', info.readBy);
|
|
259
|
+
console.log('Played by:', info.playedBy);
|
|
260
|
+
|
|
261
|
+
// Download view-once media (bypass protection)
|
|
262
|
+
const buffer = await sock.messageExtras.downloadViewOnceMedia(message);
|
|
263
|
+
|
|
264
|
+
// Remove reaction
|
|
265
|
+
await sock.messageExtras.removeReaction(key);
|
|
266
|
+
|
|
267
|
+
// Forward with additional context
|
|
268
|
+
await sock.messageExtras.forwardWithContext(toJid, originalMessage, 'Check this out!');
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
#### 8. DisappearingManager (`sock.disappearingManager`)
|
|
272
|
+
Set disappearing messages timer per chat.
|
|
273
|
+
|
|
274
|
+
**Fix issues:**
|
|
275
|
+
- Baileys: disappearing messages control tidak ada
|
|
276
|
+
- Baileys: tidak bisa set timer per chat
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
// Set timer for a chat
|
|
280
|
+
await sock.disappearingManager.setTimer(jid, '24_hours');
|
|
281
|
+
await sock.disappearingManager.setTimer(jid, '7_days');
|
|
282
|
+
await sock.disappearingManager.setTimer(jid, '90_days');
|
|
283
|
+
await sock.disappearingManager.setTimer(jid, 'off'); // disable
|
|
284
|
+
|
|
285
|
+
// Get current setting
|
|
286
|
+
const timer = await sock.disappearingManager.getSetting(jid);
|
|
287
|
+
|
|
288
|
+
// Set default timer untuk new chats
|
|
289
|
+
await sock.disappearingManager.setDefaultTimer('7_days');
|
|
290
|
+
|
|
291
|
+
// Get all chats with disappearing enabled
|
|
292
|
+
const chats = sock.disappearingManager.getDisappearingChats();
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
#### 9. LiveLocationManager (`sock.liveLocationManager`)
|
|
296
|
+
Share live location dengan real-time updates.
|
|
297
|
+
|
|
298
|
+
**Fix issues:**
|
|
299
|
+
- Baileys: live location tidak support
|
|
300
|
+
- Baileys: tidak bisa stop live location
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
// Start sharing live location
|
|
304
|
+
await sock.liveLocationManager.startSharing(jid, {
|
|
305
|
+
latitude: -6.2088,
|
|
306
|
+
longitude: 106.8456,
|
|
307
|
+
accuracy: 10,
|
|
308
|
+
speed: 0,
|
|
309
|
+
heading: 180,
|
|
310
|
+
altitude: 50,
|
|
311
|
+
expiration: 3600, // 1 hour
|
|
312
|
+
caption: 'On my way!'
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
// Update location
|
|
316
|
+
await sock.liveLocationManager.updateLocation(jid, {
|
|
317
|
+
latitude: -6.2090,
|
|
318
|
+
longitude: 106.8460
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
// Stop sharing
|
|
322
|
+
await sock.liveLocationManager.stopSharing(jid);
|
|
323
|
+
|
|
324
|
+
// Stop all active sharing
|
|
325
|
+
await sock.liveLocationManager.stopAllSharing();
|
|
326
|
+
|
|
327
|
+
// Send static location (non-live)
|
|
328
|
+
await sock.liveLocationManager.sendStaticLocation(jid, -6.2088, 106.8456, {
|
|
329
|
+
name: 'Jakarta',
|
|
330
|
+
address: 'Indonesia'
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
// Parse incoming live location
|
|
334
|
+
const loc = sock.liveLocationManager.parseLiveLocationMessage(message);
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
#### 10. StickerManager (`sock.stickerManager`)
|
|
338
|
+
Create dan send custom stickers, sticker packs.
|
|
339
|
+
|
|
340
|
+
**Fix issues:**
|
|
341
|
+
- Baileys: custom sticker support kurang
|
|
342
|
+
- Baileys: sticker pack tidak support
|
|
343
|
+
|
|
344
|
+
```typescript
|
|
345
|
+
// Send sticker dari image buffer (WebP format)
|
|
346
|
+
await sock.stickerManager.sendSticker(jid, webpBuffer, {
|
|
347
|
+
packName: 'My Pack',
|
|
348
|
+
author: 'Me',
|
|
349
|
+
emojis: ['😀'],
|
|
350
|
+
isAnimated: false
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
// Create sticker pack dari multiple images
|
|
354
|
+
const pack = await sock.stickerManager.createStickerPack(
|
|
355
|
+
'My Sticker Pack',
|
|
356
|
+
'Author Name',
|
|
357
|
+
[
|
|
358
|
+
{ buffer: webp1, emojis: ['😀'] },
|
|
359
|
+
{ buffer: webp2, emojis: ['😂'], isAnimated: true },
|
|
360
|
+
{ buffer: webp3, emojis: ['😍'] }
|
|
361
|
+
]
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
// Get sticker pack info
|
|
365
|
+
const info = await sock.stickerManager.getStickerPack(pack.id);
|
|
366
|
+
|
|
367
|
+
// Delete sticker pack
|
|
368
|
+
await sock.stickerManager.deleteStickerPack(pack.id);
|
|
369
|
+
|
|
370
|
+
// Favorite a sticker
|
|
371
|
+
await sock.stickerManager.favoriteSticker(stickerId, fileSha256);
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
#### 11. AudioTranscriptionManager
|
|
375
|
+
Audio transcription dengan pluggable provider (Whisper, Google, dll).
|
|
376
|
+
|
|
377
|
+
```typescript
|
|
378
|
+
import { AudioTranscriptionManager } from '@kangwifi-pro/waliwa';
|
|
379
|
+
|
|
380
|
+
const atm = new AudioTranscriptionManager();
|
|
381
|
+
|
|
382
|
+
// Use Whisper API
|
|
383
|
+
atm.setProvider(AudioTranscriptionManager.whisperProvider(process.env.OPENAI_API_KEY));
|
|
384
|
+
|
|
385
|
+
// Transcribe audio
|
|
386
|
+
const result = await atm.transcribe(audioBuffer, 'audio/ogg', 'audio-msg-123');
|
|
387
|
+
console.log(result.text); // "Hello, this is a voice message"
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
392
|
+
### Fixes (7 trackers)
|
|
393
|
+
|
|
394
|
+
#### 1. TypingIndicatorTracker (`sock.typingTracker`)
|
|
395
|
+
Reliable typing indicator dengan auto-timeout.
|
|
396
|
+
|
|
397
|
+
**Fix:** Baileys issue - typing indicator tidak reliable
|
|
398
|
+
|
|
399
|
+
```typescript
|
|
400
|
+
sock.typingTracker.on('typing:start', ({ jid, type, timestamp }) => {
|
|
401
|
+
console.log(`${jid} is ${type}...`);
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
sock.typingTracker.on('typing:stop', ({ jid, reason }) => {
|
|
405
|
+
console.log(`${jid} stopped typing (${reason})`);
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
// Manual check
|
|
409
|
+
if (sock.typingTracker.isTyping('user@s.whatsapp.net')) {
|
|
410
|
+
console.log('User is typing');
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// Get all currently typing users
|
|
414
|
+
const typing = sock.typingTracker.getAllTyping();
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
#### 2. LastSeenTracker (`sock.lastSeenTracker`)
|
|
418
|
+
Track last seen timestamps.
|
|
419
|
+
|
|
420
|
+
**Fix:** Baileys issue - last seen tidak bisa di-get
|
|
421
|
+
|
|
422
|
+
```typescript
|
|
423
|
+
// Auto-updated dari presence events
|
|
424
|
+
const lastSeen = sock.lastSeenTracker.getLastSeen('user@s.whatsapp.net');
|
|
425
|
+
const isOnline = sock.lastSeenTracker.isOnline('user@s.whatsapp.net');
|
|
426
|
+
|
|
427
|
+
// Formatted
|
|
428
|
+
const formatted = sock.lastSeenTracker.getFormattedLastSeen('user@s.whatsapp.net');
|
|
429
|
+
// "online now" | "5 minutes ago" | "2 hours ago" | "3 days ago"
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
#### 3. MessageStatusTracker (`sock.messageStatusTracker`)
|
|
433
|
+
Real-time message status tracking dengan detailed info.
|
|
434
|
+
|
|
435
|
+
**Fix:** Baileys issue - message status tidak real-time
|
|
436
|
+
|
|
437
|
+
```typescript
|
|
438
|
+
sock.messageStatusTracker.on('status:update', ({ key, status, timestamp }) => {
|
|
439
|
+
console.log(`Message ${key.id}: ${status} at ${new Date(timestamp).toISOString()}`);
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
// Get detailed info
|
|
443
|
+
const info = sock.messageStatusTracker.getStatusInfo(messageId);
|
|
444
|
+
// { status: 'read', timestamp, deliveredTo: [...], readBy: [...] }
|
|
445
|
+
|
|
446
|
+
// Find stuck messages (pending > 5 min)
|
|
447
|
+
const stuck = sock.messageStatusTracker.getStuckMessages();
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
#### 4. SelfMessageFilter (`sock.selfFilter`)
|
|
451
|
+
Filter self messages otomatis.
|
|
452
|
+
|
|
453
|
+
**Fix:** Baileys issue - self message detection missing
|
|
454
|
+
|
|
455
|
+
```typescript
|
|
456
|
+
// Auto-set dari creds.me
|
|
457
|
+
sock.selfFilter.setOwnJid('6281@s.whatsapp.net');
|
|
458
|
+
|
|
459
|
+
// Check if message is from self
|
|
460
|
+
const isSelf = sock.selfFilter.isSelfMessage(jid);
|
|
461
|
+
const isSelfKey = sock.selfFilter.isSelfKey(message.key);
|
|
462
|
+
|
|
463
|
+
// Filter batch
|
|
464
|
+
const filtered = sock.selfFilter.filterSelfMessages(messages);
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
#### 5. ChatStateManager (`sock.chatStateManager`)
|
|
468
|
+
Reliable chat state persistence (archive, pin, mute).
|
|
469
|
+
|
|
470
|
+
**Fix:** Baileys issue - archive/pin tidak reliable (lost on restart)
|
|
471
|
+
|
|
472
|
+
```typescript
|
|
473
|
+
// Archive/unarchive
|
|
474
|
+
sock.chatStateManager.archive(jid);
|
|
475
|
+
sock.chatStateManager.unarchive(jid);
|
|
476
|
+
|
|
477
|
+
// Pin/unpin (with optional duration)
|
|
478
|
+
sock.chatStateManager.pin(jid, 7 * 24 * 60 * 60 * 1000); // pin for 7 days
|
|
479
|
+
sock.chatStateManager.unpin(jid);
|
|
480
|
+
|
|
481
|
+
// Mute/unmute
|
|
482
|
+
sock.chatStateManager.mute(jid, 8 * 60 * 60 * 1000); // mute for 8 hours
|
|
483
|
+
sock.chatStateManager.unmute(jid);
|
|
484
|
+
|
|
485
|
+
// Mark as read/unread
|
|
486
|
+
sock.chatStateManager.markAsRead(jid);
|
|
487
|
+
sock.chatStateManager.markAsUnread(jid);
|
|
488
|
+
|
|
489
|
+
// Get lists
|
|
490
|
+
const archived = sock.chatStateManager.getArchivedChats();
|
|
491
|
+
const pinned = sock.chatStateManager.getPinnedChats();
|
|
492
|
+
const muted = sock.chatStateManager.getMutedChats();
|
|
493
|
+
|
|
494
|
+
// Serialize untuk persistence
|
|
495
|
+
const data = sock.chatStateManager.serialize();
|
|
496
|
+
// Save to file/DB...
|
|
497
|
+
|
|
498
|
+
// Restore on restart
|
|
499
|
+
sock.chatStateManager.deserialize(savedData);
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
#### 6. DeviceInfoTracker (`sock.deviceInfoTracker`)
|
|
503
|
+
Battery status dan device info tracking.
|
|
504
|
+
|
|
505
|
+
**Fix:** Baileys issue - battery status tidak terdeteksi, phone info tidak bisa di-get
|
|
506
|
+
|
|
507
|
+
```typescript
|
|
508
|
+
sock.deviceInfoTracker.on('battery:update', ({ level, isCharging }) => {
|
|
509
|
+
console.log(`Battery: ${level}% ${isCharging ? '⚡' : ''}`);
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
sock.deviceInfoTracker.on('battery:low', ({ level }) => {
|
|
513
|
+
console.warn(`⚠️ Battery low: ${level}%`);
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
// Manual check
|
|
517
|
+
const level = sock.deviceInfoTracker.getBatteryLevel();
|
|
518
|
+
const isCharging = sock.deviceInfoTracker.isDeviceCharging();
|
|
519
|
+
const deviceInfo = sock.deviceInfoTracker.getDeviceInfo();
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
#### 7. GroupEventsTracker (`sock.groupEventsTracker`)
|
|
523
|
+
Detect group changes (subject, description, announce, restrict, participant count).
|
|
524
|
+
|
|
525
|
+
**Fix:** Baileys issue - group subject/description/announce changes tidak terdeteksi
|
|
526
|
+
|
|
527
|
+
```typescript
|
|
528
|
+
sock.groupEventsTracker.on('group:subject_change', ({ groupJid, oldSubject, newSubject }) => {
|
|
529
|
+
console.log(`Group ${groupJid}: ${oldSubject} -> ${newSubject}`);
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
sock.groupEventsTracker.on('group:description_change', ({ groupJid, oldDescription, newDescription }) => {
|
|
533
|
+
console.log(`Group ${groupJid} description changed`);
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
sock.groupEventsTracker.on('group:announce_change', ({ groupJid, announce }) => {
|
|
537
|
+
console.log(`Group ${groupJid} ${announce ? 'now admins only' : 'all can send'}`);
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
sock.groupEventsTracker.on('group:restrict_change', ({ groupJid, restrict }) => {
|
|
541
|
+
console.log(`Group ${groupJid} ${restrict ? 'now restricted' : 'now open'}`);
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
sock.groupEventsTracker.on('group:participant_count_change', ({ groupJid, oldCount, newCount }) => {
|
|
545
|
+
console.log(`Group ${groupJid}: ${oldCount} -> ${newCount} participants`);
|
|
546
|
+
});
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
---
|
|
550
|
+
|
|
551
|
+
### Helper Functions
|
|
552
|
+
|
|
553
|
+
#### parseGroupInviteInfo
|
|
554
|
+
Parse info dari group invite link.
|
|
555
|
+
|
|
556
|
+
```typescript
|
|
557
|
+
import { parseGroupInviteInfo } from '@kangwifi-pro/waliwa';
|
|
558
|
+
|
|
559
|
+
// Get info dari invite link (returns GroupInviteInfo)
|
|
560
|
+
const info = parseGroupInviteInfo(responseNode);
|
|
561
|
+
// { code, groupJid, subject, description, participantsCount, isCommunity, ... }
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
#### detectLanguageFromText
|
|
565
|
+
Detect language dari text.
|
|
566
|
+
|
|
567
|
+
```typescript
|
|
568
|
+
import { detectLanguageFromText } from '@kangwifi-pro/waliwa';
|
|
569
|
+
|
|
570
|
+
detectLanguageFromText('Hello world'); // 'en'
|
|
571
|
+
detectLanguageFromText('こんにちは'); // 'ja'
|
|
572
|
+
detectLanguageFromText('مرحبا'); // 'ar'
|
|
573
|
+
detectLanguageFromText('你好'); // 'zh'
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
---
|
|
577
|
+
|
|
578
|
+
## Ringkasan Perbaikan Issue Baileys
|
|
579
|
+
|
|
580
|
+
| Issue Baileys | Fix | Module |
|
|
581
|
+
|--------------|-----|--------|
|
|
582
|
+
| Profile picture URL tidak bisa didapat | ProfileManager.fetchProfilePictureUrl | profile-manager |
|
|
583
|
+
| About text tidak bisa di-get | ProfileManager.fetchAbout | profile-manager |
|
|
584
|
+
| Business account detection missing | ProfileManager.checkBusinessAccount | profile-manager |
|
|
585
|
+
| Block/unblock tidak ada | PrivacyManager.block/unblock | privacy-manager |
|
|
586
|
+
| Privacy settings tidak bisa diubah | PrivacyManager.setPrivacy | privacy-manager |
|
|
587
|
+
| Newsletter support terbatas | NewsletterManagerExtended (10 methods) | newsletter-extended |
|
|
588
|
+
| Status reply tidak support | StatusExtended.replyToStatus | status-extended |
|
|
589
|
+
| Status view tracking missing | StatusExtended.getStatusViews | status-extended |
|
|
590
|
+
| Status privacy settings tidak ada | StatusExtended.getPrivacy/setPrivacy | status-extended |
|
|
591
|
+
| Contact sync tidak reliable | ContactsManager.syncContacts | contacts-manager |
|
|
592
|
+
| Tidak bisa check nomor terdaftar | ContactsManager.checkRegistered | contacts-manager |
|
|
593
|
+
| Bulk send tidak ada | BulkOperations.bulkSend | bulk-operations |
|
|
594
|
+
| Multi-file send tidak support | BulkOperations.sendAlbum | bulk-operations |
|
|
595
|
+
| Edit message tidak support | MessageExtras.editMessage | message-extras |
|
|
596
|
+
| Star messages tidak ada | MessageExtras.starMessage | message-extras |
|
|
597
|
+
| View once media tidak bisa didownload | MessageExtras.downloadViewOnceMedia | message-extras |
|
|
598
|
+
| Message read/delivery info missing | MessageExtras.getMessageInfo | message-extras |
|
|
599
|
+
| Disappearing messages control tidak ada | DisappearingManager.setTimer | disappearing |
|
|
600
|
+
| Live location tidak support | LiveLocationManager.startSharing | live-location |
|
|
601
|
+
| Custom sticker support kurang | StickerManager.sendSticker | sticker-manager |
|
|
602
|
+
| Sticker pack tidak support | StickerManager.createStickerPack | sticker-manager |
|
|
603
|
+
| Typing indicator tidak reliable | TypingIndicatorTracker | community-fixes |
|
|
604
|
+
| Last seen tidak bisa di-get | LastSeenTracker | community-fixes |
|
|
605
|
+
| Message status tidak real-time | MessageStatusTracker | community-fixes |
|
|
606
|
+
| Self message detection missing | SelfMessageFilter | community-fixes |
|
|
607
|
+
| Archive/pin tidak reliable | ChatStateManager | community-fixes |
|
|
608
|
+
| Battery status tidak terdeteksi | DeviceInfoTracker | community-fixes |
|
|
609
|
+
| Phone info tidak bisa di-get | DeviceInfoTracker | community-fixes |
|
|
610
|
+
| Group changes tidak terdeteksi | GroupEventsTracker | community-fixes |
|
|
611
|
+
| Group invite link info tidak support | parseGroupInviteInfo | community-fixes |
|
|
612
|
+
|
|
613
|
+
**Total: 28+ issue Baileys di-fix di v1.1.0**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kangwifi-pro/waliwa",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Lightweight, RAM-efficient WhatsApp library with hybrid protocol (WhatsApp Web MD + Mobile API), Multi-Branch SKDM Recovery system, Community features, and 9+ Baileys issue fixes. More complete than Baileys, lighter than ZapoJS.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
package/src/core/noise.ts
CHANGED
|
@@ -183,6 +183,7 @@ export class NoiseHandshake {
|
|
|
183
183
|
|
|
184
184
|
/**
|
|
185
185
|
* Step 2: Receive ephemeral + static + EE + ES from responder
|
|
186
|
+
* Server sends: [32-byte ephemeral] [48-byte encrypted static] [N-byte encrypted payload]
|
|
186
187
|
*/
|
|
187
188
|
public readResponderHandshake(payload: Uint8Array): { plaintext: Uint8Array } {
|
|
188
189
|
// First 32 bytes = ephemeral key
|
|
@@ -196,36 +197,39 @@ export class NoiseHandshake {
|
|
|
196
197
|
const ee = curveSharedSecret(this.state.e.private, re);
|
|
197
198
|
this.mixKey(ee);
|
|
198
199
|
|
|
199
|
-
// Next
|
|
200
|
-
|
|
201
|
-
const
|
|
202
|
-
|
|
200
|
+
// Next 48 bytes = encrypted static (32-byte ct + 16-byte GCM tag)
|
|
201
|
+
if (payload.length < 80) throw new Error('Handshake too short for static');
|
|
202
|
+
const encryptedStatic = payload.subarray(32, 80);
|
|
203
|
+
const remoteStatic = this.decryptWithHash(encryptedStatic); // 32 bytes
|
|
204
|
+
this.state.rs = remoteStatic;
|
|
203
205
|
this.mixHash(remoteStatic);
|
|
204
206
|
|
|
205
207
|
// Ephemeral-static DH
|
|
206
208
|
const es = curveSharedSecret(this.state.e.private, remoteStatic);
|
|
207
209
|
this.mixKey(es);
|
|
208
210
|
|
|
209
|
-
// Remaining
|
|
210
|
-
const encryptedPayload =
|
|
211
|
-
|
|
211
|
+
// Remaining = encrypted payload (may be empty)
|
|
212
|
+
const encryptedPayload = payload.subarray(80);
|
|
213
|
+
let plaintext: Uint8Array = new Uint8Array(0);
|
|
214
|
+
if (encryptedPayload.length > 0) {
|
|
215
|
+
plaintext = this.decryptWithHash(encryptedPayload);
|
|
216
|
+
}
|
|
212
217
|
|
|
213
|
-
return { plaintext
|
|
218
|
+
return { plaintext };
|
|
214
219
|
}
|
|
215
220
|
|
|
216
221
|
/**
|
|
217
|
-
* Step 3: Send our static +
|
|
222
|
+
* Step 3: Send our static + SE + payload (initiator -> responder)
|
|
223
|
+
* Returns: [48-byte encrypted static] [N-byte encrypted payload]
|
|
224
|
+
* MUST be called AFTER readResponderHandshake (needs remote ephemeral)
|
|
218
225
|
*/
|
|
219
|
-
public
|
|
220
|
-
//
|
|
221
|
-
// Now send static + ES + payload, all encrypted with current handshake key
|
|
222
|
-
|
|
223
|
-
// Encrypt our static key
|
|
226
|
+
public writeClientResponse(payload: Uint8Array): Uint8Array {
|
|
227
|
+
// Encrypt our static key (32 bytes → 48 bytes with GCM tag)
|
|
224
228
|
const encryptedStatic = this.encryptWithHash(this.state.s.public);
|
|
225
229
|
this.mixHash(this.state.s.public);
|
|
226
230
|
|
|
227
|
-
// Static-ephemeral DH (
|
|
228
|
-
if (!this.state.re) throw new Error('No remote ephemeral');
|
|
231
|
+
// Static-ephemeral DH (our static private, their ephemeral public)
|
|
232
|
+
if (!this.state.re) throw new Error('No remote ephemeral - call readResponderHandshake first');
|
|
229
233
|
const se = curveSharedSecret(this.state.s.private, this.state.re);
|
|
230
234
|
this.mixKey(se);
|
|
231
235
|
|
|
@@ -325,13 +329,13 @@ export class NoiseHandshake {
|
|
|
325
329
|
}
|
|
326
330
|
|
|
327
331
|
/**
|
|
328
|
-
* Build client hello
|
|
332
|
+
* Build initial client hello - ONLY the ephemeral key for message 1
|
|
333
|
+
* The encrypted static + payload (message 3) is sent separately
|
|
334
|
+
* after receiving the server's response (message 2)
|
|
329
335
|
*/
|
|
330
|
-
public buildClientHello(
|
|
331
|
-
//
|
|
332
|
-
|
|
333
|
-
const encrypted = this.writeInitiatorHandshake(clientPayload);
|
|
334
|
-
return concatBytes(ephemeral, encrypted);
|
|
336
|
+
public buildClientHello(): Uint8Array {
|
|
337
|
+
// Message 1: just the ephemeral public key
|
|
338
|
+
return this.writeEphemeral();
|
|
335
339
|
}
|
|
336
340
|
}
|
|
337
341
|
|
package/src/index.ts
CHANGED
|
@@ -324,7 +324,7 @@ export {
|
|
|
324
324
|
export * from './types/index.js';
|
|
325
325
|
|
|
326
326
|
// ============== Version ==============
|
|
327
|
-
export const VERSION = '1.1.
|
|
327
|
+
export const VERSION = '1.1.1';
|
|
328
328
|
export const LIBRARY_NAME = 'waliwa';
|
|
329
329
|
|
|
330
330
|
// ============== Default Config ==============
|
package/src/socket/ws-socket.ts
CHANGED
|
@@ -170,54 +170,64 @@ export class WAWebSocket extends EventEmitter {
|
|
|
170
170
|
|
|
171
171
|
/**
|
|
172
172
|
* Start Noise Protocol XX handshake
|
|
173
|
+
*
|
|
174
|
+
* Noise XX pattern requires 3 messages:
|
|
175
|
+
* 1. Client -> Server: ephemeral only (32 bytes)
|
|
176
|
+
* 2. Server -> Client: ephemeral + encrypted static + encrypted payload
|
|
177
|
+
* 3. Client -> Server: encrypted static + encrypted payload
|
|
178
|
+
*
|
|
179
|
+
* The WA protocol wraps message 1 with a WA header ("WA" + version),
|
|
180
|
+
* but messages 2 and 3 are sent as raw Noise data.
|
|
173
181
|
*/
|
|
174
182
|
private async startHandshake(): Promise<void> {
|
|
175
183
|
this.handshake = new NoiseHandshake(this.noiseKey, true);
|
|
176
184
|
|
|
177
|
-
//
|
|
185
|
+
// === Message 1: Send client ephemeral only ===
|
|
186
|
+
// Format: [0x57, 0x41] (WA magic) + [version 2 bytes] + [32-byte ephemeral]
|
|
187
|
+
const ephemeralPub = this.handshake.buildClientHello();
|
|
188
|
+
const waMagic = new Uint8Array([0x57, 0x41, 0x05, 0x2d]); // "WA" + version 5.45
|
|
189
|
+
const clientHello = concatBytes(waMagic, ephemeralPub);
|
|
190
|
+
this.logger.debug(`Sending client hello (${clientHello.length} bytes)`);
|
|
191
|
+
this.ws!.send(Buffer.from(clientHello));
|
|
192
|
+
|
|
193
|
+
// === Message 2: Wait for server response ===
|
|
194
|
+
const serverData = await this.waitForMessage(15000);
|
|
195
|
+
|
|
196
|
+
// Process server response (raw Noise data, NO WA header to strip)
|
|
197
|
+
this.handshake.readResponderHandshake(new Uint8Array(serverData));
|
|
198
|
+
this.logger.debug('Server handshake response processed');
|
|
199
|
+
|
|
200
|
+
// === Message 3: Send encrypted static + payload ===
|
|
178
201
|
const clientPayload = this.buildClientPayload();
|
|
179
|
-
const
|
|
202
|
+
const clientResponse = this.handshake.writeClientResponse(clientPayload);
|
|
203
|
+
this.logger.debug(`Sending client response (${clientResponse.length} bytes)`);
|
|
204
|
+
this.ws!.send(Buffer.from(clientResponse));
|
|
180
205
|
|
|
181
|
-
//
|
|
182
|
-
const
|
|
183
|
-
this.
|
|
206
|
+
// === Finalize: derive traffic keys ===
|
|
207
|
+
const { sendKey, recvKey } = this.handshake.finalize();
|
|
208
|
+
this.trafficCipher = new TrafficCipher(sendKey, recvKey);
|
|
209
|
+
this.logger.debug('Noise handshake completed, traffic keys derived');
|
|
210
|
+
}
|
|
184
211
|
|
|
185
|
-
|
|
212
|
+
/**
|
|
213
|
+
* Wait for a single WebSocket message with timeout
|
|
214
|
+
*/
|
|
215
|
+
private waitForMessage(timeoutMs: number): Promise<Buffer> {
|
|
186
216
|
return new Promise((resolve, reject) => {
|
|
187
217
|
const timeout = setTimeout(() => {
|
|
218
|
+
this.ws!.off('message', handler);
|
|
188
219
|
reject(new Error('Handshake response timeout'));
|
|
189
|
-
},
|
|
220
|
+
}, timeoutMs);
|
|
190
221
|
|
|
191
|
-
const
|
|
222
|
+
const handler = (data: Buffer) => {
|
|
192
223
|
clearTimeout(timeout);
|
|
193
|
-
this.ws!.off('message',
|
|
194
|
-
|
|
195
|
-
this.processHandshakeResponse(data);
|
|
196
|
-
resolve();
|
|
197
|
-
} catch (err) {
|
|
198
|
-
reject(err);
|
|
199
|
-
}
|
|
224
|
+
this.ws!.off('message', handler);
|
|
225
|
+
resolve(data);
|
|
200
226
|
};
|
|
201
|
-
this.ws!.once('message',
|
|
227
|
+
this.ws!.once('message', handler);
|
|
202
228
|
});
|
|
203
229
|
}
|
|
204
230
|
|
|
205
|
-
/**
|
|
206
|
-
* Process handshake response dari server
|
|
207
|
-
*/
|
|
208
|
-
private processHandshakeResponse(data: Buffer): void {
|
|
209
|
-
if (!this.handshake) throw new Error('No handshake state');
|
|
210
|
-
|
|
211
|
-
// Strip WA header (7 bytes: WA + version + length)
|
|
212
|
-
const payload = data.subarray(7);
|
|
213
|
-
this.handshake.readResponderHandshake(payload);
|
|
214
|
-
|
|
215
|
-
// Finalize - dapatkan traffic keys
|
|
216
|
-
const { sendKey, recvKey } = this.handshake.finalize();
|
|
217
|
-
this.trafficCipher = new TrafficCipher(sendKey, recvKey);
|
|
218
|
-
this.logger.debug('Noise handshake completed, traffic keys derived');
|
|
219
|
-
}
|
|
220
|
-
|
|
221
231
|
/**
|
|
222
232
|
* Build client payload - browser info + pairing static key
|
|
223
233
|
*/
|
|
@@ -249,6 +259,7 @@ export class WAWebSocket extends EventEmitter {
|
|
|
249
259
|
|
|
250
260
|
/**
|
|
251
261
|
* Handle incoming message - decrypt jika handshake done
|
|
262
|
+
* After handshake, messages are raw encrypted Noise data (NO WA header)
|
|
252
263
|
*/
|
|
253
264
|
private handleMessage(data: Buffer): void {
|
|
254
265
|
if (!this.isHandshakeDone) {
|
|
@@ -256,9 +267,8 @@ export class WAWebSocket extends EventEmitter {
|
|
|
256
267
|
return;
|
|
257
268
|
}
|
|
258
269
|
try {
|
|
259
|
-
//
|
|
260
|
-
const
|
|
261
|
-
const plaintext = this.trafficCipher!.decrypt(payload);
|
|
270
|
+
// Raw encrypted data - no WA header to strip
|
|
271
|
+
const plaintext = this.trafficCipher!.decrypt(new Uint8Array(data));
|
|
262
272
|
this.emit('message', plaintext);
|
|
263
273
|
} catch (err: any) {
|
|
264
274
|
this.logger.error(`Message decrypt failed: ${err.message}`);
|
|
@@ -268,14 +278,15 @@ export class WAWebSocket extends EventEmitter {
|
|
|
268
278
|
|
|
269
279
|
/**
|
|
270
280
|
* Send encrypted frame ke server
|
|
281
|
+
* After handshake, messages are sent as raw encrypted Noise data (NO WA header)
|
|
271
282
|
*/
|
|
272
283
|
send(plaintext: Uint8Array): void {
|
|
273
284
|
if (!this.isHandshakeDone || !this.trafficCipher) {
|
|
274
285
|
throw new Error('Cannot send before handshake complete');
|
|
275
286
|
}
|
|
276
287
|
const ciphertext = this.trafficCipher.encrypt(plaintext);
|
|
277
|
-
|
|
278
|
-
this.ws!.send(Buffer.from(
|
|
288
|
+
// Send raw encrypted data - no WA frame header needed
|
|
289
|
+
this.ws!.send(Buffer.from(ciphertext));
|
|
279
290
|
}
|
|
280
291
|
|
|
281
292
|
/**
|