@hive-p2p/server 1.0.52 → 1.0.54

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,19 +93,27 @@ 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
  }
102
103
  /** @param {string} from @param {import('./gossip.mjs').GossipMessage} message @param {Uint8Array} serialized */
103
104
  #signatureControl(from, message, serialized) {
104
- const { pubkey, signature, signatureStart } = message;
105
- const signedData = serialized.subarray(0, signatureStart);
106
- const signatureValid = this.cryptoCodex.verifySignature(pubkey, signature, signedData);
107
- if (signatureValid) this.adjustTrust(from, TRUST_VALUES.VALID_SIGNATURE, 'Gossip signature valid');
108
- else this.adjustTrust(from, TRUST_VALUES.WRONG_SIGNATURE, 'Gossip signature invalid');
105
+ try {
106
+ const { pubkey, signature, signatureStart } = message;
107
+ const signedData = serialized.subarray(0, signatureStart);
108
+ const signatureValid = this.cryptoCodex.verifySignature(pubkey, signature, signedData);
109
+ if (!signatureValid) throw new Error('Gossip signature invalid');
110
+ this.adjustTrust(from, TRUST_VALUES.VALID_SIGNATURE, 'Gossip signature valid');
111
+ return true;
112
+ } catch (error) {
113
+ if (this.verbose > 1) console.error(`%c(Arbiter: ${this.id}) Error during signature verification from ${from}: ${error.stack}`, LOG_CSS.ARBITER);
114
+ if (this.verbose > 2) console.log(`%c(Arbiter) signatureControl() error details: ${message}`, LOG_CSS.ARBITER);
115
+ }
116
+ this.adjustTrust(from, TRUST_VALUES.WRONG_SIGNATURE, 'Gossip signature invalid');
109
117
  }
110
118
  /** GOSSIP only @param {string} from @param {import('./gossip.mjs').GossipMessage} message */
111
119
  #hopsControl(from, message) {
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.52",
3
+ "version": "1.0.54",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },