@hive-p2p/server 1.0.59 → 1.0.61

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
@@ -1,5 +1,5 @@
1
1
  import { CLOCK } from '../services/clock.mjs';
2
- import { GOSSIP, UNICAST, LOG_CSS } from './config.mjs';
2
+ import { NODE, GOSSIP, UNICAST, LOG_CSS } from './config.mjs';
3
3
 
4
4
  // TRUST_BALANCE = seconds of ban if negative - never exceed MAX_TRUST if positive
5
5
  // Growing each second by 1000ms until 0
@@ -38,6 +38,7 @@ export class Arbiter {
38
38
  * - trustBalance = milliseconds of ban if negative
39
39
  * @type {Record<string, number>} */
40
40
  trustBalances = {};
41
+ manualBanList = new Set();
41
42
  bytesCounters = { gossip: {}, unicast: {} };
42
43
  bytesCounterResetIn = 0;
43
44
 
@@ -73,7 +74,15 @@ export class Arbiter {
73
74
  if (delta && this.verbose > 3) console.log(`%c(Arbiter: ${this.id}) ${peerId} +${delta}ms (${reason}). Updated: ${this.trustBalances[peerId]}ms.`, LOG_CSS.ARBITER);
74
75
  if (this.isBanished(peerId) && this.verbose > 1) console.log(`%c(Arbiter: ${this.id}) Peer ${peerId} is now banished.`, LOG_CSS.ARBITER);
75
76
  }
76
- isBanished(peerId = 'toto') { return (this.trustBalances[peerId] || 0) < 0; }
77
+ /** MANUAL BAN (if enabled) @param {string} peerId */
78
+ setBanished(peerId) {
79
+ if (!this.manualBanList.has(peerId)) this.manualBanList.add(peerId);
80
+ }
81
+ /** Check if a peer is banished | based on trustBalances or manualBanList @param {string} peerId */
82
+ isBanished(peerId) {
83
+ if (!NODE.MANUAL_BAN_MODE) return (this.trustBalances[peerId] || 0) < 0;
84
+ else return this.manualBanList.has(peerId);
85
+ }
77
86
 
78
87
  // MESSAGE VERIFICATION
79
88
  /** @param {string} peerId @param {number} byteLength @param {'gossip' | 'unicast'} type */
@@ -90,7 +99,7 @@ export class Arbiter {
90
99
  /** Call from HiveP2P module only! @param {string} from @param {any} message @param {Uint8Array} serialized @param {number} [powCheckFactor] default: 0.01 (1%) */
91
100
  async digestMessage(from, message, serialized, powCheckFactor = .01) {
92
101
  const { senderId, pubkey, topic, expectedEnd } = message; // avoid powControl() on banished peers
93
- if (!this.#signatureControl(from, message, serialized)) return;
102
+ if (!await this.#signatureControl(from, message, serialized)) return;
94
103
  if (!this.#lengthControl(from, topic ? 'gossip' : 'unicast', serialized, expectedEnd)) return;
95
104
 
96
105
  const routeOrHopsOk = topic ? this.#hopsControl(from, message) : this.#routeLengthControl(from, message);
@@ -102,11 +111,11 @@ export class Arbiter {
102
111
  return true;
103
112
  }
104
113
  /** @param {string} from @param {import('./gossip.mjs').GossipMessage} message @param {Uint8Array} serialized */
105
- #signatureControl(from, message, serialized) {
114
+ async #signatureControl(from, message, serialized) {
106
115
  try {
107
116
  const { pubkey, signature, signatureStart } = message;
108
117
  const signedData = serialized.subarray(0, signatureStart);
109
- const signatureValid = this.cryptoCodex.verifySignature(pubkey, signature, signedData);
118
+ const signatureValid = await this.cryptoCodex.verifySignature(pubkey, signature, signedData);
110
119
  if (!signatureValid) throw new Error('Gossip signature invalid');
111
120
  this.adjustTrust(from, TRUST_VALUES.VALID_SIGNATURE, 'Gossip signature valid');
112
121
  return true;
package/core/config.mjs CHANGED
@@ -50,6 +50,8 @@ export const NODE = {
50
50
  CONNECTION_UPGRADE_TIMEOUT: 15_000,
51
51
  /** Flag to indicate if we are running in a browser environment | DON'T MODIFY THIS VALUE */
52
52
  IS_BROWSER: isNode ? false : true,
53
+ /** Enable manual banning of peers through the Arbiter module | Default: false (useful for consensus based ban, arbiter.trustBalances remain accessible) */
54
+ MANUAL_BAN_MODE: false
53
55
  }
54
56
 
55
57
  export const SERVICE = {
@@ -168,9 +168,9 @@ export class CryptoCodex {
168
168
 
169
169
  // MESSSAGE READING (DESERIALIZATION AND SIGNATURE VERIFICATION INCLUDED)
170
170
  /** @param {Uint8Array} publicKey @param {Uint8Array} dataToVerify @param {Uint8Array} signature */
171
- verifySignature(publicKey, dataToVerify, signature) {
171
+ async verifySignature(publicKey, dataToVerify, signature) {
172
172
  if (this.AVOID_CRYPTO) return true;
173
- return ed25519.verify(dataToVerify, signature, publicKey);
173
+ return ed25519.verifyAsync(dataToVerify, signature, publicKey);
174
174
  }
175
175
  /** @param {Uint8Array} bufferView */
176
176
  readBufferHeader(bufferView, readAssociatedId = true) {
@@ -56,7 +56,7 @@ export class NodeServices {
56
56
  ws.on('error', (error) => console.error(`WebSocket error on Node #${this.id} with peer ${remoteId}:`, error.stack));
57
57
 
58
58
  let remoteId;
59
- ws.on('message', (data) => { // When peer proves his id, we can handle data normally
59
+ ws.on('message', async (data) => { // When peer proves his id, we can handle data normally
60
60
  if (remoteId) for (const cb of this.peerStore.callbacks.data) cb(remoteId, data);
61
61
  else { // FIRST MESSAGE SHOULD BE HANDSHAKE WITH ID
62
62
  const d = new Uint8Array(data); if (d[0] > 127) return; // not unicast, ignore
@@ -68,7 +68,7 @@ export class NodeServices {
68
68
 
69
69
  const { signatureStart, pubkey, signature } = message;
70
70
  const signedData = d.subarray(0, signatureStart);
71
- if (!this.cryptoCodex.verifySignature(pubkey, signature, signedData)) return;
71
+ if (!await this.cryptoCodex.verifySignature(pubkey, signature, signedData)) return;
72
72
 
73
73
  remoteId = route[0];
74
74
  this.peerStore.digestPeerNeighbors(remoteId, neighborsList); // Update known store
@@ -175,7 +175,7 @@ export class Topologist {
175
175
  this.bootstrapsConnectionState.set(publicUrl, false);
176
176
  for (const cb of this.peerStore.callbacks.disconnect) cb(remoteId, 'out');
177
177
  }
178
- ws.onmessage = (data) => {
178
+ ws.onmessage = async (data) => {
179
179
  if (remoteId) for (const cb of this.peerStore.callbacks.data) cb(remoteId, data.data);
180
180
  else { // FIRST MESSAGE SHOULD BE HANDSHAKE WITH ID
181
181
  const d = new Uint8Array(data.data); if (d[0] > 127) return; // not unicast, ignore
@@ -187,7 +187,7 @@ export class Topologist {
187
187
 
188
188
  const { signatureStart, pubkey, signature } = message;
189
189
  const signedData = d.subarray(0, signatureStart);
190
- if (!this.cryptoCodex.verifySignature(pubkey, signature, signedData)) return;
190
+ if (!await this.cryptoCodex.verifySignature(pubkey, signature, signedData)) return;
191
191
 
192
192
  remoteId = route[0];
193
193
  this.peerStore.digestPeerNeighbors(remoteId, neighborsList); // Update known store
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hive-p2p/server",
3
- "version": "1.0.59",
3
+ "version": "1.0.61",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },