@signalapp/libsignal-client 0.50.0 → 0.51.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/Native.d.ts CHANGED
@@ -114,6 +114,18 @@ export abstract class InputStream {
114
114
 
115
115
  export abstract class SyncInputStream extends Buffer {}
116
116
 
117
+ export abstract class ChatListener {
118
+ _incoming_message(
119
+ envelope: Buffer,
120
+ timestamp: number,
121
+ ack: ServerMessageAck
122
+ ): void;
123
+ _queue_empty(): void;
124
+ _connection_interrupted(): void;
125
+ }
126
+
127
+ export abstract class MakeChatListener extends ChatListener {}
128
+
117
129
  type Wrapper<T> = Readonly<{
118
130
  _nativeHandle: T;
119
131
  }>;
@@ -168,6 +180,7 @@ export function Cds2ClientState_New(mrenclave: Buffer, attestationMsg: Buffer, c
168
180
  export function CdsiLookup_complete(asyncRuntime: Wrapper<TokioAsyncContext>, lookup: Wrapper<CdsiLookup>): Promise<LookupResponse>;
169
181
  export function CdsiLookup_new(asyncRuntime: Wrapper<TokioAsyncContext>, connectionManager: Wrapper<ConnectionManager>, username: string, password: string, request: Wrapper<LookupRequest>): Promise<CdsiLookup>;
170
182
  export function CdsiLookup_token(lookup: Wrapper<CdsiLookup>): Buffer;
183
+ export function ChatServer_SetListener(runtime: Wrapper<TokioAsyncContext>, chat: Wrapper<Chat>, makeListener: MakeChatListener | null): void;
171
184
  export function ChatService_auth_send(asyncRuntime: Wrapper<TokioAsyncContext>, chat: Wrapper<Chat>, httpRequest: Wrapper<HttpRequest>, timeoutMillis: number): Promise<ChatResponse>;
172
185
  export function ChatService_auth_send_and_debug(asyncRuntime: Wrapper<TokioAsyncContext>, chat: Wrapper<Chat>, httpRequest: Wrapper<HttpRequest>, timeoutMillis: number): Promise<ResponseAndDebugInfo>;
173
186
  export function ChatService_connect_auth(asyncRuntime: Wrapper<TokioAsyncContext>, chat: Wrapper<Chat>): Promise<ChatServiceDebugInfo>;
@@ -480,6 +493,7 @@ export function TESTING_ChatServiceDebugInfoConvert(): ChatServiceDebugInfo;
480
493
  export function TESTING_ChatServiceErrorConvert(errorDescription: string): void;
481
494
  export function TESTING_ChatServiceResponseAndDebugInfoConvert(): ResponseAndDebugInfo;
482
495
  export function TESTING_ChatServiceResponseConvert(bodyPresent: boolean): ChatResponse;
496
+ export function TESTING_ChatService_InjectConnectionInterrupted(chat: Wrapper<Chat>): void;
483
497
  export function TESTING_ChatService_InjectRawServerRequest(chat: Wrapper<Chat>, bytes: Buffer): void;
484
498
  export function TESTING_ErrorOnBorrowAsync(_input: null): Promise<void>;
485
499
  export function TESTING_ErrorOnBorrowIo(asyncRuntime: Wrapper<NonSuspendingBackgroundThreadRuntime>, _input: null): Promise<void>;
@@ -669,7 +669,7 @@ For more information on this, and how to apply and follow the GNU AGPL, see
669
669
 
670
670
  ```
671
671
 
672
- ## attest 0.1.0, device-transfer 0.1.0, libsignal-bridge 0.1.0, libsignal-bridge-macros 0.1.0, libsignal-core 0.1.0, libsignal-ffi 0.50.0, libsignal-jni 0.50.0, libsignal-message-backup 0.1.0, libsignal-message-backup-macros 0.1.0, libsignal-net 0.1.0, libsignal-node 0.50.0, libsignal-protocol 0.1.0, libsignal-svr3 0.1.0, poksho 0.7.0, signal-crypto 0.1.0, signal-media 0.1.0, signal-neon-futures 0.1.0, signal-neon-futures-tests 0.1.0, signal-pin 0.1.0, usernames 0.1.0, zkcredential 0.1.0, zkgroup 0.9.0
672
+ ## attest 0.1.0, device-transfer 0.1.0, libsignal-bridge 0.1.0, libsignal-bridge-macros 0.1.0, libsignal-core 0.1.0, libsignal-ffi 0.51.0, libsignal-jni 0.51.0, libsignal-message-backup 0.1.0, libsignal-message-backup-macros 0.1.0, libsignal-net 0.1.0, libsignal-node 0.51.0, libsignal-protocol 0.1.0, libsignal-svr3 0.1.0, poksho 0.7.0, signal-crypto 0.1.0, signal-media 0.1.0, signal-neon-futures 0.1.0, signal-neon-futures-tests 0.1.0, signal-pin 0.1.0, usernames 0.1.0, zkcredential 0.1.0, zkgroup 0.9.0
673
673
 
674
674
  ```
675
675
  GNU AFFERO GENERAL PUBLIC LICENSE
package/dist/net.d.ts CHANGED
@@ -2,6 +2,7 @@
2
2
  import type { ReadonlyDeep } from 'type-fest';
3
3
  import * as Native from '../Native';
4
4
  import { Wrapper } from '../Native';
5
+ import { Buffer } from 'node:buffer';
5
6
  export declare enum Environment {
6
7
  Staging = 0,
7
8
  Production = 1
@@ -42,6 +43,41 @@ export declare class TokioAsyncContext {
42
43
  constructor(handle: Native.TokioAsyncContext);
43
44
  makeCancellable<T>(abortSignal: AbortSignal | undefined, promise: Promise<T>): Promise<T>;
44
45
  }
46
+ export declare class ChatServerMessageAck {
47
+ private readonly asyncContext;
48
+ readonly _nativeHandle: Native.ServerMessageAck;
49
+ private promise;
50
+ constructor(asyncContext: TokioAsyncContext, _nativeHandle: Native.ServerMessageAck);
51
+ send(): Promise<void>;
52
+ }
53
+ export interface ChatServiceListener {
54
+ /**
55
+ * Called when the server delivers an incoming message to the client.
56
+ *
57
+ * `timestamp` is in milliseconds.
58
+ *
59
+ * If `ack`'s `send` method is not called, the server will leave this message in the message
60
+ * queue and attempt to deliver it again in the future.
61
+ */
62
+ onIncomingMessage(envelope: Buffer, timestamp: number, ack: ChatServerMessageAck): void;
63
+ /**
64
+ * Called when the server indicates that there are no further messages in the message queue.
65
+ *
66
+ * Note that further messages may still be delivered; this merely indicates that all messages that
67
+ * were in the queue *when the connection was established* have been delivered.
68
+ */
69
+ onQueueEmpty(): void;
70
+ /**
71
+ * Called when the client gets disconnected from the server.
72
+ *
73
+ * This includes both deliberate disconnects as well as unexpected socket closures that will be
74
+ * automatically retried.
75
+ *
76
+ * Will not be called if no other requests have been invoked for this connection attempt. That is,
77
+ * you should never see this as the first callback, nor two of these callbacks in a row.
78
+ */
79
+ onConnectionInterrupted(): void;
80
+ }
45
81
  /**
46
82
  * Provides API methods to connect and communicate with the Chat Service.
47
83
  * Before using either authenticated or unauthenticated channels,
@@ -50,8 +86,19 @@ export declare class TokioAsyncContext {
50
86
  */
51
87
  export declare class ChatService {
52
88
  private readonly asyncContext;
53
- private readonly chatService;
89
+ readonly chatService: Wrapper<Native.Chat>;
54
90
  constructor(asyncContext: TokioAsyncContext, connectionManager: ConnectionManager);
91
+ /**
92
+ * Sets the listener for server push messages on the authenticated connection.
93
+ *
94
+ * Note that this creates a **non-garbage-collectable** reference to `listener`. If `listener`
95
+ * contains a reference to this ChatService (directly or indirectly), both objects will be kept
96
+ * alive even with no other references. This may be fine if `listener` is a long-lived object
97
+ * anyway, but if not, make sure to eventually break the cycle, possibly by calling
98
+ * {@link #clearListener}.
99
+ */
100
+ setListener(listener: ChatServiceListener): void;
101
+ clearListener(): void;
55
102
  /**
56
103
  * Initiates termination of the underlying connection to the Chat Service. After the service is
57
104
  * disconnected, it will not attempt to automatically reconnect until you call
@@ -80,6 +127,7 @@ export declare class ChatService {
80
127
  * reconnect attempt will be made.
81
128
  *
82
129
  * Calling this method will result in starting to accept incoming requests from the Chat Service.
130
+ * You should set a listener first using {@link #setListener()}.
83
131
  *
84
132
  * @throws {AppExpiredError} if the current app version is too old (as judged by the server).
85
133
  * @throws {DeviceDelinkedError} if the current device has been delinked.
package/dist/net.js CHANGED
@@ -4,9 +4,10 @@
4
4
  // SPDX-License-Identifier: AGPL-3.0-only
5
5
  //
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.RestoredSecret = exports.Net = exports.ChatService = exports.TokioAsyncContext = exports.Environment = void 0;
7
+ exports.RestoredSecret = exports.Net = exports.ChatService = exports.ChatServerMessageAck = exports.TokioAsyncContext = exports.Environment = void 0;
8
8
  const Native = require("../Native");
9
9
  const Address_1 = require("./Address");
10
+ const node_buffer_1 = require("node:buffer");
10
11
  const DEFAULT_CHAT_REQUEST_TIMEOUT_MILLIS = 5000;
11
12
  // This must match the libsignal-bridge Rust enum of the same name.
12
13
  var Environment;
@@ -43,6 +44,20 @@ class TokioAsyncContext {
43
44
  }
44
45
  }
45
46
  exports.TokioAsyncContext = TokioAsyncContext;
47
+ class ChatServerMessageAck {
48
+ constructor(asyncContext, _nativeHandle) {
49
+ this.asyncContext = asyncContext;
50
+ this._nativeHandle = _nativeHandle;
51
+ this.promise = null;
52
+ }
53
+ send() {
54
+ if (!this.promise) {
55
+ this.promise = Native.ServerMessageAck_Send(this.asyncContext, this);
56
+ }
57
+ return this.promise;
58
+ }
59
+ }
60
+ exports.ChatServerMessageAck = ChatServerMessageAck;
46
61
  /**
47
62
  * Provides API methods to connect and communicate with the Chat Service.
48
63
  * Before using either authenticated or unauthenticated channels,
@@ -54,6 +69,33 @@ class ChatService {
54
69
  this.asyncContext = asyncContext;
55
70
  this.chatService = newNativeHandle(Native.ChatService_new(connectionManager, '', ''));
56
71
  }
72
+ /**
73
+ * Sets the listener for server push messages on the authenticated connection.
74
+ *
75
+ * Note that this creates a **non-garbage-collectable** reference to `listener`. If `listener`
76
+ * contains a reference to this ChatService (directly or indirectly), both objects will be kept
77
+ * alive even with no other references. This may be fine if `listener` is a long-lived object
78
+ * anyway, but if not, make sure to eventually break the cycle, possibly by calling
79
+ * {@link #clearListener}.
80
+ */
81
+ setListener(listener) {
82
+ const asyncContext = this.asyncContext;
83
+ const nativeChatListener = {
84
+ _incoming_message(envelope, timestamp, ack) {
85
+ listener.onIncomingMessage(envelope, timestamp, new ChatServerMessageAck(asyncContext, ack));
86
+ },
87
+ _queue_empty() {
88
+ listener.onQueueEmpty();
89
+ },
90
+ _connection_interrupted() {
91
+ listener.onConnectionInterrupted();
92
+ },
93
+ };
94
+ Native.ChatServer_SetListener(asyncContext, this.chatService, nativeChatListener);
95
+ }
96
+ clearListener() {
97
+ Native.ChatServer_SetListener(this.asyncContext, this.chatService, null);
98
+ }
57
99
  /**
58
100
  * Initiates termination of the underlying connection to the Chat Service. After the service is
59
101
  * disconnected, it will not attempt to automatically reconnect until you call
@@ -84,6 +126,7 @@ class ChatService {
84
126
  * reconnect attempt will be made.
85
127
  *
86
128
  * Calling this method will result in starting to accept incoming requests from the Chat Service.
129
+ * You should set a listener first using {@link #setListener()}.
87
130
  *
88
131
  * @throws {AppExpiredError} if the current app version is too old (as judged by the server).
89
132
  * @throws {DeviceDelinkedError} if the current device has been delinked.
@@ -136,7 +179,7 @@ class ChatService {
136
179
  }
137
180
  static buildHttpRequest(chatRequest) {
138
181
  const { verb, path, body, headers } = chatRequest;
139
- const bodyBuffer = body !== undefined ? Buffer.from(body) : null;
182
+ const bodyBuffer = body !== undefined ? node_buffer_1.Buffer.from(body) : null;
140
183
  const httpRequest = {
141
184
  _nativeHandle: Native.HttpRequest_new(verb, path, bodyBuffer),
142
185
  };
@@ -195,7 +238,7 @@ class Net {
195
238
  Native.LookupRequest_addE164(request, e164);
196
239
  });
197
240
  acisAndAccessKeys.forEach(({ aci: aciStr, accessKey: accessKeyStr }) => {
198
- Native.LookupRequest_addAciAndAccessKey(request, Address_1.Aci.parseFromServiceIdString(aciStr).getServiceIdFixedWidthBinary(), Buffer.from(accessKeyStr, 'base64'));
241
+ Native.LookupRequest_addAciAndAccessKey(request, Address_1.Aci.parseFromServiceIdString(aciStr).getServiceIdFixedWidthBinary(), node_buffer_1.Buffer.from(accessKeyStr, 'base64'));
199
242
  });
200
243
  Native.LookupRequest_setReturnAcisWithoutUaks(request, returnAcisWithoutUaks);
201
244
  const lookup = await this.asyncContext.makeCancellable(abortSignal, Native.CdsiLookup_new(this.asyncContext, this.connectionManager, username, password, request));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signalapp/libsignal-client",
3
- "version": "0.50.0",
3
+ "version": "0.51.0",
4
4
  "license": "AGPL-3.0-only",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -19,6 +19,7 @@
19
19
  "scripts": {
20
20
  "install": "node-gyp-build",
21
21
  "build": "node-gyp build",
22
+ "build-with-debug-level-logs": "npx --libsignal-debug-level-logs node-gyp build",
22
23
  "tsc": "tsc -b",
23
24
  "clean": "rimraf dist build prebuilds",
24
25
  "test": "mocha --recursive dist/test --require source-map-support/register",
@@ -39,6 +40,8 @@
39
40
  "@types/chance": "^1.1.3",
40
41
  "@types/mocha": "^5.2.7",
41
42
  "@types/node": "~18.15.0",
43
+ "@types/sinon": "^17.0.3",
44
+ "@types/sinon-chai": "^3.2.12",
42
45
  "@types/uuid": "^8.3.0",
43
46
  "@typescript-eslint/eslint-plugin": "^5.47.0",
44
47
  "@typescript-eslint/parser": "^5.47.0",
@@ -57,6 +60,8 @@
57
60
  "prebuildify": "^5.0.1",
58
61
  "prettier": "^2.7.1",
59
62
  "rimraf": "^3.0.1",
63
+ "sinon": "^18.0.0",
64
+ "sinon-chai": "^3.7.0",
60
65
  "source-map-support": "^0.5.19",
61
66
  "typescript": "4.9.3"
62
67
  }
Binary file
Binary file
Binary file