iosignal 5.3.0 → 6.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.
@@ -2,19 +2,19 @@ import require$$0$2, { Transform } from 'stream';
2
2
  import net from 'net';
3
3
  import require$$0$3 from 'events';
4
4
  import require$$1$1 from 'https';
5
- import require$$2$2 from 'http';
5
+ import require$$2$1 from 'http';
6
6
  import require$$4 from 'tls';
7
7
  import require$$1 from 'crypto';
8
8
  import require$$7 from 'url';
9
9
  import require$$0 from 'zlib';
10
- import fs, { readFileSync } from 'fs';
11
- import path from 'path';
12
- import require$$2, { networkInterfaces } from 'os';
13
10
  import require$$0$1 from 'buffer';
14
- import require$$2$1 from 'util';
11
+ import require$$2 from 'util';
12
+ import { networkInterfaces } from 'os';
13
+ import fs, { readFileSync } from 'fs';
15
14
  import { memoryUsage } from 'process';
15
+ import path from 'path';
16
16
 
17
- var version$1 = "5.3.0";
17
+ var version$1 = "6.1.0";
18
18
  var pkg = {
19
19
  version: version$1};
20
20
 
@@ -665,6 +665,7 @@ const encoder$2 = new TextEncoder();
665
665
  function getSignalPack(tag, ...args) {
666
666
  if (typeof tag !== 'string') throw TypeError('tag should be string.')
667
667
  let tagEncoded = encoder$2.encode(tag);
668
+ if (tagEncoded.byteLength > SIZE_LIMIT.TAG_LEN1) throw TypeError('tag UTF-8 byte length exceeds 255')
668
669
  let payload = parsePayload(args);
669
670
 
670
671
  let sigPack;
@@ -772,6 +773,16 @@ const Buffer$1 = $$1.Buffer;
772
773
  const encoder$1 = new TextEncoder();
773
774
  const decoder$4 = new TextDecoder();
774
775
 
776
+ // Wire tag lengths use one byte, regardless of JavaScript string length.
777
+ function encodeTag(tag, allowEmpty = true) {
778
+ if (typeof tag !== 'string') throw TypeError('tag should be string.')
779
+ const encoded = encoder$1.encode(tag);
780
+ if ((!allowEmpty && encoded.byteLength === 0) || encoded.byteLength > SIZE_LIMIT.TAG_LEN1) {
781
+ throw TypeError('tag UTF-8 byte length must be ' + (allowEmpty ? '0' : '1') + '~255')
782
+ }
783
+ return encoded
784
+ }
785
+
775
786
  function byteToUrl(buffer) {
776
787
  //ipv4(4bytes) , port(2bytes)
777
788
  if (buffer.byteLength != 6) return
@@ -1306,10 +1317,10 @@ class IOCore extends EventEmitter {
1306
1317
  switch (payloadType) {
1307
1318
 
1308
1319
  case PAYLOAD_TYPE.EMPTY:
1309
- if (tag.indexOf('@') === 0) this.emit('@', tag, null);
1320
+ if (tag.indexOf('@') === 0) this.emit('@', tag);
1310
1321
  else {
1311
- this.emit(tag, tag, null);
1312
- this.emit('message', tag, null);
1322
+ this.emit(tag, tag);
1323
+ this.emit('message', tag);
1313
1324
  }
1314
1325
  break;
1315
1326
 
@@ -1593,6 +1604,7 @@ class IOCore extends EventEmitter {
1593
1604
  */
1594
1605
  signal(tag, ...args) {
1595
1606
  if (typeof tag !== 'string') throw TypeError('tag should be string.')
1607
+ if (tag.startsWith('@') && this.cid) encodeTag(this.cid + tag);
1596
1608
  let signalPack = getSignalPack(tag, ...args);
1597
1609
  this.send_enc_mode(signalPack);
1598
1610
  }
@@ -1616,9 +1628,9 @@ class IOCore extends EventEmitter {
1616
1628
  */
1617
1629
  signal_e2e(tag, data, key) {
1618
1630
 
1631
+ const tagEncoded = encodeTag(tag);
1632
+ if (tag.startsWith('@') && this.cid) encodeTag(this.cid + tag);
1619
1633
  if( !this.boho.isAuthorized ) return;
1620
- if (typeof tag !== 'string') throw TypeError('tag should be string.')
1621
- let tagEncoded = encoder$1.encode(tag);
1622
1634
  let dataPack = $$1.B8(data);
1623
1635
 
1624
1636
  //encrypt payload area with key
@@ -1703,39 +1715,37 @@ class IOCore extends EventEmitter {
1703
1715
  * @throws {TypeError} If tag is not a string or exceeds length limit.
1704
1716
  */
1705
1717
  subscribe(tag) {
1706
- if (typeof tag !== 'string') throw TypeError('tag should be string.')
1707
- if (tag.length > SIZE_LIMIT.TAG_LEN1) throw TypeError('please check tag string length limit:' + SIZE_LIMIT.TAG_LEN1)
1708
-
1709
- try {
1710
- let tagEncoded = encoder$1.encode(tag);
1711
- this.send_enc_mode(
1712
- Buffer$1.concat([
1713
- $$1.NB('8', IOMsg.SUBSCRIBE),
1714
- $$1.NB('8', tagEncoded.byteLength),
1715
- tagEncoded]));
1716
- } catch (error) { }
1717
-
1718
+ const tagEncoded = encodeTag(tag);
1719
+ this.send_enc_mode(Buffer$1.concat([
1720
+ $$1.NB('8', IOMsg.SUBSCRIBE),
1721
+ $$1.NB('8', tagEncoded.byteLength),
1722
+ tagEncoded]));
1718
1723
  }
1719
1724
 
1720
1725
 
1721
1726
  /**
1722
- * Subscribes stored channels.
1723
- * called client state become 'ready'
1727
+ * Sends subscriptions stored by listen()/link() on each CID-ready transition,
1728
+ * including reconnection. This automates subscription setup for simple clients.
1724
1729
  */
1725
1730
  subscribe_channels() {
1726
- if (this.state !== STATE.READY) return
1727
- if (this.channels.size == 0) return
1728
- let tag = Array.from(this.channels).join(',');
1729
-
1730
- try {
1731
- let tagEncoded = encoder$1.encode(tag);
1732
- this.send_enc_mode(
1733
- Buffer$1.concat([
1734
- $$1.NB('8', IOMsg.SUBSCRIBE),
1735
- $$1.NB('8', tagEncoded.byteLength),
1736
- tagEncoded]));
1737
- } catch (error) { }
1738
-
1731
+ if (this.state !== STATE.READY || this.channels.size === 0) return
1732
+ // Validate the entire list first, then split only at tag boundaries.
1733
+ // Preserve comma-separated entries accepted by existing registration APIs.
1734
+ const tags = Array.from(this.channels).join(',').split(',');
1735
+ const sizes = tags.map(tag => encodeTag(tag).byteLength);
1736
+ const batches = [];
1737
+ let batch = [], bytes = 0;
1738
+ tags.forEach((tag, i) => {
1739
+ if (batch.length && bytes + 1 + sizes[i] > SIZE_LIMIT.TAG_LEN1) {
1740
+ batches.push(batch.join(','));
1741
+ batch = [];
1742
+ bytes = 0;
1743
+ }
1744
+ bytes += (batch.length ? 1 : 0) + sizes[i];
1745
+ batch.push(tag);
1746
+ });
1747
+ if (batch.length) batches.push(batch.join(','));
1748
+ batches.forEach(tag => this.subscribe(tag));
1739
1749
  }
1740
1750
 
1741
1751
  /**
@@ -1744,7 +1754,7 @@ class IOCore extends EventEmitter {
1744
1754
  * @throws {TypeError} If tag is not a string or exceeds length limit.
1745
1755
  */
1746
1756
  unsubscribe(tag = "") {
1747
- if (typeof tag !== 'string') throw TypeError('tag should be string.')
1757
+ const tagEncoded = encodeTag(tag);
1748
1758
 
1749
1759
  if (tag == "") { // blank tag means unsubscribe all
1750
1760
  this.channels.clear();
@@ -1755,8 +1765,6 @@ class IOCore extends EventEmitter {
1755
1765
  });
1756
1766
  }
1757
1767
 
1758
- let tagEncoded = encoder$1.encode(tag);
1759
- if (tagEncoded.byteLength > SIZE_LIMIT.TAG_LEN1) throw TypeError('please use tag string bytelength below:' + SIZE_LIMIT.TAG_LEN1)
1760
1768
 
1761
1769
  this.send_enc_mode(Buffer$1.concat([
1762
1770
  $$1.NB('8', IOMsg.UNSUBSCRIBE),
@@ -1766,22 +1774,28 @@ class IOCore extends EventEmitter {
1766
1774
 
1767
1775
 
1768
1776
  /**
1769
- * Listens for signals on a specific tag.
1777
+ * Convenience API for simple clients (for example, CLI tools): register a
1778
+ * tag handler once and remember its subscription in channels. Register before
1779
+ * connection readiness; the CID-ready flow subscribes on initial connection
1780
+ * and again after reconnect, without application-level ready/subscribe code.
1781
+ * This does not send a subscription immediately, even if already ready.
1782
+ * For precise subscription/send ordering or dynamic subscriptions, use
1783
+ * on() with subscribe() in a ready handler instead. Direct signals use on('@').
1770
1784
  * @param {string} tag - The tag to listen on.
1771
1785
  * @param {Function} handler - The callback function to handle the signal.
1772
1786
  * @throws {TypeError} If tag is not a string, handler is not a function, or tag length is invalid.
1773
1787
  */
1774
1788
  listen(tag, handler) {
1775
1789
  if (typeof tag !== 'string') throw TypeError('tag should be string.')
1776
- if (tag.length > 255 || tag.length == 0) throw TypeError('tag string length range: 1~255')
1790
+ encodeTag(tag, false);
1777
1791
  if (typeof handler !== 'function') throw TypeError('handler is not a function.')
1778
1792
 
1779
1793
  if (tag.indexOf('@') !== 0) {
1780
1794
  this.channels.add(tag);
1781
1795
  }
1782
1796
  this.on(tag, handler);
1783
- // do not subscribe now.
1784
- // will subscribe when io state is 'ready'. (receive CID_RES from server)
1797
+ // Subscribe from the CID-ready flow, initially and after reconnect.
1798
+ // Keep registration separate from immediate subscription/send ordering.
1785
1799
 
1786
1800
  }
1787
1801
 
@@ -1797,7 +1811,7 @@ class IOCore extends EventEmitter {
1797
1811
  link(to, tag, handler) {
1798
1812
  if (typeof to !== 'string') throw TypeError('to(local link target) is not a string.')
1799
1813
  if (typeof tag !== 'string') throw TypeError('tag is not a string.')
1800
- if (tag.length > 255 || tag.length == 0) throw TypeError('tag string length range: 1~255')
1814
+ encodeTag(tag, false);
1801
1815
  if (typeof handler !== 'function') throw TypeError('handler is not a function.')
1802
1816
 
1803
1817
  if (tag.indexOf('@') !== 0) {
@@ -1828,7 +1842,7 @@ class IOCore extends EventEmitter {
1828
1842
  unlink(to, tag) {
1829
1843
  if (typeof to !== 'string') throw TypeError('to(local link target) is not a string.')
1830
1844
  if (typeof tag !== 'string') throw TypeError('tag is not a string.')
1831
- if (tag.length > 255 || tag.length == 0) throw TypeError('tag string length range: 1~255')
1845
+ encodeTag(tag, false);
1832
1846
 
1833
1847
  const linkSet = this.linkMap.get(to);
1834
1848
  if (!linkSet || !linkSet.has(tag)) return;
@@ -2193,300 +2207,6 @@ function requireConstants () {
2193
2207
  return constants;
2194
2208
  }
2195
2209
 
2196
- var bufferutil = {exports: {}};
2197
-
2198
- function commonjsRequire(path) {
2199
- throw new Error('Could not dynamically require "' + path + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.');
2200
- }
2201
-
2202
- var nodeGypBuild$1 = {exports: {}};
2203
-
2204
- var nodeGypBuild;
2205
- var hasRequiredNodeGypBuild$1;
2206
-
2207
- function requireNodeGypBuild$1 () {
2208
- if (hasRequiredNodeGypBuild$1) return nodeGypBuild;
2209
- hasRequiredNodeGypBuild$1 = 1;
2210
- var fs$1 = fs;
2211
- var path$1 = path;
2212
- var os = require$$2;
2213
-
2214
- // Workaround to fix webpack's build warnings: 'the request of a dependency is an expression'
2215
- var runtimeRequire = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : commonjsRequire; // eslint-disable-line
2216
-
2217
- var vars = (process.config && process.config.variables) || {};
2218
- var prebuildsOnly = !!process.env.PREBUILDS_ONLY;
2219
- var abi = process.versions.modules; // TODO: support old node where this is undef
2220
- var runtime = isElectron() ? 'electron' : (isNwjs() ? 'node-webkit' : 'node');
2221
-
2222
- var arch = process.env.npm_config_arch || os.arch();
2223
- var platform = process.env.npm_config_platform || os.platform();
2224
- var libc = process.env.LIBC || (isAlpine(platform) ? 'musl' : 'glibc');
2225
- var armv = process.env.ARM_VERSION || (arch === 'arm64' ? '8' : vars.arm_version) || '';
2226
- var uv = (process.versions.uv || '').split('.')[0];
2227
-
2228
- nodeGypBuild = load;
2229
-
2230
- function load (dir) {
2231
- return runtimeRequire(load.resolve(dir))
2232
- }
2233
-
2234
- load.resolve = load.path = function (dir) {
2235
- dir = path$1.resolve(dir || '.');
2236
-
2237
- try {
2238
- var name = runtimeRequire(path$1.join(dir, 'package.json')).name.toUpperCase().replace(/-/g, '_');
2239
- if (process.env[name + '_PREBUILD']) dir = process.env[name + '_PREBUILD'];
2240
- } catch (err) {}
2241
-
2242
- if (!prebuildsOnly) {
2243
- var release = getFirst(path$1.join(dir, 'build/Release'), matchBuild);
2244
- if (release) return release
2245
-
2246
- var debug = getFirst(path$1.join(dir, 'build/Debug'), matchBuild);
2247
- if (debug) return debug
2248
- }
2249
-
2250
- var prebuild = resolve(dir);
2251
- if (prebuild) return prebuild
2252
-
2253
- var nearby = resolve(path$1.dirname(process.execPath));
2254
- if (nearby) return nearby
2255
-
2256
- var target = [
2257
- 'platform=' + platform,
2258
- 'arch=' + arch,
2259
- 'runtime=' + runtime,
2260
- 'abi=' + abi,
2261
- 'uv=' + uv,
2262
- armv ? 'armv=' + armv : '',
2263
- 'libc=' + libc,
2264
- 'node=' + process.versions.node,
2265
- process.versions.electron ? 'electron=' + process.versions.electron : '',
2266
- typeof __webpack_require__ === 'function' ? 'webpack=true' : '' // eslint-disable-line
2267
- ].filter(Boolean).join(' ');
2268
-
2269
- throw new Error('No native build was found for ' + target + '\n loaded from: ' + dir + '\n')
2270
-
2271
- function resolve (dir) {
2272
- // Find matching "prebuilds/<platform>-<arch>" directory
2273
- var tuples = readdirSync(path$1.join(dir, 'prebuilds')).map(parseTuple);
2274
- var tuple = tuples.filter(matchTuple(platform, arch)).sort(compareTuples)[0];
2275
- if (!tuple) return
2276
-
2277
- // Find most specific flavor first
2278
- var prebuilds = path$1.join(dir, 'prebuilds', tuple.name);
2279
- var parsed = readdirSync(prebuilds).map(parseTags);
2280
- var candidates = parsed.filter(matchTags(runtime, abi));
2281
- var winner = candidates.sort(compareTags(runtime))[0];
2282
- if (winner) return path$1.join(prebuilds, winner.file)
2283
- }
2284
- };
2285
-
2286
- function readdirSync (dir) {
2287
- try {
2288
- return fs$1.readdirSync(dir)
2289
- } catch (err) {
2290
- return []
2291
- }
2292
- }
2293
-
2294
- function getFirst (dir, filter) {
2295
- var files = readdirSync(dir).filter(filter);
2296
- return files[0] && path$1.join(dir, files[0])
2297
- }
2298
-
2299
- function matchBuild (name) {
2300
- return /\.node$/.test(name)
2301
- }
2302
-
2303
- function parseTuple (name) {
2304
- // Example: darwin-x64+arm64
2305
- var arr = name.split('-');
2306
- if (arr.length !== 2) return
2307
-
2308
- var platform = arr[0];
2309
- var architectures = arr[1].split('+');
2310
-
2311
- if (!platform) return
2312
- if (!architectures.length) return
2313
- if (!architectures.every(Boolean)) return
2314
-
2315
- return { name, platform, architectures }
2316
- }
2317
-
2318
- function matchTuple (platform, arch) {
2319
- return function (tuple) {
2320
- if (tuple == null) return false
2321
- if (tuple.platform !== platform) return false
2322
- return tuple.architectures.includes(arch)
2323
- }
2324
- }
2325
-
2326
- function compareTuples (a, b) {
2327
- // Prefer single-arch prebuilds over multi-arch
2328
- return a.architectures.length - b.architectures.length
2329
- }
2330
-
2331
- function parseTags (file) {
2332
- var arr = file.split('.');
2333
- var extension = arr.pop();
2334
- var tags = { file: file, specificity: 0 };
2335
-
2336
- if (extension !== 'node') return
2337
-
2338
- for (var i = 0; i < arr.length; i++) {
2339
- var tag = arr[i];
2340
-
2341
- if (tag === 'node' || tag === 'electron' || tag === 'node-webkit') {
2342
- tags.runtime = tag;
2343
- } else if (tag === 'napi') {
2344
- tags.napi = true;
2345
- } else if (tag.slice(0, 3) === 'abi') {
2346
- tags.abi = tag.slice(3);
2347
- } else if (tag.slice(0, 2) === 'uv') {
2348
- tags.uv = tag.slice(2);
2349
- } else if (tag.slice(0, 4) === 'armv') {
2350
- tags.armv = tag.slice(4);
2351
- } else if (tag === 'glibc' || tag === 'musl') {
2352
- tags.libc = tag;
2353
- } else {
2354
- continue
2355
- }
2356
-
2357
- tags.specificity++;
2358
- }
2359
-
2360
- return tags
2361
- }
2362
-
2363
- function matchTags (runtime, abi) {
2364
- return function (tags) {
2365
- if (tags == null) return false
2366
- if (tags.runtime && tags.runtime !== runtime && !runtimeAgnostic(tags)) return false
2367
- if (tags.abi && tags.abi !== abi && !tags.napi) return false
2368
- if (tags.uv && tags.uv !== uv) return false
2369
- if (tags.armv && tags.armv !== armv) return false
2370
- if (tags.libc && tags.libc !== libc) return false
2371
-
2372
- return true
2373
- }
2374
- }
2375
-
2376
- function runtimeAgnostic (tags) {
2377
- return tags.runtime === 'node' && tags.napi
2378
- }
2379
-
2380
- function compareTags (runtime) {
2381
- // Precedence: non-agnostic runtime, abi over napi, then by specificity.
2382
- return function (a, b) {
2383
- if (a.runtime !== b.runtime) {
2384
- return a.runtime === runtime ? -1 : 1
2385
- } else if (a.abi !== b.abi) {
2386
- return a.abi ? -1 : 1
2387
- } else if (a.specificity !== b.specificity) {
2388
- return a.specificity > b.specificity ? -1 : 1
2389
- } else {
2390
- return 0
2391
- }
2392
- }
2393
- }
2394
-
2395
- function isNwjs () {
2396
- return !!(process.versions && process.versions.nw)
2397
- }
2398
-
2399
- function isElectron () {
2400
- if (process.versions && process.versions.electron) return true
2401
- if (process.env.ELECTRON_RUN_AS_NODE) return true
2402
- return typeof window !== 'undefined' && window.process && window.process.type === 'renderer'
2403
- }
2404
-
2405
- function isAlpine (platform) {
2406
- return platform === 'linux' && fs$1.existsSync('/etc/alpine-release')
2407
- }
2408
-
2409
- // Exposed for unit tests
2410
- // TODO: move to lib
2411
- load.parseTags = parseTags;
2412
- load.matchTags = matchTags;
2413
- load.compareTags = compareTags;
2414
- load.parseTuple = parseTuple;
2415
- load.matchTuple = matchTuple;
2416
- load.compareTuples = compareTuples;
2417
- return nodeGypBuild;
2418
- }
2419
-
2420
- var hasRequiredNodeGypBuild;
2421
-
2422
- function requireNodeGypBuild () {
2423
- if (hasRequiredNodeGypBuild) return nodeGypBuild$1.exports;
2424
- hasRequiredNodeGypBuild = 1;
2425
- const runtimeRequire = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : commonjsRequire; // eslint-disable-line
2426
- if (typeof runtimeRequire.addon === 'function') { // if the platform supports native resolving prefer that
2427
- nodeGypBuild$1.exports = runtimeRequire.addon.bind(runtimeRequire);
2428
- } else { // else use the runtime version here
2429
- nodeGypBuild$1.exports = requireNodeGypBuild$1();
2430
- }
2431
- return nodeGypBuild$1.exports;
2432
- }
2433
-
2434
- var fallback$1;
2435
- var hasRequiredFallback$1;
2436
-
2437
- function requireFallback$1 () {
2438
- if (hasRequiredFallback$1) return fallback$1;
2439
- hasRequiredFallback$1 = 1;
2440
-
2441
- /**
2442
- * Masks a buffer using the given mask.
2443
- *
2444
- * @param {Buffer} source The buffer to mask
2445
- * @param {Buffer} mask The mask to use
2446
- * @param {Buffer} output The buffer where to store the result
2447
- * @param {Number} offset The offset at which to start writing
2448
- * @param {Number} length The number of bytes to mask.
2449
- * @public
2450
- */
2451
- const mask = (source, mask, output, offset, length) => {
2452
- for (var i = 0; i < length; i++) {
2453
- output[offset + i] = source[i] ^ mask[i & 3];
2454
- }
2455
- };
2456
-
2457
- /**
2458
- * Unmasks a buffer using the given mask.
2459
- *
2460
- * @param {Buffer} buffer The buffer to unmask
2461
- * @param {Buffer} mask The mask to use
2462
- * @public
2463
- */
2464
- const unmask = (buffer, mask) => {
2465
- // Required until https://github.com/nodejs/node/issues/9006 is resolved.
2466
- const length = buffer.length;
2467
- for (var i = 0; i < length; i++) {
2468
- buffer[i] ^= mask[i & 3];
2469
- }
2470
- };
2471
-
2472
- fallback$1 = { mask, unmask };
2473
- return fallback$1;
2474
- }
2475
-
2476
- var hasRequiredBufferutil;
2477
-
2478
- function requireBufferutil () {
2479
- if (hasRequiredBufferutil) return bufferutil.exports;
2480
- hasRequiredBufferutil = 1;
2481
-
2482
- try {
2483
- bufferutil.exports = requireNodeGypBuild()(__dirname);
2484
- } catch (e) {
2485
- bufferutil.exports = requireFallback$1();
2486
- }
2487
- return bufferutil.exports;
2488
- }
2489
-
2490
2210
  var hasRequiredBufferUtil;
2491
2211
 
2492
2212
  function requireBufferUtil () {
@@ -2607,7 +2327,7 @@ function requireBufferUtil () {
2607
2327
  /* istanbul ignore else */
2608
2328
  if (!process.env.WS_NO_BUFFER_UTIL) {
2609
2329
  try {
2610
- const bufferUtil$1 = requireBufferutil();
2330
+ const bufferUtil$1 = require('bufferutil');
2611
2331
 
2612
2332
  bufferUtil.exports.mask = function (source, mask, output, offset, length) {
2613
2333
  if (length < 48) _mask(source, mask, output, offset, length);
@@ -3228,92 +2948,6 @@ function requirePermessageDeflate () {
3228
2948
 
3229
2949
  var validation = {exports: {}};
3230
2950
 
3231
- var utf8Validate = {exports: {}};
3232
-
3233
- var fallback;
3234
- var hasRequiredFallback;
3235
-
3236
- function requireFallback () {
3237
- if (hasRequiredFallback) return fallback;
3238
- hasRequiredFallback = 1;
3239
-
3240
- /**
3241
- * Checks if a given buffer contains only correct UTF-8.
3242
- * Ported from https://www.cl.cam.ac.uk/%7Emgk25/ucs/utf8_check.c by
3243
- * Markus Kuhn.
3244
- *
3245
- * @param {Buffer} buf The buffer to check
3246
- * @return {Boolean} `true` if `buf` contains only correct UTF-8, else `false`
3247
- * @public
3248
- */
3249
- function isValidUTF8(buf) {
3250
- const len = buf.length;
3251
- let i = 0;
3252
-
3253
- while (i < len) {
3254
- if ((buf[i] & 0x80) === 0x00) { // 0xxxxxxx
3255
- i++;
3256
- } else if ((buf[i] & 0xe0) === 0xc0) { // 110xxxxx 10xxxxxx
3257
- if (
3258
- i + 1 === len ||
3259
- (buf[i + 1] & 0xc0) !== 0x80 ||
3260
- (buf[i] & 0xfe) === 0xc0 // overlong
3261
- ) {
3262
- return false;
3263
- }
3264
-
3265
- i += 2;
3266
- } else if ((buf[i] & 0xf0) === 0xe0) { // 1110xxxx 10xxxxxx 10xxxxxx
3267
- if (
3268
- i + 2 >= len ||
3269
- (buf[i + 1] & 0xc0) !== 0x80 ||
3270
- (buf[i + 2] & 0xc0) !== 0x80 ||
3271
- buf[i] === 0xe0 && (buf[i + 1] & 0xe0) === 0x80 || // overlong
3272
- buf[i] === 0xed && (buf[i + 1] & 0xe0) === 0xa0 // surrogate (U+D800 - U+DFFF)
3273
- ) {
3274
- return false;
3275
- }
3276
-
3277
- i += 3;
3278
- } else if ((buf[i] & 0xf8) === 0xf0) { // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
3279
- if (
3280
- i + 3 >= len ||
3281
- (buf[i + 1] & 0xc0) !== 0x80 ||
3282
- (buf[i + 2] & 0xc0) !== 0x80 ||
3283
- (buf[i + 3] & 0xc0) !== 0x80 ||
3284
- buf[i] === 0xf0 && (buf[i + 1] & 0xf0) === 0x80 || // overlong
3285
- buf[i] === 0xf4 && buf[i + 1] > 0x8f || buf[i] > 0xf4 // > U+10FFFF
3286
- ) {
3287
- return false;
3288
- }
3289
-
3290
- i += 4;
3291
- } else {
3292
- return false;
3293
- }
3294
- }
3295
-
3296
- return true;
3297
- }
3298
-
3299
- fallback = isValidUTF8;
3300
- return fallback;
3301
- }
3302
-
3303
- var hasRequiredUtf8Validate;
3304
-
3305
- function requireUtf8Validate () {
3306
- if (hasRequiredUtf8Validate) return utf8Validate.exports;
3307
- hasRequiredUtf8Validate = 1;
3308
-
3309
- try {
3310
- utf8Validate.exports = requireNodeGypBuild()(__dirname);
3311
- } catch (e) {
3312
- utf8Validate.exports = requireFallback();
3313
- }
3314
- return utf8Validate.exports;
3315
- }
3316
-
3317
2951
  var hasRequiredValidation;
3318
2952
 
3319
2953
  function requireValidation () {
@@ -3461,7 +3095,7 @@ function requireValidation () {
3461
3095
  };
3462
3096
  } /* istanbul ignore else */ else if (!process.env.WS_NO_UTF_8_VALIDATE) {
3463
3097
  try {
3464
- const isValidUTF8 = requireUtf8Validate();
3098
+ const isValidUTF8 = require('utf-8-validate');
3465
3099
 
3466
3100
  validation.exports.isValidUTF8 = function (buf) {
3467
3101
  return buf.length < 32 ? _isValidUTF8(buf) : isValidUTF8(buf);
@@ -4237,7 +3871,7 @@ function requireSender () {
4237
3871
  const { randomFillSync } = require$$1;
4238
3872
  const {
4239
3873
  types: { isUint8Array }
4240
- } = require$$2$1;
3874
+ } = require$$2;
4241
3875
 
4242
3876
  const PerMessageDeflate = requirePermessageDeflate();
4243
3877
  const { EMPTY_BUFFER, kWebSocket, NOOP } = requireConstants();
@@ -5361,7 +4995,7 @@ function requireWebsocket () {
5361
4995
 
5362
4996
  const EventEmitter = require$$0$3;
5363
4997
  const https = require$$1$1;
5364
- const http = require$$2$2;
4998
+ const http = require$$2$1;
5365
4999
  const net$1 = net;
5366
5000
  const tls = require$$4;
5367
5001
  const { randomBytes, createHash } = require$$1;
@@ -7030,7 +6664,7 @@ function requireWebsocketServer () {
7030
6664
  hasRequiredWebsocketServer = 1;
7031
6665
 
7032
6666
  const EventEmitter = require$$0$3;
7033
- const http = require$$2$2;
6667
+ const http = require$$2$1;
7034
6668
  const { Duplex } = require$$0$2;
7035
6669
  const { createHash } = require$$1;
7036
6670
 
@@ -8697,7 +8331,7 @@ class Manager {
8697
8331
  }
8698
8332
 
8699
8333
  this.remotes.delete(remote);
8700
- this.cid2remote.delete(remote.cid);
8334
+ if (this.cid2remote.get(remote.cid) === remote) this.cid2remote.delete(remote.cid);
8701
8335
  remote = null;
8702
8336
 
8703
8337
  }
@@ -8727,6 +8361,7 @@ class Manager {
8727
8361
  let tagLen = buffer.readUint8(1);
8728
8362
  let newTagBuf = encoder.encode(newTag);
8729
8363
  let newTagLen = newTagBuf.byteLength;
8364
+ if (newTagLen > SIZE_LIMIT.TAG_LEN1) return null;
8730
8365
  let payloadCunk = buffer.subarray(2 + tagLen);
8731
8366
  let newBuffer = Buffer.concat([Buffer.from([msgType, newTagLen]), newTagBuf, payloadCunk]);
8732
8367
  return newBuffer
@@ -8764,6 +8399,7 @@ class Manager {
8764
8399
  }
8765
8400
 
8766
8401
  sender(tag, remote, message) {
8402
+ if (encoder.encode(tag).byteLength > SIZE_LIMIT.TAG_LEN1) return ['err', 'Tag exceeds 255 UTF-8 bytes']
8767
8403
  if (serverOption.membersOnly && !remote.boho.isAuthorized) {
8768
8404
  // console.log("### server reject client signal reason: [membersOnly]" ,tag, remote.cid )
8769
8405
  remote.send(Buffer.from([IOMsg.AUTH_CLEAR]));
@@ -8780,6 +8416,7 @@ class Manager {
8780
8416
  // modify signalpack with cid_appneded tag.
8781
8417
  tag = remote.cid + tag;
8782
8418
  message = this.getNewSignalTagMessage(message, tag);
8419
+ if (!message) return ['err', 'CID-prefixed tag exceeds 255 UTF-8 bytes']
8783
8420
 
8784
8421
  } else if (cidIndex > 0) {
8785
8422
  // uni-cast.
@@ -8789,6 +8426,7 @@ class Manager {
8789
8426
  let ommitCIdTag = '@' + tag.split('@')[1];
8790
8427
  // console.log('uni-cast tag change from', tag, 'to' , ommitCIdTag )
8791
8428
  message = this.getNewSignalTagMessage(message, ommitCIdTag);
8429
+ if (!message) return ['err', 'Tag exceeds 255 UTF-8 bytes']
8792
8430
  // console.log(`origin tag: ${tag} omitTag: ${this.getSignalTag(message)}`)
8793
8431
  this.cid2remote.get(targetCId).send_enc_mode(message);
8794
8432
  return ['ok', 1]
@@ -9265,6 +8903,7 @@ class BohoAuth {
9265
8903
  }
9266
8904
 
9267
8905
  send_auth_fail(peer, reason) {
8906
+ peer.boho.isAuthorized = false;
9268
8907
  if (this.authLogger) {
9269
8908
  let peerInfo = `FAIL #${peer.ssid} reason:${reason} `;
9270
8909
  this.authLogger.log(peerInfo);
@@ -9342,6 +8981,7 @@ class BohoAuth {
9342
8981
  $$1.MB('#reason', 'duplicate login.')
9343
8982
  );
9344
8983
  if (this.keepOldConnection) { // default true
8984
+ peer.boho.isAuthorized = false;
9345
8985
  // keep old connection. reject new connection by sending auth_fail signal.
9346
8986
  // peer.send(authClearSignal)
9347
8987
  if( peer.socketType == 'websocket'){
@@ -9352,9 +8992,9 @@ class BohoAuth {
9352
8992
  } else {
9353
8993
  // accept new connection. stop the old connection by sending auth_clear signal.
9354
8994
  old.send(authClearSignal);
9355
- peer.close();
8995
+ old.close();
9356
8996
  }
9357
- return
8997
+ if (this.keepOldConnection) return
9358
8998
  }
9359
8999
 
9360
9000
  //6. delete current (or anonymouse)cid if exist.