@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 +17 -9
- package/core/gossip.mjs +2 -1
- package/core/node.mjs +9 -0
- package/core/peer-store.mjs +2 -2
- package/core/unicast.mjs +2 -1
- package/package.json +1 -1
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
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
}
|
package/core/peer-store.mjs
CHANGED
|
@@ -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
|
|