react-native-ble-mesh 2.1.2 → 2.1.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-ble-mesh",
3
- "version": "2.1.2",
3
+ "version": "2.1.3",
4
4
  "description": "React Native Bluetooth Low Energy (BLE) mesh networking library with end-to-end encryption, offline messaging, peer-to-peer communication, and Noise Protocol security for iOS and Android",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",
@@ -78,7 +78,8 @@
78
78
  "peerDependencies": {
79
79
  "react-native": ">=0.60.0",
80
80
  "react-native-get-random-values": ">=1.8.0",
81
- "react-native-ble-plx": ">=2.0.0"
81
+ "react-native-ble-plx": ">=2.0.0",
82
+ "tweetnacl": ">=1.0.0"
82
83
  },
83
84
  "peerDependenciesMeta": {
84
85
  "react-native": {
@@ -86,6 +87,12 @@
86
87
  },
87
88
  "react-native-ble-plx": {
88
89
  "optional": true
90
+ },
91
+ "react-native-get-random-values": {
92
+ "optional": true
93
+ },
94
+ "tweetnacl": {
95
+ "optional": true
89
96
  }
90
97
  },
91
98
  "files": [
@@ -10,10 +10,40 @@
10
10
 
11
11
  const CryptoProvider = require('../CryptoProvider');
12
12
 
13
+ /**
14
+ * Converts a hex string to Uint8Array (Buffer-free for React Native compatibility)
15
+ * @param {string} hex - Hex string
16
+ * @returns {Uint8Array}
17
+ */
18
+ function hexToBytes(hex) {
19
+ const bytes = new Uint8Array(hex.length / 2);
20
+ for (let i = 0; i < hex.length; i += 2) {
21
+ bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);
22
+ }
23
+ return bytes;
24
+ }
25
+
26
+ /**
27
+ * Concatenates multiple Uint8Arrays into a single Uint8Array
28
+ * @param {...Uint8Array} arrays
29
+ * @returns {Uint8Array}
30
+ */
31
+ function concatBytes(...arrays) {
32
+ let totalLength = 0;
33
+ for (const arr of arrays) { totalLength += arr.length; }
34
+ const result = new Uint8Array(totalLength);
35
+ let offset = 0;
36
+ for (const arr of arrays) {
37
+ result.set(arr, offset);
38
+ offset += arr.length;
39
+ }
40
+ return result;
41
+ }
42
+
13
43
  /** DER header for PKCS8 private key wrapping (X25519) */
14
- const PKCS8_HEADER = Buffer.from('302e020100300506032b656e04220420', 'hex');
44
+ const PKCS8_HEADER = hexToBytes('302e020100300506032b656e04220420');
15
45
  /** DER header for SPKI public key wrapping (X25519) */
16
- const SPKI_HEADER = Buffer.from('302a300506032b656e032100', 'hex');
46
+ const SPKI_HEADER = hexToBytes('302a300506032b656e032100');
17
47
 
18
48
  /**
19
49
  * Crypto provider using react-native-quick-crypto.
@@ -63,18 +93,18 @@ class QuickCryptoProvider extends CryptoProvider {
63
93
  sharedSecret(/** @type {any} */ secretKey, /** @type {any} */ publicKey) {
64
94
  const crypto = this._getCrypto();
65
95
  const privKey = crypto.createPrivateKey({
66
- key: Buffer.concat([
96
+ key: concatBytes(
67
97
  PKCS8_HEADER,
68
- Buffer.from(secretKey)
69
- ]),
98
+ new Uint8Array(secretKey)
99
+ ),
70
100
  format: 'der',
71
101
  type: 'pkcs8'
72
102
  });
73
103
  const pubKey = crypto.createPublicKey({
74
- key: Buffer.concat([
104
+ key: concatBytes(
75
105
  SPKI_HEADER,
76
- Buffer.from(publicKey)
77
- ]),
106
+ new Uint8Array(publicKey)
107
+ ),
78
108
  format: 'der',
79
109
  type: 'spki'
80
110
  });
@@ -1,4 +1,5 @@
1
1
  'use strict';
2
+ /* global __DEV__ */
2
3
 
3
4
  /**
4
5
  * @fileoverview React Native app state management for mesh service
@@ -63,7 +64,7 @@ class AppStateManager {
63
64
  this._AppState = AppState;
64
65
  } catch (e) {
65
66
  // React Native not available (Node.js environment)
66
- console.warn('AppStateManager: React Native AppState not available');
67
+ // React Native not available (Node.js or test environment) — silently skip
67
68
  return false;
68
69
  }
69
70
 
@@ -122,7 +123,9 @@ class AppStateManager {
122
123
  this._mesh._saveState();
123
124
  }
124
125
  } catch (e) {
125
- console.warn('AppStateManager: Error handling background transition', e);
126
+ if (typeof __DEV__ !== 'undefined' && __DEV__) {
127
+ console.warn('AppStateManager: Error handling background transition', e);
128
+ }
126
129
  }
127
130
  }
128
131
 
@@ -144,7 +147,9 @@ class AppStateManager {
144
147
  this._mesh._restoreState();
145
148
  }
146
149
  } catch (e) {
147
- console.warn('AppStateManager: Error handling foreground transition', e);
150
+ if (typeof __DEV__ !== 'undefined' && __DEV__) {
151
+ console.warn('AppStateManager: Error handling foreground transition', e);
152
+ }
148
153
  }
149
154
  }
150
155
 
@@ -342,7 +342,7 @@ class EmergencyManager extends EventEmitter {
342
342
  }
343
343
  }
344
344
 
345
- console.log(`Panic wipe completed in ${elapsedMs}ms`);
345
+ // Panic wipe completed — avoid logging sensitive operations in production
346
346
 
347
347
  return results;
348
348
  }
@@ -1,4 +1,5 @@
1
1
  'use strict';
2
+ /* global __DEV__ */
2
3
 
3
4
  /**
4
5
  * @fileoverview LC3 codec wrapper for React Native
@@ -79,7 +80,9 @@ class LC3Codec extends EventEmitter {
79
80
  } else {
80
81
  // Use mock implementation for testing
81
82
  this._useMock = true;
82
- console.warn('LC3Codec: Native module not available, using mock implementation');
83
+ if (typeof __DEV__ !== 'undefined' && __DEV__) {
84
+ console.warn('LC3Codec: Native module not available, using mock implementation');
85
+ }
83
86
  }
84
87
 
85
88
  this._initialized = true;
@@ -10,6 +10,7 @@
10
10
 
11
11
  const Transport = require('./Transport');
12
12
  const { ConnectionError } = require('../errors');
13
+ const base64 = require('../utils/base64');
13
14
 
14
15
  /**
15
16
  * Wi-Fi Direct transport states
@@ -228,14 +229,14 @@ class WiFiDirectTransport extends Transport {
228
229
  const peerInfo = this._peers.get(peerId);
229
230
 
230
231
  // Convert Uint8Array to base64 for transfer
231
- const base64 = this._uint8ArrayToBase64(data);
232
+ const encoded = this._uint8ArrayToBase64(data);
232
233
 
233
234
  if (this._isGroupOwner) {
234
235
  // Group owner sends via server socket
235
- await p2p?.sendMessage(base64);
236
+ await p2p?.sendMessage(encoded);
236
237
  } else {
237
238
  // Client sends to group owner address
238
- await p2p?.sendMessageTo(peerInfo.groupOwnerAddress, this._port, base64);
239
+ await p2p?.sendMessageTo(peerInfo.groupOwnerAddress, this._port, encoded);
239
240
  }
240
241
  }
241
242
 
@@ -289,12 +290,7 @@ class WiFiDirectTransport extends Transport {
289
290
 
290
291
  /** @private */
291
292
  _uint8ArrayToBase64(/** @type {any} */ bytes) {
292
- const chunks = [];
293
- for (let i = 0; i < bytes.length; i += 8192) {
294
- chunks.push(String.fromCharCode.apply(null, bytes.subarray(i, Math.min(i + 8192, bytes.length))));
295
- }
296
- const binary = chunks.join('');
297
- return typeof btoa !== 'undefined' ? btoa(binary) : Buffer.from(bytes).toString('base64');
293
+ return base64.encode(bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes));
298
294
  }
299
295
  }
300
296
 
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  const BLEAdapter = require('./BLEAdapter');
9
+ const base64 = require('../../utils/base64');
9
10
 
10
11
  /**
11
12
  * React Native BLE adapter implementation.
@@ -360,26 +361,17 @@ class RNBLEAdapter extends BLEAdapter {
360
361
  * @private
361
362
  */
362
363
  _uint8ArrayToBase64(bytes) {
363
- let binary = '';
364
- for (let i = 0; i < bytes.length; i++) {
365
- binary += String.fromCharCode(bytes[i]);
366
- }
367
- return btoa(binary);
364
+ return base64.encode(bytes);
368
365
  }
369
366
 
370
367
  /**
371
368
  * Converts Base64 string to Uint8Array
372
- * @param {string} base64 - Base64 string
369
+ * @param {string} base64Str - Base64 string
373
370
  * @returns {Uint8Array} Byte array
374
371
  * @private
375
372
  */
376
- _base64ToUint8Array(base64) {
377
- const binary = atob(base64);
378
- const bytes = new Uint8Array(binary.length);
379
- for (let i = 0; i < binary.length; i++) {
380
- bytes[i] = binary.charCodeAt(i);
381
- }
382
- return bytes;
373
+ _base64ToUint8Array(base64Str) {
374
+ return base64.decode(base64Str);
383
375
  }
384
376
  }
385
377
 
@@ -1,4 +1,5 @@
1
1
  'use strict';
2
+ /* global __DEV__ */
2
3
 
3
4
  /**
4
5
  * @fileoverview Enhanced EventEmitter class
@@ -51,11 +52,13 @@ class EventEmitter {
51
52
 
52
53
  // Warn if max listeners exceeded
53
54
  if (listeners.length >= this._maxListeners) {
54
- console.warn(
55
- 'MaxListenersExceededWarning: Possible EventEmitter memory leak detected. ' +
56
- `${listeners.length + 1} ${event} listeners added. ` +
57
- 'Use setMaxListeners() to increase limit'
58
- );
55
+ if (typeof __DEV__ !== 'undefined' && __DEV__) {
56
+ console.warn(
57
+ 'MaxListenersExceededWarning: Possible EventEmitter memory leak detected. ' +
58
+ `${listeners.length + 1} ${event} listeners added. ` +
59
+ 'Use setMaxListeners() to increase limit'
60
+ );
61
+ }
59
62
  }
60
63
 
61
64
  listeners.push({ listener, once: false });
@@ -91,9 +91,7 @@ class MessageCompressor {
91
91
  }
92
92
  } catch (/** @type {any} */ error) {
93
93
  // Log compression error at debug level for troubleshooting
94
- if (typeof console !== 'undefined' && console.debug) {
95
- console.debug('Compression failed, using uncompressed:', error.message);
96
- }
94
+ // Compression failure is non-fatal silently fall back to uncompressed
97
95
  }
98
96
 
99
97
  this._stats.bytesOut += payload.length;