@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 +14 -5
- package/core/config.mjs +2 -0
- package/core/crypto-codex.mjs +2 -2
- package/core/node-services.mjs +2 -2
- package/core/topologist.mjs +2 -2
- package/package.json +1 -1
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
|
-
|
|
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 = {
|
package/core/crypto-codex.mjs
CHANGED
|
@@ -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.
|
|
173
|
+
return ed25519.verifyAsync(dataToVerify, signature, publicKey);
|
|
174
174
|
}
|
|
175
175
|
/** @param {Uint8Array} bufferView */
|
|
176
176
|
readBufferHeader(bufferView, readAssociatedId = true) {
|
package/core/node-services.mjs
CHANGED
|
@@ -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
|
package/core/topologist.mjs
CHANGED
|
@@ -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
|