@hive-p2p/server 1.0.53 → 1.0.55

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/core/arbiter.mjs CHANGED
@@ -84,8 +84,8 @@ export class Arbiter {
84
84
  /** Call from HiveP2P module only! @param {string} from @param {any} message @param {Uint8Array} serialized @param {number} [powCheckFactor] default: 0.01 (1%) */
85
85
  async digestMessage(from, message, serialized, powCheckFactor = .01) {
86
86
  const { senderId, pubkey, topic, expectedEnd } = message; // avoid powControl() on banished peers
87
- this.#signatureControl(from, message, serialized);
88
- if (!this.#lengthControl(topic ? 'gossip' : 'unicast', serialized, expectedEnd)) return;
87
+ if (!this.#signatureControl(from, message, serialized)) return;
88
+ if (!this.#lengthControl(from, topic ? 'gossip' : 'unicast', serialized, expectedEnd)) return;
89
89
 
90
90
  if (topic) this.#hopsControl(from, message);
91
91
  else this.#routeLengthControl(from, message);
@@ -93,9 +93,10 @@ export class Arbiter {
93
93
  if (this.isBanished(from) || this.isBanished(senderId)) return;
94
94
  if (this.trustBalances[senderId] > TRUST_VALUES.VALID_POW) return;
95
95
  if (Math.random() < powCheckFactor) await this.#powControl(senderId, pubkey);
96
+ return true;
96
97
  }
97
- /** @param {'gossip' | 'unicast'} type */
98
- #lengthControl(type, serialized, expectedEnd) {
98
+ /** @param {string} from @param {'gossip' | 'unicast'} type */
99
+ #lengthControl(from, type, serialized, expectedEnd) {
99
100
  if (!expectedEnd || serialized.length === expectedEnd) return true;
100
101
  this.adjustTrust(from, TRUST_VALUES.WRONG_LENGTH, `${type} message length mismatch`);
101
102
  }
@@ -105,9 +106,11 @@ export class Arbiter {
105
106
  const { pubkey, signature, signatureStart } = message;
106
107
  const signedData = serialized.subarray(0, signatureStart);
107
108
  const signatureValid = this.cryptoCodex.verifySignature(pubkey, signature, signedData);
108
- if (signatureValid) return this.adjustTrust(from, TRUST_VALUES.VALID_SIGNATURE, 'Gossip signature valid');
109
+ if (!signatureValid) throw new Error('Gossip signature invalid');
110
+ this.adjustTrust(from, TRUST_VALUES.VALID_SIGNATURE, 'Gossip signature valid');
111
+ return true;
109
112
  } catch (error) {
110
- if (this.verbose > 1) console.error(`%c(Arbiter: ${this.id}) Error during signature verification from ${from}:`, LOG_CSS.ARBITER, error);
113
+ if (this.verbose > 1) console.error(`%c(Arbiter: ${this.id}) Error during signature verification from ${from}: ${error.stack}`, LOG_CSS.ARBITER);
111
114
  if (this.verbose > 2) console.log(`%c(Arbiter) signatureControl() error details: ${message}`, LOG_CSS.ARBITER);
112
115
  }
113
116
  this.adjustTrust(from, TRUST_VALUES.WRONG_SIGNATURE, 'Gossip signature invalid');
package/core/gossip.mjs CHANGED
@@ -131,7 +131,8 @@ export class Gossip {
131
131
 
132
132
  const message = this.cryptoCodex.readGossipMessage(serialized);
133
133
  if (!message) return this.arbiter.countPeerAction(from, 'WRONG_SERIALIZATION');
134
- await this.arbiter.digestMessage(from, message, serialized);
134
+ const isOk = await this.arbiter.digestMessage(from, message, serialized);
135
+ if (!isOk) return; // invalid message or from banished peer
135
136
  if (this.arbiter.isBanished(from)) return; // ignore messages from banished peers
136
137
  if (this.arbiter.isBanished(message.senderId)) return; // ignore messages from banished peers
137
138
 
package/core/node.mjs CHANGED
@@ -211,4 +211,13 @@ export class Node {
211
211
  /** Triggered when a new signal answer is received from another peer.
212
212
  * @param {function} callback can use arguments: (senderId:string, data:SignalData) */
213
213
  onSignalAnswer(callback) { this.messager.on('signal_answer', callback); }
214
+
215
+ /** Kick a peer. @param {string} peerId @param {string} [reason] */
216
+ kickPeer(peerId, reason = 'kicked_by_node') { this.peerStore.kickPeer(peerId, 0, reason); }
217
+
218
+ /** Ban a peer for a certain duration (ms). @param {string} peerId @param {number} [duration] default: 60_000ms @param {string} [reason] */
219
+ banPeer(peerId, duration = 60_000, reason = 'banished_by_node') {
220
+ this.arbiter.trustBalances[peerId] = 0; // reset trust balance
221
+ this.arbiter.adjustTrust(peerId, -duration, reason);
222
+ }
214
223
  }
@@ -219,8 +219,8 @@ export class PeerStore { // Manages all peers informations and connections (WebS
219
219
  this.connecting[remoteId][direction] = new PeerConnection(remoteId, instance, direction);
220
220
  return true;
221
221
  }
222
- /** @param {string} remoteId @param {{type: 'offer' | 'answer', sdp: Record<string, string>}} signal @param {string} [offerHash] answer only @param {number} timestamp Answer reception timestamp */
223
- assignSignal(remoteId, signal, offerHash, timestamp) {
222
+ /** @param {string} remoteId @param {{type: 'offer' | 'answer', sdp: Record<string, string>}} signal @param {string} [offerHash] answer only @param {number} [timestamp] Answer reception timestamp */
223
+ assignSignal(remoteId, signal, offerHash, timestamp = CLOCK.time) {
224
224
  const peerConn = this.connecting[remoteId]?.[signal.type === 'offer' ? 'in' : 'out'];
225
225
  try {
226
226
  if (peerConn?.isWebSocket) throw new Error(`Cannot assign signal for ID ${remoteId}. (WebSocket)`);
package/core/unicast.mjs CHANGED
@@ -114,7 +114,8 @@ export class UnicastMessager {
114
114
 
115
115
  const message = this.cryptoCodex.readUnicastMessage(serialized);
116
116
  if (!message) return this.arbiter.countPeerAction(from, 'WRONG_SERIALIZATION');
117
- await this.arbiter.digestMessage(from, message, serialized);
117
+ const isOk = await this.arbiter.digestMessage(from, message, serialized);
118
+ if (!isOk) return; // invalid message or from banished peer
118
119
  if (this.arbiter.isBanished(from)) return; // ignore messages from banished peers
119
120
  if (this.arbiter.isBanished(message.senderId)) return; // ignore messages from banished peers
120
121
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hive-p2p/server",
3
- "version": "1.0.53",
3
+ "version": "1.0.55",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -3,8 +3,8 @@ const IS_BROWSER = typeof window !== 'undefined';
3
3
 
4
4
  // ED25519 EXPOSURE NODEJS/BROWSER COMPATIBLE ---------------------------------
5
5
  const [ed_, {sha512}] = await Promise.all([
6
- import(IS_BROWSER ? '../libs/ed25519-custom.js' : '@noble/ed25519'),
7
- import(IS_BROWSER ? '../libs/ed25519-custom.js' : '@noble/hashes/sha2.js')
6
+ import(IS_BROWSER ? '../libs/ed25519-custom.min.js' : '@noble/ed25519'),
7
+ import(IS_BROWSER ? '../libs/ed25519-custom.min.js' : '@noble/hashes/sha2.js')
8
8
  ]);
9
9
  /** @type {import('@noble/ed25519')} */
10
10
  const ed25519 = ed_.default || ed_;