react-native-ble-mesh 1.1.1 → 2.1.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.
Files changed (80) hide show
  1. package/README.md +288 -172
  2. package/docs/IOS-BACKGROUND-BLE.md +231 -0
  3. package/docs/OPTIMIZATION.md +183 -0
  4. package/docs/SPEC-v2.1.md +308 -0
  5. package/package.json +1 -1
  6. package/src/MeshNetwork.js +667 -465
  7. package/src/constants/index.js +1 -0
  8. package/src/crypto/AutoCrypto.js +90 -0
  9. package/src/crypto/CryptoProvider.js +99 -0
  10. package/src/crypto/index.js +15 -63
  11. package/src/crypto/providers/ExpoCryptoProvider.js +126 -0
  12. package/src/crypto/providers/QuickCryptoProvider.js +158 -0
  13. package/src/crypto/providers/TweetNaClProvider.js +124 -0
  14. package/src/crypto/providers/index.js +11 -0
  15. package/src/errors/MeshError.js +2 -1
  16. package/src/expo/withBLEMesh.js +102 -0
  17. package/src/hooks/AppStateManager.js +9 -1
  18. package/src/hooks/useMesh.js +47 -13
  19. package/src/hooks/useMessages.js +6 -4
  20. package/src/hooks/usePeers.js +13 -9
  21. package/src/index.js +23 -8
  22. package/src/mesh/dedup/BloomFilter.js +44 -57
  23. package/src/mesh/dedup/DedupManager.js +67 -10
  24. package/src/mesh/fragment/Assembler.js +5 -0
  25. package/src/mesh/fragment/Fragmenter.js +1 -1
  26. package/src/mesh/index.js +1 -1
  27. package/src/mesh/monitor/ConnectionQuality.js +433 -0
  28. package/src/mesh/monitor/NetworkMonitor.js +376 -320
  29. package/src/mesh/monitor/index.js +7 -3
  30. package/src/mesh/peer/Peer.js +5 -2
  31. package/src/mesh/peer/PeerManager.js +21 -4
  32. package/src/mesh/router/MessageRouter.js +38 -19
  33. package/src/mesh/router/RouteTable.js +24 -8
  34. package/src/mesh/store/StoreAndForwardManager.js +305 -296
  35. package/src/mesh/store/index.js +1 -1
  36. package/src/protocol/deserializer.js +9 -10
  37. package/src/protocol/header.js +13 -7
  38. package/src/protocol/message.js +15 -3
  39. package/src/protocol/serializer.js +7 -10
  40. package/src/protocol/validator.js +23 -5
  41. package/src/service/BatteryOptimizer.js +285 -278
  42. package/src/service/EmergencyManager.js +224 -214
  43. package/src/service/HandshakeManager.js +163 -13
  44. package/src/service/MeshService.js +72 -6
  45. package/src/service/SessionManager.js +79 -2
  46. package/src/service/audio/AudioManager.js +8 -2
  47. package/src/service/file/FileAssembler.js +106 -0
  48. package/src/service/file/FileChunker.js +79 -0
  49. package/src/service/file/FileManager.js +307 -0
  50. package/src/service/file/FileMessage.js +122 -0
  51. package/src/service/file/index.js +15 -0
  52. package/src/service/text/TextManager.js +21 -15
  53. package/src/service/text/broadcast/BroadcastManager.js +16 -0
  54. package/src/storage/MessageStore.js +55 -2
  55. package/src/transport/BLETransport.js +141 -10
  56. package/src/transport/MockTransport.js +1 -1
  57. package/src/transport/MultiTransport.js +330 -0
  58. package/src/transport/WiFiDirectTransport.js +296 -0
  59. package/src/transport/adapters/NodeBLEAdapter.js +34 -0
  60. package/src/transport/adapters/RNBLEAdapter.js +56 -1
  61. package/src/transport/index.js +6 -0
  62. package/src/utils/EventEmitter.js +6 -9
  63. package/src/utils/bytes.js +12 -10
  64. package/src/utils/compression.js +293 -291
  65. package/src/utils/encoding.js +33 -8
  66. package/src/crypto/aead.js +0 -189
  67. package/src/crypto/chacha20.js +0 -181
  68. package/src/crypto/hkdf.js +0 -187
  69. package/src/crypto/hmac.js +0 -143
  70. package/src/crypto/keys/KeyManager.js +0 -271
  71. package/src/crypto/keys/KeyPair.js +0 -216
  72. package/src/crypto/keys/SecureStorage.js +0 -219
  73. package/src/crypto/keys/index.js +0 -32
  74. package/src/crypto/noise/handshake.js +0 -410
  75. package/src/crypto/noise/index.js +0 -27
  76. package/src/crypto/noise/session.js +0 -253
  77. package/src/crypto/noise/state.js +0 -268
  78. package/src/crypto/poly1305.js +0 -113
  79. package/src/crypto/sha256.js +0 -240
  80. package/src/crypto/x25519.js +0 -154
@@ -1,219 +0,0 @@
1
- 'use strict';
2
-
3
- /**
4
- * SecureStorage - Abstract storage interface for sensitive key material.
5
- * Implementations should use platform-specific secure storage mechanisms.
6
- * @module crypto/keys/SecureStorage
7
- */
8
-
9
- /**
10
- * SecureStorage defines the interface for secure key storage.
11
- * This is an abstract class - use platform-specific implementations.
12
- *
13
- * Platform implementations:
14
- * - React Native: Use react-native-keychain or expo-secure-store
15
- * - Node.js: Use encrypted file storage or keytar
16
- * - Browser: Use IndexedDB with encryption
17
- *
18
- * @abstract
19
- * @class
20
- */
21
- class SecureStorage {
22
- /**
23
- * Stores a value securely.
24
- * @param {string} key - Storage key
25
- * @param {string} value - Value to store (should be serialized JSON)
26
- * @returns {Promise<void>}
27
- * @abstract
28
- */
29
- async set(_key, _value) {
30
- throw new Error('SecureStorage.set() must be implemented');
31
- }
32
-
33
- /**
34
- * Retrieves a stored value.
35
- * @param {string} key - Storage key
36
- * @returns {Promise<string|null>} Stored value or null if not found
37
- * @abstract
38
- */
39
- async get(_key) {
40
- throw new Error('SecureStorage.get() must be implemented');
41
- }
42
-
43
- /**
44
- * Deletes a stored value.
45
- * @param {string} key - Storage key
46
- * @returns {Promise<void>}
47
- * @abstract
48
- */
49
- async delete(_key) {
50
- throw new Error('SecureStorage.delete() must be implemented');
51
- }
52
-
53
- /**
54
- * Checks if a key exists in storage.
55
- * @param {string} key - Storage key
56
- * @returns {Promise<boolean>} True if key exists
57
- */
58
- async has(key) {
59
- const value = await this.get(key);
60
- return value !== null && value !== undefined;
61
- }
62
-
63
- /**
64
- * Clears all stored values.
65
- * @returns {Promise<void>}
66
- * @abstract
67
- */
68
- async clear() {
69
- throw new Error('SecureStorage.clear() must be implemented');
70
- }
71
- }
72
-
73
- /**
74
- * MemorySecureStorage - In-memory implementation for testing.
75
- * WARNING: Not secure for production use - keys are not persisted
76
- * and are stored in plain memory.
77
- *
78
- * @class
79
- * @extends SecureStorage
80
- */
81
- class MemorySecureStorage extends SecureStorage {
82
- constructor() {
83
- super();
84
- /** @type {Map<string, string>} */
85
- this._store = new Map();
86
- }
87
-
88
- /**
89
- * Stores a value in memory.
90
- * @param {string} key - Storage key
91
- * @param {string} value - Value to store
92
- * @returns {Promise<void>}
93
- */
94
- async set(key, value) {
95
- if (typeof key !== 'string') {
96
- throw new Error('Key must be a string');
97
- }
98
- if (typeof value !== 'string') {
99
- throw new Error('Value must be a string');
100
- }
101
- this._store.set(key, value);
102
- }
103
-
104
- /**
105
- * Retrieves a value from memory.
106
- * @param {string} key - Storage key
107
- * @returns {Promise<string|null>} Stored value or null
108
- */
109
- async get(key) {
110
- if (typeof key !== 'string') {
111
- throw new Error('Key must be a string');
112
- }
113
- return this._store.get(key) || null;
114
- }
115
-
116
- /**
117
- * Deletes a value from memory.
118
- * @param {string} key - Storage key
119
- * @returns {Promise<void>}
120
- */
121
- async delete(key) {
122
- if (typeof key !== 'string') {
123
- throw new Error('Key must be a string');
124
- }
125
- this._store.delete(key);
126
- }
127
-
128
- /**
129
- * Clears all stored values.
130
- * @returns {Promise<void>}
131
- */
132
- async clear() {
133
- this._store.clear();
134
- }
135
-
136
- /**
137
- * Gets the number of stored items.
138
- * @returns {number} Number of items
139
- */
140
- get size() {
141
- return this._store.size;
142
- }
143
- }
144
-
145
- /**
146
- * Creates a SecureStorage adapter for React Native AsyncStorage.
147
- * Note: AsyncStorage is NOT secure - consider using expo-secure-store
148
- * or react-native-keychain for production.
149
- *
150
- * @param {object} asyncStorage - AsyncStorage instance
151
- * @returns {SecureStorage} Storage adapter
152
- *
153
- * @example
154
- * import AsyncStorage from '@react-native-async-storage/async-storage';
155
- * const storage = createAsyncStorageAdapter(AsyncStorage);
156
- */
157
- function createAsyncStorageAdapter(asyncStorage) {
158
- return {
159
- async set(key, value) {
160
- await asyncStorage.setItem(key, value);
161
- },
162
- async get(key) {
163
- return await asyncStorage.getItem(key);
164
- },
165
- async delete(key) {
166
- await asyncStorage.removeItem(key);
167
- },
168
- async has(key) {
169
- const value = await asyncStorage.getItem(key);
170
- return value !== null;
171
- },
172
- async clear() {
173
- // Only clear mesh-related keys
174
- const keys = await asyncStorage.getAllKeys();
175
- const meshKeys = keys.filter(k => k.startsWith('mesh_'));
176
- await asyncStorage.multiRemove(meshKeys);
177
- }
178
- };
179
- }
180
-
181
- /**
182
- * Creates a SecureStorage adapter for expo-secure-store.
183
- * This provides actual secure storage on iOS/Android.
184
- *
185
- * @param {object} secureStore - SecureStore module from expo-secure-store
186
- * @returns {SecureStorage} Storage adapter
187
- *
188
- * @example
189
- * import * as SecureStore from 'expo-secure-store';
190
- * const storage = createExpoSecureStoreAdapter(SecureStore);
191
- */
192
- function createExpoSecureStoreAdapter(secureStore) {
193
- return {
194
- async set(key, value) {
195
- await secureStore.setItemAsync(key, value);
196
- },
197
- async get(key) {
198
- return await secureStore.getItemAsync(key);
199
- },
200
- async delete(key) {
201
- await secureStore.deleteItemAsync(key);
202
- },
203
- async has(key) {
204
- const value = await secureStore.getItemAsync(key);
205
- return value !== null;
206
- },
207
- async clear() {
208
- // expo-secure-store doesn't have getAllKeys, so we track known keys
209
- console.warn('SecureStore clear() requires manual key tracking');
210
- }
211
- };
212
- }
213
-
214
- module.exports = {
215
- SecureStorage,
216
- MemorySecureStorage,
217
- createAsyncStorageAdapter,
218
- createExpoSecureStoreAdapter
219
- };
@@ -1,32 +0,0 @@
1
- 'use strict';
2
-
3
- /**
4
- * Keys Module
5
- * Re-exports all key management components.
6
- * @module crypto/keys
7
- */
8
-
9
- const { KeyPair, KEY_SIZE } = require('./KeyPair');
10
- const { KeyManager, DEFAULT_IDENTITY_KEY } = require('./KeyManager');
11
- const {
12
- SecureStorage,
13
- MemorySecureStorage,
14
- createAsyncStorageAdapter,
15
- createExpoSecureStoreAdapter
16
- } = require('./SecureStorage');
17
-
18
- module.exports = {
19
- // KeyPair
20
- KeyPair,
21
- KEY_SIZE,
22
-
23
- // KeyManager
24
- KeyManager,
25
- DEFAULT_IDENTITY_KEY,
26
-
27
- // SecureStorage
28
- SecureStorage,
29
- MemorySecureStorage,
30
- createAsyncStorageAdapter,
31
- createExpoSecureStoreAdapter
32
- };
@@ -1,410 +0,0 @@
1
- 'use strict';
2
-
3
- /**
4
- * Noise Protocol XX Handshake Implementation
5
- *
6
- * XX Pattern (mutual authentication with transmitted static keys):
7
- * -> e (initiator sends ephemeral public key)
8
- * <- e, ee, s, es (responder: ephemeral, DH, encrypted static)
9
- * -> s, se (initiator: encrypted static, final DH)
10
- *
11
- * @module crypto/noise/handshake
12
- */
13
-
14
- const { SymmetricState, PROTOCOL_NAME } = require('./state');
15
- const { generateKeyPair, scalarMult } = require('../x25519');
16
- const { concat } = require('../../utils/bytes');
17
-
18
- /**
19
- * Handshake state machine states
20
- * @enum {string}
21
- */
22
- const HandshakeState = {
23
- INITIAL: 'INITIAL',
24
- MSG1_WRITTEN: 'MSG1_WRITTEN',
25
- MSG1_READ: 'MSG1_READ',
26
- MSG2_WRITTEN: 'MSG2_WRITTEN',
27
- MSG2_READ: 'MSG2_READ',
28
- MSG3_WRITTEN: 'MSG3_WRITTEN',
29
- MSG3_READ: 'MSG3_READ',
30
- COMPLETE: 'COMPLETE',
31
- ERROR: 'ERROR'
32
- };
33
-
34
- /**
35
- * Role in the handshake
36
- * @enum {string}
37
- */
38
- const Role = {
39
- INITIATOR: 'INITIATOR',
40
- RESPONDER: 'RESPONDER'
41
- };
42
-
43
- /**
44
- * Public key size in bytes
45
- * @constant {number}
46
- */
47
- const PUBLIC_KEY_SIZE = 32;
48
-
49
- /**
50
- * AEAD tag size in bytes
51
- * @constant {number}
52
- */
53
- const TAG_SIZE = 16;
54
-
55
- /**
56
- * NoiseHandshake implements the XX handshake pattern.
57
- * @class
58
- */
59
- class NoiseHandshake {
60
- constructor() {
61
- /** @type {SymmetricState|null} */
62
- this._symmetricState = null;
63
-
64
- /** @type {string} */
65
- this._state = HandshakeState.INITIAL;
66
-
67
- /** @type {string|null} */
68
- this._role = null;
69
-
70
- /** @type {{publicKey: Uint8Array, secretKey: Uint8Array}|null} */
71
- this._staticKeyPair = null;
72
-
73
- /** @type {{publicKey: Uint8Array, secretKey: Uint8Array}|null} */
74
- this._ephemeralKeyPair = null;
75
-
76
- /** @type {Uint8Array|null} */
77
- this._remoteStaticPublicKey = null;
78
-
79
- /** @type {Uint8Array|null} */
80
- this._remoteEphemeralPublicKey = null;
81
-
82
- /** @type {{sendKey: Uint8Array, receiveKey: Uint8Array}|null} */
83
- this._transportKeys = null;
84
- }
85
-
86
- /**
87
- * Initializes the handshake as the initiator.
88
- * @param {{publicKey: Uint8Array, secretKey: Uint8Array}} staticKeyPair
89
- */
90
- initializeInitiator(staticKeyPair) {
91
- if (this._role !== null) {
92
- throw new Error('Invalid state: handshake already initialized');
93
- }
94
- this._validateState(HandshakeState.INITIAL, 'initializeInitiator');
95
- this._validateKeyPair(staticKeyPair, 'static');
96
-
97
- this._role = Role.INITIATOR;
98
- this._staticKeyPair = staticKeyPair;
99
- this._symmetricState = new SymmetricState(PROTOCOL_NAME);
100
-
101
- // Prologue can be empty for basic use
102
- this._symmetricState.mixHash(new Uint8Array(0));
103
- }
104
-
105
- /**
106
- * Initializes the handshake as the responder.
107
- * @param {{publicKey: Uint8Array, secretKey: Uint8Array}} staticKeyPair
108
- */
109
- initializeResponder(staticKeyPair) {
110
- if (this._role !== null) {
111
- throw new Error('Invalid state: handshake already initialized');
112
- }
113
- this._validateState(HandshakeState.INITIAL, 'initializeResponder');
114
- this._validateKeyPair(staticKeyPair, 'static');
115
-
116
- this._role = Role.RESPONDER;
117
- this._staticKeyPair = staticKeyPair;
118
- this._symmetricState = new SymmetricState(PROTOCOL_NAME);
119
-
120
- // Prologue can be empty for basic use
121
- this._symmetricState.mixHash(new Uint8Array(0));
122
- }
123
-
124
- /**
125
- * Writes message 1: -> e
126
- * Initiator sends ephemeral public key.
127
- * @returns {Uint8Array} Message 1 data
128
- */
129
- writeMessage1() {
130
- this._validateRole(Role.INITIATOR, 'writeMessage1');
131
- this._validateState(HandshakeState.INITIAL, 'writeMessage1');
132
-
133
- // Generate ephemeral key pair
134
- this._ephemeralKeyPair = generateKeyPair();
135
-
136
- // e: Mix ephemeral public key into hash
137
- this._symmetricState.mixHash(this._ephemeralKeyPair.publicKey);
138
-
139
- this._state = HandshakeState.MSG1_WRITTEN;
140
- return new Uint8Array(this._ephemeralKeyPair.publicKey);
141
- }
142
-
143
- /**
144
- * Reads message 1: -> e
145
- * Responder receives initiator's ephemeral public key.
146
- * @param {Uint8Array} data - Message 1 data
147
- */
148
- readMessage1(data) {
149
- this._validateRole(Role.RESPONDER, 'readMessage1');
150
- this._validateState(HandshakeState.INITIAL, 'readMessage1');
151
-
152
- if (data.length < PUBLIC_KEY_SIZE) {
153
- throw new Error('Message 1 too short');
154
- }
155
-
156
- // Extract remote ephemeral public key
157
- this._remoteEphemeralPublicKey = data.subarray(0, PUBLIC_KEY_SIZE);
158
-
159
- // e: Mix remote ephemeral into hash
160
- this._symmetricState.mixHash(this._remoteEphemeralPublicKey);
161
-
162
- this._state = HandshakeState.MSG1_READ;
163
- }
164
-
165
- /**
166
- * Writes message 2: <- e, ee, s, es
167
- * Responder sends ephemeral, performs DH, sends encrypted static.
168
- * @returns {Uint8Array} Message 2 data
169
- */
170
- writeMessage2() {
171
- this._validateRole(Role.RESPONDER, 'writeMessage2');
172
- this._validateState(HandshakeState.MSG1_READ, 'writeMessage2');
173
-
174
- // Generate ephemeral key pair
175
- this._ephemeralKeyPair = generateKeyPair();
176
-
177
- // e: Mix our ephemeral public key into hash
178
- this._symmetricState.mixHash(this._ephemeralKeyPair.publicKey);
179
-
180
- // ee: DH(ephemeral, remoteEphemeral)
181
- const ee = scalarMult(
182
- this._ephemeralKeyPair.secretKey,
183
- this._remoteEphemeralPublicKey
184
- );
185
- this._symmetricState.mixKey(ee);
186
-
187
- // s: Encrypt and send static public key
188
- const encryptedStatic = this._symmetricState.encryptAndHash(
189
- this._staticKeyPair.publicKey
190
- );
191
-
192
- // es: DH(ephemeral, remoteStatic) - but we dont have it yet in XX
193
- // Actually in XX responder pattern: es = DH(s, re)
194
- const es = scalarMult(
195
- this._staticKeyPair.secretKey,
196
- this._remoteEphemeralPublicKey
197
- );
198
- this._symmetricState.mixKey(es);
199
-
200
- // Combine: e || encrypted_s
201
- const message = concat(this._ephemeralKeyPair.publicKey, encryptedStatic);
202
-
203
- this._state = HandshakeState.MSG2_WRITTEN;
204
- return message;
205
- }
206
-
207
- /**
208
- * Reads message 2: <- e, ee, s, es
209
- * Initiator receives and processes responder's message 2.
210
- * @param {Uint8Array} data - Message 2 data
211
- */
212
- readMessage2(data) {
213
- this._validateRole(Role.INITIATOR, 'readMessage2');
214
- this._validateState(HandshakeState.MSG1_WRITTEN, 'readMessage2');
215
-
216
- const expectedSize = PUBLIC_KEY_SIZE + PUBLIC_KEY_SIZE + TAG_SIZE;
217
- if (data.length < expectedSize) {
218
- throw new Error('Message 2 too short');
219
- }
220
-
221
- // e: Extract and mix remote ephemeral
222
- this._remoteEphemeralPublicKey = data.subarray(0, PUBLIC_KEY_SIZE);
223
- this._symmetricState.mixHash(this._remoteEphemeralPublicKey);
224
-
225
- // ee: DH(ephemeral, remoteEphemeral)
226
- const ee = scalarMult(
227
- this._ephemeralKeyPair.secretKey,
228
- this._remoteEphemeralPublicKey
229
- );
230
- this._symmetricState.mixKey(ee);
231
-
232
- // s: Decrypt remote static public key
233
- const encryptedStatic = data.subarray(
234
- PUBLIC_KEY_SIZE,
235
- PUBLIC_KEY_SIZE + PUBLIC_KEY_SIZE + TAG_SIZE
236
- );
237
- this._remoteStaticPublicKey = this._symmetricState.decryptAndHash(
238
- encryptedStatic
239
- );
240
-
241
- // es: DH(e, rs)
242
- const es = scalarMult(
243
- this._ephemeralKeyPair.secretKey,
244
- this._remoteStaticPublicKey
245
- );
246
- this._symmetricState.mixKey(es);
247
-
248
- this._state = HandshakeState.MSG2_READ;
249
- }
250
-
251
- /**
252
- * Writes message 3: -> s, se
253
- * Initiator sends encrypted static and performs final DH.
254
- * @returns {Uint8Array} Message 3 data
255
- */
256
- writeMessage3() {
257
- this._validateRole(Role.INITIATOR, 'writeMessage3');
258
- this._validateState(HandshakeState.MSG2_READ, 'writeMessage3');
259
-
260
- // s: Encrypt and send static public key
261
- const encryptedStatic = this._symmetricState.encryptAndHash(
262
- this._staticKeyPair.publicKey
263
- );
264
-
265
- // se: DH(s, re)
266
- const se = scalarMult(
267
- this._staticKeyPair.secretKey,
268
- this._remoteEphemeralPublicKey
269
- );
270
- this._symmetricState.mixKey(se);
271
-
272
- // Split to get transport keys
273
- const { sendKey, receiveKey } = this._symmetricState.split();
274
- this._transportKeys = { sendKey, receiveKey };
275
-
276
- this._state = HandshakeState.MSG3_WRITTEN;
277
- return encryptedStatic;
278
- }
279
-
280
- /**
281
- * Reads message 3: -> s, se
282
- * Responder receives and processes initiator's message 3.
283
- * @param {Uint8Array} data - Message 3 data
284
- */
285
- readMessage3(data) {
286
- this._validateRole(Role.RESPONDER, 'readMessage3');
287
- this._validateState(HandshakeState.MSG2_WRITTEN, 'readMessage3');
288
-
289
- const expectedSize = PUBLIC_KEY_SIZE + TAG_SIZE;
290
- if (data.length < expectedSize) {
291
- throw new Error('Message 3 too short');
292
- }
293
-
294
- // s: Decrypt remote static public key
295
- this._remoteStaticPublicKey = this._symmetricState.decryptAndHash(data);
296
-
297
- // se: DH(e, rs)
298
- const se = scalarMult(
299
- this._ephemeralKeyPair.secretKey,
300
- this._remoteStaticPublicKey
301
- );
302
- this._symmetricState.mixKey(se);
303
-
304
- // Split to get transport keys (reversed for responder)
305
- const { sendKey, receiveKey } = this._symmetricState.split();
306
- this._transportKeys = { sendKey: receiveKey, receiveKey: sendKey };
307
-
308
- this._state = HandshakeState.MSG3_READ;
309
- }
310
-
311
- /**
312
- * Checks if the handshake is complete.
313
- * @returns {boolean} True if handshake is complete
314
- */
315
- isComplete() {
316
- return this._state === HandshakeState.MSG3_WRITTEN ||
317
- this._state === HandshakeState.MSG3_READ;
318
- }
319
-
320
- /**
321
- * Gets the NoiseSession for transport encryption.
322
- * @returns {NoiseSession} Transport session
323
- * @throws {Error} If handshake is not complete
324
- */
325
- getSession() {
326
- if (!this.isComplete()) {
327
- throw new Error('Handshake not complete');
328
- }
329
-
330
- const { NoiseSession } = require('./session');
331
- return new NoiseSession(
332
- this._transportKeys.sendKey,
333
- this._transportKeys.receiveKey,
334
- this._role === Role.INITIATOR
335
- );
336
- }
337
-
338
- /**
339
- * Gets the remote peer's static public key.
340
- * @returns {Uint8Array|null} Remote static public key or null
341
- */
342
- getRemotePublicKey() {
343
- return this._remoteStaticPublicKey
344
- ? new Uint8Array(this._remoteStaticPublicKey)
345
- : null;
346
- }
347
-
348
- /**
349
- * Gets the current handshake hash (channel binding).
350
- * @returns {Uint8Array} Handshake hash
351
- */
352
- getHandshakeHash() {
353
- if (!this._symmetricState) {
354
- throw new Error('Handshake not initialized');
355
- }
356
- return this._symmetricState.getHandshakeHash();
357
- }
358
-
359
- /**
360
- * Validates that the current state matches expected.
361
- * @param {string} expected - Expected state
362
- * @param {string} operation - Operation name for error message
363
- * @private
364
- */
365
- _validateState(expected, operation) {
366
- if (this._state !== expected) {
367
- throw new Error(
368
- `Invalid state for ${operation}: expected ${expected}, got ${this._state}`
369
- );
370
- }
371
- }
372
-
373
- /**
374
- * Validates that the role matches expected.
375
- * @param {string} expected - Expected role
376
- * @param {string} operation - Operation name for error message
377
- * @private
378
- */
379
- _validateRole(expected, operation) {
380
- if (this._role !== expected) {
381
- throw new Error(
382
- `Invalid role for ${operation}: expected ${expected}, got ${this._role}`
383
- );
384
- }
385
- }
386
-
387
- /**
388
- * Validates a key pair.
389
- * @param {object} keyPair - Key pair to validate
390
- * @param {string} name - Name for error message
391
- * @private
392
- */
393
- _validateKeyPair(keyPair, name) {
394
- if (!keyPair || !keyPair.publicKey || !keyPair.secretKey) {
395
- throw new Error(`Invalid ${name} key pair`);
396
- }
397
- if (keyPair.publicKey.length !== PUBLIC_KEY_SIZE) {
398
- throw new Error(`${name} public key must be ${PUBLIC_KEY_SIZE} bytes`);
399
- }
400
- if (keyPair.secretKey.length !== PUBLIC_KEY_SIZE) {
401
- throw new Error(`${name} secret key must be ${PUBLIC_KEY_SIZE} bytes`);
402
- }
403
- }
404
- }
405
-
406
- module.exports = {
407
- NoiseHandshake,
408
- HandshakeState,
409
- Role
410
- };
@@ -1,27 +0,0 @@
1
- 'use strict';
2
-
3
- /**
4
- * Noise Protocol Module
5
- * Re-exports all Noise Protocol components.
6
- * @module crypto/noise
7
- */
8
-
9
- const { SymmetricState, PROTOCOL_NAME } = require('./state');
10
- const { NoiseHandshake, HandshakeState, Role } = require('./handshake');
11
- const { NoiseSession, MAX_NONCE, REKEY_THRESHOLD } = require('./session');
12
-
13
- module.exports = {
14
- // State management
15
- SymmetricState,
16
- PROTOCOL_NAME,
17
-
18
- // Handshake
19
- NoiseHandshake,
20
- HandshakeState,
21
- Role,
22
-
23
- // Transport session
24
- NoiseSession,
25
- MAX_NONCE,
26
- REKEY_THRESHOLD
27
- };