@peers-app/peers-sdk 0.25.6 → 0.25.8

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.
@@ -0,0 +1,219 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const nacl = require("tweetnacl");
4
+ const utils_1 = require("../utils");
5
+ const frame_cipher_1 = require("./frame-cipher");
6
+ function randomKey() {
7
+ return nacl.randomBytes(32);
8
+ }
9
+ function derivationParams() {
10
+ return {
11
+ ephemeralSharedSecret: nacl.randomBytes(32),
12
+ staticSharedSecret: nacl.randomBytes(32),
13
+ connectionId: (0, utils_1.newid)(),
14
+ clientDeviceId: (0, utils_1.newid)(),
15
+ serverDeviceId: (0, utils_1.newid)(),
16
+ timestamp: Date.now(),
17
+ };
18
+ }
19
+ function innerFrame(type, payload) {
20
+ const frame = new Uint8Array(1 + payload.length);
21
+ frame[0] = type;
22
+ frame.set(payload, 1);
23
+ return frame;
24
+ }
25
+ describe("frame-cipher", () => {
26
+ describe("seal / open", () => {
27
+ it("round-trips an inner frame with exactly FRAME_CIPHER_OVERHEAD bytes added", () => {
28
+ const key = randomKey();
29
+ const connectionId = (0, utils_1.newid)();
30
+ const sealer = new frame_cipher_1.FrameSealer(key.slice(), connectionId);
31
+ const opener = new frame_cipher_1.FrameOpener(key.slice(), connectionId);
32
+ const inner = innerFrame(0x10, new Uint8Array([1, 2, 3, 4, 5]));
33
+ const sealed = sealer.seal(inner);
34
+ expect(sealed[0]).toBe(frame_cipher_1.FRAME_ENC);
35
+ expect(sealed.length).toBe(inner.length + frame_cipher_1.FRAME_CIPHER_OVERHEAD);
36
+ expect(Buffer.from(opener.open(sealed) ?? [])).toEqual(Buffer.from(inner));
37
+ });
38
+ it("round-trips an empty inner frame and a large inner frame", () => {
39
+ const key = randomKey();
40
+ const { sealer, opener } = (0, frame_cipher_1.createFrameCiphers)({ sendKey: key.slice(), receiveKey: key.slice() }, "conn");
41
+ const empty = new Uint8Array(0);
42
+ expect(opener.open(sealer.seal(empty))?.length).toBe(0);
43
+ const large = new Uint8Array(512 * 1024);
44
+ for (let i = 0; i < large.length; i++)
45
+ large[i] = i % 251;
46
+ const opened = opener.open(sealer.seal(large));
47
+ expect(opened).not.toBeNull();
48
+ expect(Buffer.from(opened)).toEqual(Buffer.from(large));
49
+ });
50
+ it("does not leak the inner frame bytes on the wire", () => {
51
+ const key = randomKey();
52
+ const sealer = new frame_cipher_1.FrameSealer(key, "conn");
53
+ const marker = Buffer.from("SECRET-MARKER-0123456789abcdef");
54
+ const sealed = Buffer.from(sealer.seal(innerFrame(0x00, marker)));
55
+ expect(sealed.indexOf(marker)).toBe(-1);
56
+ });
57
+ it("fails to open with the wrong key", () => {
58
+ const sealer = new frame_cipher_1.FrameSealer(randomKey(), "conn");
59
+ const opener = new frame_cipher_1.FrameOpener(randomKey(), "conn");
60
+ expect(opener.open(sealer.seal(innerFrame(0x00, new Uint8Array([9]))))).toBeNull();
61
+ });
62
+ it("fails to open with the wrong connectionId (AAD)", () => {
63
+ const key = randomKey();
64
+ const sealer = new frame_cipher_1.FrameSealer(key.slice(), "conn-a");
65
+ const opener = new frame_cipher_1.FrameOpener(key.slice(), "conn-b");
66
+ expect(opener.open(sealer.seal(innerFrame(0x00, new Uint8Array([9]))))).toBeNull();
67
+ });
68
+ it("fails to open a frame sealed for the other direction", () => {
69
+ const derived = (0, frame_cipher_1.deriveFrameKeys)(derivationParams());
70
+ const client = (0, frame_cipher_1.createFrameCiphers)((0, frame_cipher_1.frameKeysForRole)(derived, "client"), "conn");
71
+ const server = (0, frame_cipher_1.createFrameCiphers)((0, frame_cipher_1.frameKeysForRole)(derived, "server"), "conn");
72
+ const sealed = client.sealer.seal(innerFrame(0x00, new Uint8Array([1])));
73
+ // The client's own opener holds the server-to-client key: wrong direction.
74
+ expect(client.opener.open(sealed)).toBeNull();
75
+ // The server's opener holds the client-to-server key and is at counter 0.
76
+ expect(server.opener.open(sealed)).not.toBeNull();
77
+ });
78
+ it("fails to open when a ciphertext bit is flipped", () => {
79
+ const key = randomKey();
80
+ const sealer = new frame_cipher_1.FrameSealer(key.slice(), "conn");
81
+ const opener = new frame_cipher_1.FrameOpener(key.slice(), "conn");
82
+ const sealed = sealer.seal(innerFrame(0x00, new Uint8Array([1, 2, 3])));
83
+ sealed[2] ^= 0x01;
84
+ expect(opener.open(sealed)).toBeNull();
85
+ });
86
+ it("fails to open when the tag is truncated or the type byte is wrong", () => {
87
+ const key = randomKey();
88
+ const sealer = new frame_cipher_1.FrameSealer(key.slice(), "conn");
89
+ const sealed = sealer.seal(innerFrame(0x00, new Uint8Array([1, 2, 3])));
90
+ expect(new frame_cipher_1.FrameOpener(key.slice(), "conn").open(sealed.subarray(0, sealed.length - 1))).toBeNull();
91
+ expect(new frame_cipher_1.FrameOpener(key.slice(), "conn").open(new Uint8Array([frame_cipher_1.FRAME_ENC]))).toBeNull();
92
+ const wrongType = sealed.slice();
93
+ wrongType[0] = 0x00;
94
+ expect(new frame_cipher_1.FrameOpener(key.slice(), "conn").open(wrongType)).toBeNull();
95
+ });
96
+ it("fails to open a replayed frame because the receive counter has advanced", () => {
97
+ const key = randomKey();
98
+ const sealer = new frame_cipher_1.FrameSealer(key.slice(), "conn");
99
+ const opener = new frame_cipher_1.FrameOpener(key.slice(), "conn");
100
+ const sealed = sealer.seal(innerFrame(0x00, new Uint8Array([7])));
101
+ expect(opener.open(sealed)).not.toBeNull();
102
+ expect(opener.open(sealed)).toBeNull();
103
+ });
104
+ it("fails to open frames delivered out of order", () => {
105
+ const key = randomKey();
106
+ const sealer = new frame_cipher_1.FrameSealer(key.slice(), "conn");
107
+ const opener = new frame_cipher_1.FrameOpener(key.slice(), "conn");
108
+ sealer.seal(innerFrame(0x00, new Uint8Array([1]))); // frame 0, never delivered
109
+ const second = sealer.seal(innerFrame(0x00, new Uint8Array([2])));
110
+ expect(opener.open(second)).toBeNull();
111
+ });
112
+ it("advances counters independently per direction", () => {
113
+ const derived = (0, frame_cipher_1.deriveFrameKeys)(derivationParams());
114
+ const client = (0, frame_cipher_1.createFrameCiphers)((0, frame_cipher_1.frameKeysForRole)(derived, "client"), "conn");
115
+ const server = (0, frame_cipher_1.createFrameCiphers)((0, frame_cipher_1.frameKeysForRole)(derived, "server"), "conn");
116
+ for (let i = 0; i < 5; i++) {
117
+ const opened = server.opener.open(client.sealer.seal(innerFrame(0x00, new Uint8Array([i]))));
118
+ expect(opened?.[1]).toBe(i);
119
+ }
120
+ expect(client.sealer.count).toBe(5);
121
+ expect(server.opener.count).toBe(5);
122
+ expect(server.sealer.count).toBe(0);
123
+ expect(client.opener.count).toBe(0);
124
+ const back = client.opener.open(server.sealer.seal(innerFrame(0x00, new Uint8Array([42]))));
125
+ expect(back?.[1]).toBe(42);
126
+ expect(server.sealer.count).toBe(1);
127
+ expect(client.opener.count).toBe(1);
128
+ });
129
+ it("produces different ciphertext for identical plaintext on consecutive frames", () => {
130
+ const sealer = new frame_cipher_1.FrameSealer(randomKey(), "conn");
131
+ const inner = innerFrame(0x00, new Uint8Array([1, 2, 3, 4]));
132
+ const a = Buffer.from(sealer.seal(inner));
133
+ const b = Buffer.from(sealer.seal(inner));
134
+ expect(a.equals(b)).toBe(false);
135
+ });
136
+ it("rejects keys of the wrong length", () => {
137
+ expect(() => new frame_cipher_1.FrameSealer(new Uint8Array(16), "conn")).toThrow(/32 bytes/);
138
+ expect(() => new frame_cipher_1.FrameOpener(new Uint8Array(31), "conn")).toThrow(/32 bytes/);
139
+ });
140
+ });
141
+ describe("deriveFrameKeys", () => {
142
+ it("is symmetric: both peers derive identical directional keys", () => {
143
+ const params = derivationParams();
144
+ const a = (0, frame_cipher_1.deriveFrameKeys)({ ...params });
145
+ const b = (0, frame_cipher_1.deriveFrameKeys)({ ...params });
146
+ expect(Buffer.from(a.clientToServer)).toEqual(Buffer.from(b.clientToServer));
147
+ expect(Buffer.from(a.serverToClient)).toEqual(Buffer.from(b.serverToClient));
148
+ expect(Buffer.from(a.clientToServer).equals(Buffer.from(a.serverToClient))).toBe(false);
149
+ });
150
+ it("maps roles onto directions so client.send == server.receive", () => {
151
+ const derived = (0, frame_cipher_1.deriveFrameKeys)(derivationParams());
152
+ const client = (0, frame_cipher_1.frameKeysForRole)(derived, "client");
153
+ const server = (0, frame_cipher_1.frameKeysForRole)(derived, "server");
154
+ expect(Buffer.from(client.sendKey)).toEqual(Buffer.from(server.receiveKey));
155
+ expect(Buffer.from(client.receiveKey)).toEqual(Buffer.from(server.sendKey));
156
+ });
157
+ it("changes with every input", () => {
158
+ const base = derivationParams();
159
+ const reference = (0, frame_cipher_1.deriveFrameKeys)(base);
160
+ const variants = [
161
+ { ephemeralSharedSecret: nacl.randomBytes(32) },
162
+ { staticSharedSecret: nacl.randomBytes(32) },
163
+ { connectionId: (0, utils_1.newid)() },
164
+ { clientDeviceId: (0, utils_1.newid)() },
165
+ { serverDeviceId: (0, utils_1.newid)() },
166
+ { timestamp: base.timestamp + 1 },
167
+ ];
168
+ for (const variant of variants) {
169
+ const derived = (0, frame_cipher_1.deriveFrameKeys)({ ...base, ...variant });
170
+ expect(Buffer.from(derived.clientToServer).equals(Buffer.from(reference.clientToServer))).toBe(false);
171
+ expect(Buffer.from(derived.serverToClient).equals(Buffer.from(reference.serverToClient))).toBe(false);
172
+ }
173
+ });
174
+ it("distinguishes swapped device IDs", () => {
175
+ const base = derivationParams();
176
+ const a = (0, frame_cipher_1.deriveFrameKeys)(base);
177
+ const b = (0, frame_cipher_1.deriveFrameKeys)({
178
+ ...base,
179
+ clientDeviceId: base.serverDeviceId,
180
+ serverDeviceId: base.clientDeviceId,
181
+ });
182
+ expect(Buffer.from(a.clientToServer).equals(Buffer.from(b.clientToServer))).toBe(false);
183
+ });
184
+ it("rejects malformed inputs", () => {
185
+ const base = derivationParams();
186
+ expect(() => (0, frame_cipher_1.deriveFrameKeys)({ ...base, ephemeralSharedSecret: new Uint8Array(31) })).toThrow(/32-byte/);
187
+ expect(() => (0, frame_cipher_1.deriveFrameKeys)({ ...base, connectionId: "" })).toThrow(/connectionId/);
188
+ expect(() => (0, frame_cipher_1.deriveFrameKeys)({ ...base, timestamp: -1 })).toThrow(/timestamp/);
189
+ expect(() => (0, frame_cipher_1.deriveFrameKeys)({ ...base, timestamp: 1.5 })).toThrow(/timestamp/);
190
+ });
191
+ it("works end to end with real X25519 shared secrets", () => {
192
+ const clientEph = nacl.box.keyPair();
193
+ const serverEph = nacl.box.keyPair();
194
+ const clientStatic = nacl.box.keyPair();
195
+ const serverStatic = nacl.box.keyPair();
196
+ const common = {
197
+ connectionId: (0, utils_1.newid)(),
198
+ clientDeviceId: (0, utils_1.newid)(),
199
+ serverDeviceId: (0, utils_1.newid)(),
200
+ timestamp: Date.now(),
201
+ };
202
+ const clientKeys = (0, frame_cipher_1.frameKeysForRole)((0, frame_cipher_1.deriveFrameKeys)({
203
+ ...common,
204
+ ephemeralSharedSecret: nacl.scalarMult(clientEph.secretKey, serverEph.publicKey),
205
+ staticSharedSecret: nacl.scalarMult(clientStatic.secretKey, serverStatic.publicKey),
206
+ }), "client");
207
+ const serverKeys = (0, frame_cipher_1.frameKeysForRole)((0, frame_cipher_1.deriveFrameKeys)({
208
+ ...common,
209
+ ephemeralSharedSecret: nacl.scalarMult(serverEph.secretKey, clientEph.publicKey),
210
+ staticSharedSecret: nacl.scalarMult(serverStatic.secretKey, clientStatic.publicKey),
211
+ }), "server");
212
+ const client = (0, frame_cipher_1.createFrameCiphers)(clientKeys, common.connectionId);
213
+ const server = (0, frame_cipher_1.createFrameCiphers)(serverKeys, common.connectionId);
214
+ const inner = innerFrame(0x11, Buffer.from("hello over x25519"));
215
+ expect(Buffer.from(server.opener.open(client.sealer.seal(inner)) ?? [])).toEqual(Buffer.from(inner));
216
+ expect(Buffer.from(client.opener.open(server.sealer.seal(inner)) ?? [])).toEqual(Buffer.from(inner));
217
+ });
218
+ });
219
+ });
@@ -1,5 +1,23 @@
1
+ import type { FrameKeys } from "./frame-cipher";
2
+ /** Default chunk size for raw byte streaming. */
1
3
  export declare const DEFAULT_MAX_CHUNK_SIZE: number;
2
- export type RPCCallback = (error?: any, result?: any) => void;
4
+ /**
5
+ * Transport instructions attached to one RPC reply.
6
+ *
7
+ * Only `Connection`'s handshake handler uses this: the server must send its
8
+ * handshake response in the clear (the client cannot open a sealed frame until
9
+ * it has the server's ephemeral key, which is in that response) and seal
10
+ * everything after it. Threading the keys through the reply callback lets the
11
+ * socket arm the send cipher synchronously after that exact frame.
12
+ */
13
+ export interface RPCSendOptions {
14
+ /** Arm the outbound frame cipher with these keys right after this reply frame has been sent. */
15
+ armFrameCipherAfter?: FrameKeys;
16
+ }
17
+ /** Reply callback handed to RPC handlers. */
18
+ export type RPCCallback = (error?: any, result?: any, sendOptions?: RPCSendOptions) => void;
19
+ /** Which direction(s) of the frame cipher to arm. */
20
+ export type FrameCipherDirection = "both" | "send" | "receive";
3
21
  /**
4
22
  * Lightweight stats tracking for socket throughput.
5
23
  * Tracks bytes and messages sent/received with minimal overhead.
@@ -16,7 +34,9 @@ export interface ISocketStats {
16
34
  }
17
35
  /** Creates a new stats object for tracking socket throughput */
18
36
  export declare function createSocketStats(): ISocketStats;
37
+ /** Underlying transport family of a socket. */
19
38
  export type TransportType = "ws" | "wrtc" | "unknown";
39
+ /** Minimal RPC + raw-byte transport abstraction consumed by `Connection`. */
20
40
  export interface ISocket {
21
41
  id?: string;
22
42
  connected?: boolean;
@@ -59,7 +79,28 @@ export interface ISocket {
59
79
  * @param streamId - Stream identifier to stop listening on
60
80
  */
61
81
  removeRawBytesHandler?(streamId: string): void;
82
+ /**
83
+ * Arms the per-connection frame cipher (see `frame-cipher.ts`). Sockets that
84
+ * implement this seal every outbound frame and require every inbound frame to
85
+ * be sealed once the corresponding direction is armed. `Connection` only
86
+ * advertises `frameCrypto` support in its handshake when this is present.
87
+ * @param keys - This peer's send and receive keys
88
+ * @param direction - Defaults to `"both"`. The handshake server arms
89
+ * `"receive"` first and lets the reply's {@link RPCSendOptions} arm send.
90
+ */
91
+ armFrameCipher?(keys: FrameKeys, direction?: FrameCipherDirection): void;
92
+ /** True once both directions of the frame cipher are armed. */
93
+ readonly frameCipherArmed?: boolean;
94
+ /**
95
+ * Controls delivery of inbound plaintext `STREAM_*` frames. Sockets start
96
+ * permissive so bare transports keep working; `Connection` turns this off on
97
+ * construction and only turns it back on for a verified legacy peer. Sealed
98
+ * stream frames are always delivered because arming implies a completed
99
+ * handshake.
100
+ */
101
+ setPlaintextStreamsAllowed?(allowed: boolean): void;
62
102
  }
103
+ /** How much a remote device identity is trusted. Negative values are rejected. */
63
104
  export declare enum TrustLevel {
64
105
  Malicious = -20,
65
106
  Untrusted = -10,
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TrustLevel = exports.DEFAULT_MAX_CHUNK_SIZE = void 0;
4
4
  exports.createSocketStats = createSocketStats;
5
+ /** Default chunk size for raw byte streaming. */
5
6
  exports.DEFAULT_MAX_CHUNK_SIZE = 1024 * 1024; // 1MB
6
7
  /** Creates a new stats object for tracking socket throughput */
7
8
  function createSocketStats() {
@@ -17,6 +18,7 @@ function createSocketStats() {
17
18
  lastSampleBytesReceived: 0,
18
19
  };
19
20
  }
21
+ /** How much a remote device identity is trusted. Negative values are rejected. */
20
22
  var TrustLevel;
21
23
  (function (TrustLevel) {
22
24
  TrustLevel[TrustLevel["Malicious"] = -20] = "Malicious";
package/dist/index.d.ts CHANGED
@@ -9,6 +9,7 @@ export * from "./device/binary-peer-connection-v2";
9
9
  export * from "./device/connection";
10
10
  export * from "./device/device";
11
11
  export * from "./device/device-election";
12
+ export * from "./device/frame-cipher";
12
13
  export * from "./device/get-trust-level-fn";
13
14
  export * from "./device/socket.type";
14
15
  export * from "./device/socket-io-binary-peer";
package/dist/index.js CHANGED
@@ -30,6 +30,7 @@ __exportStar(require("./device/binary-peer-connection-v2"), exports);
30
30
  __exportStar(require("./device/connection"), exports);
31
31
  __exportStar(require("./device/device"), exports);
32
32
  __exportStar(require("./device/device-election"), exports);
33
+ __exportStar(require("./device/frame-cipher"), exports);
33
34
  __exportStar(require("./device/get-trust-level-fn"), exports);
34
35
  __exportStar(require("./device/socket.type"), exports);
35
36
  __exportStar(require("./device/socket-io-binary-peer"), exports);
package/dist/keys.d.ts CHANGED
@@ -82,6 +82,25 @@ export declare function openSignedObject<T>(signedObj: ISignedObject<T>): T;
82
82
  * @param toPublicBoxKey Recipient’s X25519 public key (base64url)
83
83
  */
84
84
  export declare function boxDataWithKeys(data: any, toPublicBoxKey: string, mySecretKey: string): IDataBox;
85
+ /**
86
+ * Raw X25519 shared secret between the box key derived from `myEd25519SecretKey` and
87
+ * `theirPublicBoxKey`. Used as key-agreement input (feed it to a KDF, never use it directly).
88
+ * @param myEd25519SecretKey Ed25519 secret key in the encoding produced by {@link newKeys}
89
+ * @param theirPublicBoxKey Peer's X25519 public key (base64url)
90
+ * @returns 32-byte shared secret; the caller should zeroize it when done
91
+ */
92
+ export declare function computeStaticSharedSecret(myEd25519SecretKey: string, theirPublicBoxKey: string): Uint8Array;
93
+ /** Fresh X25519 keypair for one connection's frame-key agreement. Raw bytes, not base64. */
94
+ export declare function newEphemeralBoxKeyPair(): {
95
+ publicKey: Uint8Array;
96
+ secretKey: Uint8Array;
97
+ };
98
+ /**
99
+ * Raw X25519 shared secret between a raw 32-byte secret key and a base64url public key.
100
+ * Used for the ephemeral half of frame-key agreement; feed the result to a KDF.
101
+ * @returns 32-byte shared secret; the caller should zeroize it when done
102
+ */
103
+ export declare function computeEphemeralSharedSecret(mySecretKey: Uint8Array, theirPublicKey: string): Uint8Array;
85
104
  /** Narrowing guard: value looks like an {@link IDataBox} envelope. */
86
105
  export declare function isBoxedData(data: any): boolean;
87
106
  /**
package/dist/keys.js CHANGED
@@ -16,6 +16,9 @@ exports.openMessageWithPublicKey = openMessageWithPublicKey;
16
16
  exports.signObjectWithSecretKey = signObjectWithSecretKey;
17
17
  exports.openSignedObject = openSignedObject;
18
18
  exports.boxDataWithKeys = boxDataWithKeys;
19
+ exports.computeStaticSharedSecret = computeStaticSharedSecret;
20
+ exports.newEphemeralBoxKeyPair = newEphemeralBoxKeyPair;
21
+ exports.computeEphemeralSharedSecret = computeEphemeralSharedSecret;
19
22
  exports.isBoxedData = isBoxedData;
20
23
  exports.openBoxWithSecretKey = openBoxWithSecretKey;
21
24
  exports.encryptData = encryptData;
@@ -242,6 +245,31 @@ function boxDataWithKeys(data, toPublicBoxKey, mySecretKey) {
242
245
  fromPublicKey: encodeBase64(boxKeyPair.publicKey),
243
246
  };
244
247
  }
248
+ /**
249
+ * Raw X25519 shared secret between the box key derived from `myEd25519SecretKey` and
250
+ * `theirPublicBoxKey`. Used as key-agreement input (feed it to a KDF, never use it directly).
251
+ * @param myEd25519SecretKey Ed25519 secret key in the encoding produced by {@link newKeys}
252
+ * @param theirPublicBoxKey Peer's X25519 public key (base64url)
253
+ * @returns 32-byte shared secret; the caller should zeroize it when done
254
+ */
255
+ function computeStaticSharedSecret(myEd25519SecretKey, theirPublicBoxKey) {
256
+ const curveSecret = ed2curve.convertSecretKey(decodeBase64(myEd25519SecretKey));
257
+ const shared = nacl.scalarMult(curveSecret, decodeBase64(theirPublicBoxKey));
258
+ curveSecret.fill(0);
259
+ return shared;
260
+ }
261
+ /** Fresh X25519 keypair for one connection's frame-key agreement. Raw bytes, not base64. */
262
+ function newEphemeralBoxKeyPair() {
263
+ return nacl.box.keyPair();
264
+ }
265
+ /**
266
+ * Raw X25519 shared secret between a raw 32-byte secret key and a base64url public key.
267
+ * Used for the ephemeral half of frame-key agreement; feed the result to a KDF.
268
+ * @returns 32-byte shared secret; the caller should zeroize it when done
269
+ */
270
+ function computeEphemeralSharedSecret(mySecretKey, theirPublicKey) {
271
+ return nacl.scalarMult(mySecretKey, decodeBase64(theirPublicKey));
272
+ }
245
273
  /** Narrowing guard: value looks like an {@link IDataBox} envelope. */
246
274
  function isBoxedData(data) {
247
275
  return (typeof data === "object" &&
@@ -41,6 +41,8 @@ export interface IConnectedDeviceSummary {
41
41
  connectionAddress?: string;
42
42
  trustLevel: number;
43
43
  verified: boolean;
44
+ /** True when every frame on the connection is sealed by the per-connection frame cipher. */
45
+ frameCipherArmed?: boolean;
44
46
  }
45
47
  /** Filters and bounds for one remote System Logs query. */
46
48
  export interface IRemoteLogsQueryInput {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peers-app/peers-sdk",
3
- "version": "0.25.6",
3
+ "version": "0.25.8",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/peers-app/peers-sdk.git"
@@ -35,6 +35,7 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "@msgpack/msgpack": "^3.1.2",
38
+ "@noble/ciphers": "^1.3.0",
38
39
  "@noble/hashes": "^1.8.0",
39
40
  "buffer": "^6.0.3",
40
41
  "ed2curve": "^0.3.0",