react-native-ble-mesh 1.1.1 → 2.0.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 (65) hide show
  1. package/README.md +288 -172
  2. package/docs/IOS-BACKGROUND-BLE.md +231 -0
  3. package/docs/OPTIMIZATION.md +70 -0
  4. package/docs/SPEC-v2.1.md +308 -0
  5. package/package.json +1 -1
  6. package/src/MeshNetwork.js +659 -465
  7. package/src/constants/index.js +1 -0
  8. package/src/crypto/AutoCrypto.js +79 -0
  9. package/src/crypto/CryptoProvider.js +99 -0
  10. package/src/crypto/index.js +15 -63
  11. package/src/crypto/providers/ExpoCryptoProvider.js +125 -0
  12. package/src/crypto/providers/QuickCryptoProvider.js +134 -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/useMesh.js +30 -9
  18. package/src/hooks/useMessages.js +2 -0
  19. package/src/index.js +23 -8
  20. package/src/mesh/dedup/DedupManager.js +36 -10
  21. package/src/mesh/fragment/Assembler.js +5 -0
  22. package/src/mesh/index.js +1 -1
  23. package/src/mesh/monitor/ConnectionQuality.js +408 -0
  24. package/src/mesh/monitor/NetworkMonitor.js +327 -316
  25. package/src/mesh/monitor/index.js +7 -3
  26. package/src/mesh/peer/PeerManager.js +6 -1
  27. package/src/mesh/router/MessageRouter.js +26 -15
  28. package/src/mesh/router/RouteTable.js +7 -1
  29. package/src/mesh/store/StoreAndForwardManager.js +295 -297
  30. package/src/mesh/store/index.js +1 -1
  31. package/src/service/BatteryOptimizer.js +282 -278
  32. package/src/service/EmergencyManager.js +224 -214
  33. package/src/service/HandshakeManager.js +167 -13
  34. package/src/service/MeshService.js +72 -6
  35. package/src/service/SessionManager.js +77 -2
  36. package/src/service/audio/AudioManager.js +8 -2
  37. package/src/service/file/FileAssembler.js +106 -0
  38. package/src/service/file/FileChunker.js +79 -0
  39. package/src/service/file/FileManager.js +307 -0
  40. package/src/service/file/FileMessage.js +122 -0
  41. package/src/service/file/index.js +15 -0
  42. package/src/service/text/broadcast/BroadcastManager.js +16 -0
  43. package/src/transport/BLETransport.js +131 -9
  44. package/src/transport/MockTransport.js +1 -1
  45. package/src/transport/MultiTransport.js +305 -0
  46. package/src/transport/WiFiDirectTransport.js +295 -0
  47. package/src/transport/adapters/NodeBLEAdapter.js +34 -0
  48. package/src/transport/adapters/RNBLEAdapter.js +56 -1
  49. package/src/transport/index.js +6 -0
  50. package/src/utils/compression.js +291 -291
  51. package/src/crypto/aead.js +0 -189
  52. package/src/crypto/chacha20.js +0 -181
  53. package/src/crypto/hkdf.js +0 -187
  54. package/src/crypto/hmac.js +0 -143
  55. package/src/crypto/keys/KeyManager.js +0 -271
  56. package/src/crypto/keys/KeyPair.js +0 -216
  57. package/src/crypto/keys/SecureStorage.js +0 -219
  58. package/src/crypto/keys/index.js +0 -32
  59. package/src/crypto/noise/handshake.js +0 -410
  60. package/src/crypto/noise/index.js +0 -27
  61. package/src/crypto/noise/session.js +0 -253
  62. package/src/crypto/noise/state.js +0 -268
  63. package/src/crypto/poly1305.js +0 -113
  64. package/src/crypto/sha256.js +0 -240
  65. package/src/crypto/x25519.js +0 -154
@@ -3,7 +3,7 @@
3
3
  /**
4
4
  * @fileoverview Emergency Manager for Panic Mode / Data Wipe
5
5
  * @module service/EmergencyManager
6
- *
6
+ *
7
7
  * Provides panic mode functionality for immediate data wipe.
8
8
  * Critical security feature for high-risk users (activists, protesters).
9
9
  * Target: <200ms wipe completion time.
@@ -16,10 +16,10 @@ const EventEmitter = require('../utils/EventEmitter');
16
16
  * @constant {Object}
17
17
  */
18
18
  const PANIC_TRIGGER = Object.freeze({
19
- TRIPLE_TAP: 'triple_tap',
20
- SHAKE: 'shake',
21
- MANUAL: 'manual',
22
- VOLUME_COMBO: 'volume_combo',
19
+ TRIPLE_TAP: 'triple_tap',
20
+ SHAKE: 'shake',
21
+ MANUAL: 'manual',
22
+ VOLUME_COMBO: 'volume_combo'
23
23
  });
24
24
 
25
25
  /**
@@ -27,41 +27,41 @@ const PANIC_TRIGGER = Object.freeze({
27
27
  * @constant {Object}
28
28
  */
29
29
  const DEFAULT_CONFIG = Object.freeze({
30
- /** Trigger type for panic mode */
31
- trigger: PANIC_TRIGGER.TRIPLE_TAP,
32
- /** Time window for multi-tap detection (ms) */
33
- tapWindowMs: 500,
34
- /** Number of taps required */
35
- tapCount: 3,
36
- /** Shake threshold for accelerometer */
37
- shakeThreshold: 15,
38
- /** Shake duration required (ms) */
39
- shakeDurationMs: 500,
40
- /** Confirmation required before wipe */
41
- requireConfirmation: false,
42
- /** Target wipe time (ms) */
43
- targetWipeTimeMs: 200,
30
+ /** Trigger type for panic mode */
31
+ trigger: PANIC_TRIGGER.TRIPLE_TAP,
32
+ /** Time window for multi-tap detection (ms) */
33
+ tapWindowMs: 500,
34
+ /** Number of taps required */
35
+ tapCount: 3,
36
+ /** Shake threshold for accelerometer */
37
+ shakeThreshold: 15,
38
+ /** Shake duration required (ms) */
39
+ shakeDurationMs: 500,
40
+ /** Confirmation required before wipe */
41
+ requireConfirmation: false,
42
+ /** Target wipe time (ms) */
43
+ targetWipeTimeMs: 200
44
44
  });
45
45
 
46
46
  /**
47
47
  * Emergency Manager for panic mode and data wipe.
48
- *
48
+ *
49
49
  * @class EmergencyManager
50
50
  * @extends EventEmitter
51
51
  * @example
52
52
  * const emergency = new EmergencyManager({
53
53
  * trigger: 'triple_tap',
54
54
  * });
55
- *
55
+ *
56
56
  * emergency.enablePanicMode({
57
57
  * onWipe: () => console.log('Data wiped'),
58
58
  * });
59
- *
59
+ *
60
60
  * // Register tap events
61
61
  * emergency.registerTap();
62
62
  */
63
63
  class EmergencyManager extends EventEmitter {
64
- /**
64
+ /**
65
65
  * Creates a new EmergencyManager instance.
66
66
  * @param {Object} [options={}] - Configuration options
67
67
  * @param {string} [options.trigger='triple_tap'] - Panic trigger type
@@ -69,302 +69,312 @@ class EmergencyManager extends EventEmitter {
69
69
  * @param {number} [options.tapCount=3] - Required tap count
70
70
  * @param {boolean} [options.requireConfirmation=false] - Require confirmation
71
71
  */
72
- constructor(options = {}) {
73
- super();
72
+ constructor(options = {}) {
73
+ super();
74
74
 
75
- /**
75
+ /**
76
76
  * Configuration
77
77
  * @type {Object}
78
78
  * @private
79
79
  */
80
- this._config = { ...DEFAULT_CONFIG, ...options };
80
+ this._config = { ...DEFAULT_CONFIG, ...options };
81
81
 
82
- /**
82
+ /**
83
83
  * Whether panic mode is enabled
84
84
  * @type {boolean}
85
85
  * @private
86
86
  */
87
- this._enabled = false;
87
+ this._enabled = false;
88
88
 
89
- /**
89
+ /**
90
90
  * Tap tracking
91
91
  * @type {Object}
92
92
  * @private
93
93
  */
94
- this._tapState = {
95
- count: 0,
96
- lastTapTime: 0,
97
- };
94
+ this._tapState = {
95
+ count: 0,
96
+ lastTapTime: 0
97
+ };
98
98
 
99
- /**
99
+ /**
100
100
  * Shake tracking
101
101
  * @type {Object}
102
102
  * @private
103
103
  */
104
- this._shakeState = {
105
- startTime: 0,
106
- isShaking: false,
107
- };
104
+ this._shakeState = {
105
+ startTime: 0,
106
+ isShaking: false
107
+ };
108
108
 
109
- /**
109
+ /**
110
110
  * Wipe callback
111
111
  * @type {Function|null}
112
112
  * @private
113
113
  */
114
- this._onWipe = null;
114
+ this._onWipe = null;
115
115
 
116
- /**
116
+ /**
117
117
  * Data clearers to execute during wipe
118
118
  * @type {Function[]}
119
119
  * @private
120
120
  */
121
- this._clearers = [];
121
+ this._clearers = [];
122
122
 
123
- /**
123
+ /**
124
124
  * Statistics
125
125
  * @type {Object}
126
126
  * @private
127
127
  */
128
- this._stats = {
129
- wipesTriggered: 0,
130
- averageWipeTimeMs: 0,
131
- lastWipeTime: null,
132
- };
133
- }
134
-
135
- /**
128
+ this._stats = {
129
+ wipesTriggered: 0,
130
+ averageWipeTimeMs: 0,
131
+ lastWipeTime: null
132
+ };
133
+ }
134
+
135
+ /**
136
136
  * Enables panic mode.
137
137
  * @param {Object} [options={}] - Enable options
138
138
  * @param {Function} [options.onWipe] - Callback after wipe
139
139
  * @param {string} [options.trigger] - Override trigger type
140
140
  */
141
- enablePanicMode(options = {}) {
142
- this._enabled = true;
143
- this._onWipe = options.onWipe || null;
144
-
145
- if (options.trigger) {
146
- this._config.trigger = options.trigger;
147
- }
141
+ enablePanicMode(options = {}) {
142
+ this._enabled = true;
143
+ this._onWipe = options.onWipe || null;
148
144
 
149
- this.emit('panic-mode-enabled', {
150
- trigger: this._config.trigger,
151
- });
145
+ if (options.trigger) {
146
+ this._config.trigger = options.trigger;
152
147
  }
153
148
 
154
- /**
149
+ this.emit('panic-mode-enabled', {
150
+ trigger: this._config.trigger
151
+ });
152
+ }
153
+
154
+ /**
155
155
  * Disables panic mode.
156
156
  */
157
- disablePanicMode() {
158
- this._enabled = false;
159
- this._resetTapState();
160
- this._resetShakeState();
157
+ disablePanicMode() {
158
+ this._enabled = false;
159
+ this._resetTapState();
160
+ this._resetShakeState();
161
161
 
162
- this.emit('panic-mode-disabled');
163
- }
162
+ this.emit('panic-mode-disabled');
163
+ }
164
164
 
165
- /**
165
+ /**
166
166
  * Checks if panic mode is enabled.
167
167
  * @returns {boolean} True if enabled
168
168
  */
169
- isEnabled() {
170
- return this._enabled;
171
- }
169
+ isEnabled() {
170
+ return this._enabled;
171
+ }
172
172
 
173
- /**
173
+ /**
174
174
  * Registers a data clearer function.
175
175
  * @param {Function} clearer - Async function to clear data
176
176
  */
177
- registerClearer(clearer) {
178
- if (typeof clearer === 'function') {
179
- this._clearers.push(clearer);
180
- }
177
+ registerClearer(clearer) {
178
+ if (typeof clearer === 'function') {
179
+ this._clearers.push(clearer);
181
180
  }
181
+ }
182
182
 
183
- /**
183
+ /**
184
184
  * Registers a tap event (for triple-tap detection).
185
185
  */
186
- registerTap() {
187
- if (!this._enabled || this._config.trigger !== PANIC_TRIGGER.TRIPLE_TAP) {
188
- return;
189
- }
190
-
191
- const now = Date.now();
192
- const windowExpired = (now - this._tapState.lastTapTime) > this._config.tapWindowMs;
193
-
194
- if (windowExpired) {
195
- this._tapState.count = 1;
196
- } else {
197
- this._tapState.count++;
198
- }
199
-
200
- this._tapState.lastTapTime = now;
201
-
202
- // Check if threshold reached
203
- if (this._tapState.count >= this._config.tapCount) {
204
- this._triggerPanic(PANIC_TRIGGER.TRIPLE_TAP);
205
- this._resetTapState();
206
- }
186
+ registerTap() {
187
+ if (!this._enabled || this._config.trigger !== PANIC_TRIGGER.TRIPLE_TAP) {
188
+ return;
207
189
  }
208
190
 
209
- /**
191
+ const now = Date.now();
192
+ const windowExpired = (now - this._tapState.lastTapTime) > this._config.tapWindowMs;
193
+
194
+ if (windowExpired) {
195
+ this._tapState.count = 1;
196
+ } else {
197
+ this._tapState.count++;
198
+ }
199
+
200
+ this._tapState.lastTapTime = now;
201
+
202
+ // Check if threshold reached
203
+ if (this._tapState.count >= this._config.tapCount) {
204
+ this._triggerPanic(PANIC_TRIGGER.TRIPLE_TAP).catch(() => {});
205
+ this._resetTapState();
206
+ }
207
+ }
208
+
209
+ /**
210
210
  * Registers accelerometer data for shake detection.
211
211
  * @param {Object} data - Accelerometer data
212
212
  * @param {number} data.x - X acceleration
213
213
  * @param {number} data.y - Y acceleration
214
214
  * @param {number} data.z - Z acceleration
215
215
  */
216
- registerAccelerometer(data) {
217
- if (!this._enabled || this._config.trigger !== PANIC_TRIGGER.SHAKE) {
218
- return;
219
- }
220
-
221
- const magnitude = Math.sqrt(data.x ** 2 + data.y ** 2 + data.z ** 2);
222
- const now = Date.now();
223
-
224
- if (magnitude > this._config.shakeThreshold) {
225
- if (!this._shakeState.isShaking) {
226
- this._shakeState.isShaking = true;
227
- this._shakeState.startTime = now;
228
- } else if ((now - this._shakeState.startTime) >= this._config.shakeDurationMs) {
229
- this._triggerPanic(PANIC_TRIGGER.SHAKE);
230
- this._resetShakeState();
231
- }
232
- } else {
233
- this._resetShakeState();
234
- }
216
+ registerAccelerometer(data) {
217
+ if (!this._enabled || this._config.trigger !== PANIC_TRIGGER.SHAKE) {
218
+ return;
235
219
  }
236
220
 
237
- /**
221
+ const magnitude = Math.sqrt(data.x ** 2 + data.y ** 2 + data.z ** 2);
222
+ const now = Date.now();
223
+
224
+ if (magnitude > this._config.shakeThreshold) {
225
+ if (!this._shakeState.isShaking) {
226
+ this._shakeState.isShaking = true;
227
+ this._shakeState.startTime = now;
228
+ } else if ((now - this._shakeState.startTime) >= this._config.shakeDurationMs) {
229
+ this._triggerPanic(PANIC_TRIGGER.SHAKE).catch(() => {});
230
+ this._resetShakeState();
231
+ }
232
+ } else {
233
+ this._resetShakeState();
234
+ }
235
+ }
236
+
237
+ /**
238
238
  * Manually triggers panic wipe.
239
239
  * @returns {Promise<Object>} Wipe result
240
240
  */
241
- async triggerManualWipe() {
242
- return this._executeWipe(PANIC_TRIGGER.MANUAL);
243
- }
241
+ async triggerManualWipe() {
242
+ return this._executeWipe(PANIC_TRIGGER.MANUAL);
243
+ }
244
244
 
245
- /**
245
+ /**
246
246
  * Wipes all registered data.
247
247
  * @returns {Promise<Object>} Wipe result with timing
248
248
  */
249
- async wipeAllData() {
250
- return this._executeWipe(PANIC_TRIGGER.MANUAL);
251
- }
249
+ async wipeAllData() {
250
+ return this._executeWipe(PANIC_TRIGGER.MANUAL);
251
+ }
252
252
 
253
- /**
253
+ /**
254
254
  * Gets emergency statistics.
255
255
  * @returns {Object} Statistics
256
256
  */
257
- getStats() {
258
- return { ...this._stats };
259
- }
257
+ getStats() {
258
+ return { ...this._stats };
259
+ }
260
260
 
261
- /**
261
+ /**
262
262
  * Destroys the manager.
263
263
  */
264
- destroy() {
265
- this.disablePanicMode();
266
- this._clearers = [];
267
- this.removeAllListeners();
268
- }
264
+ destroy() {
265
+ this.disablePanicMode();
266
+ this._clearers = [];
267
+ this.removeAllListeners();
268
+ }
269
269
 
270
- /**
270
+ /**
271
271
  * Triggers panic mode.
272
272
  * @param {string} trigger - Trigger type
273
273
  * @private
274
274
  */
275
- _triggerPanic(trigger) {
276
- if (this._config.requireConfirmation) {
277
- this.emit('panic-confirmation-required', { trigger });
278
- return;
279
- }
275
+ async _triggerPanic(trigger) {
276
+ if (this._config.requireConfirmation) {
277
+ this.emit('panic-confirmation-required', { trigger });
278
+ return;
279
+ }
280
280
 
281
- this._executeWipe(trigger);
281
+ try {
282
+ await this._executeWipe(trigger);
283
+ } catch (error) {
284
+ this.emit('error', {
285
+ message: 'Panic wipe failed',
286
+ error: error.message,
287
+ trigger
288
+ });
282
289
  }
290
+ }
283
291
 
284
- /**
292
+ /**
285
293
  * Executes the data wipe.
286
294
  * @param {string} trigger - Trigger type
287
295
  * @returns {Promise<Object>} Wipe result
288
296
  * @private
289
297
  */
290
- async _executeWipe(trigger) {
291
- const startTime = Date.now();
292
-
293
- this.emit('panic-wipe-started', { trigger, timestamp: startTime });
294
-
295
- const results = {
296
- trigger,
297
- startTime,
298
- clearerResults: [],
299
- errors: [],
300
- };
301
-
302
- // Execute all clearers in parallel for speed
303
- const promises = this._clearers.map(async (clearer, index) => {
304
- try {
305
- await clearer();
306
- results.clearerResults.push({ index, success: true });
307
- } catch (error) {
308
- results.errors.push({ index, error: error.message });
309
- results.clearerResults.push({ index, success: false, error: error.message });
310
- }
311
- });
312
-
313
- await Promise.all(promises);
314
-
315
- const endTime = Date.now();
316
- const elapsedMs = endTime - startTime;
317
-
318
- // Update stats with correct running average calculation
319
- const previousCount = this._stats.wipesTriggered;
320
- this._stats.wipesTriggered++;
321
- this._stats.lastWipeTime = endTime;
322
- // Proper running average: ((oldAvg * oldCount) + newValue) / newCount
323
- this._stats.averageWipeTimeMs = previousCount > 0
324
- ? ((this._stats.averageWipeTimeMs * previousCount) + elapsedMs) / this._stats.wipesTriggered
325
- : elapsedMs;
326
-
327
- results.endTime = endTime;
328
- results.elapsedMs = elapsedMs;
329
- results.metTarget = elapsedMs <= this._config.targetWipeTimeMs;
330
-
331
- this.emit('panic-wipe-completed', results);
332
-
333
- // Call user callback
334
- if (this._onWipe) {
335
- try {
336
- this._onWipe(results);
337
- } catch (error) {
338
- // Ignore callback errors
339
- }
340
- }
341
-
342
- console.log(`Panic wipe completed in ${elapsedMs}ms`);
343
-
344
- return results;
298
+ async _executeWipe(trigger) {
299
+ const startTime = Date.now();
300
+
301
+ this.emit('panic-wipe-started', { trigger, timestamp: startTime });
302
+
303
+ const results = {
304
+ trigger,
305
+ startTime,
306
+ clearerResults: [],
307
+ errors: []
308
+ };
309
+
310
+ // Execute all clearers in parallel for speed
311
+ const clearerResults = new Array(this._clearers.length);
312
+ const promises = this._clearers.map(async (clearer, index) => {
313
+ try {
314
+ await clearer();
315
+ clearerResults[index] = { index, success: true };
316
+ } catch (error) {
317
+ results.errors.push({ index, error: error.message });
318
+ clearerResults[index] = { index, success: false, error: error.message };
319
+ }
320
+ });
321
+
322
+ await Promise.all(promises);
323
+ results.clearerResults = clearerResults;
324
+
325
+ const endTime = Date.now();
326
+ const elapsedMs = endTime - startTime;
327
+
328
+ // Update stats with correct running average calculation
329
+ const previousCount = this._stats.wipesTriggered;
330
+ this._stats.wipesTriggered++;
331
+ this._stats.lastWipeTime = endTime;
332
+ // Proper running average: ((oldAvg * oldCount) + newValue) / newCount
333
+ this._stats.averageWipeTimeMs = previousCount > 0
334
+ ? ((this._stats.averageWipeTimeMs * previousCount) + elapsedMs) / this._stats.wipesTriggered
335
+ : elapsedMs;
336
+
337
+ results.endTime = endTime;
338
+ results.elapsedMs = elapsedMs;
339
+ results.metTarget = elapsedMs <= this._config.targetWipeTimeMs;
340
+
341
+ this.emit('panic-wipe-completed', results);
342
+
343
+ // Call user callback
344
+ if (this._onWipe) {
345
+ try {
346
+ this._onWipe(results);
347
+ } catch (error) {
348
+ // Ignore callback errors
349
+ }
345
350
  }
346
351
 
347
- /**
352
+ console.log(`Panic wipe completed in ${elapsedMs}ms`);
353
+
354
+ return results;
355
+ }
356
+
357
+ /**
348
358
  * Resets tap state.
349
359
  * @private
350
360
  */
351
- _resetTapState() {
352
- this._tapState.count = 0;
353
- this._tapState.lastTapTime = 0;
354
- }
361
+ _resetTapState() {
362
+ this._tapState.count = 0;
363
+ this._tapState.lastTapTime = 0;
364
+ }
355
365
 
356
- /**
366
+ /**
357
367
  * Resets shake state.
358
368
  * @private
359
369
  */
360
- _resetShakeState() {
361
- this._shakeState.isShaking = false;
362
- this._shakeState.startTime = 0;
363
- }
370
+ _resetShakeState() {
371
+ this._shakeState.isShaking = false;
372
+ this._shakeState.startTime = 0;
373
+ }
364
374
  }
365
375
 
366
376
  module.exports = {
367
- EmergencyManager,
368
- PANIC_TRIGGER,
369
- DEFAULT_CONFIG,
377
+ EmergencyManager,
378
+ PANIC_TRIGGER,
379
+ DEFAULT_CONFIG
370
380
  };