@decentnetwork/peer 0.1.91 → 0.1.92
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/dist/peer.js +39 -1
- package/package.json +1 -1
package/dist/peer.js
CHANGED
|
@@ -1725,7 +1725,45 @@ export class Peer {
|
|
|
1725
1725
|
else {
|
|
1726
1726
|
this.#adoptRemote(state, remote.address, remote.port);
|
|
1727
1727
|
}
|
|
1728
|
-
|
|
1728
|
+
// CONVERGENCE RESYNC: the peer is retransmitting the SAME session pubkey
|
|
1729
|
+
// we already hold, so OUR view of the session looks fine. But if we've
|
|
1730
|
+
// been receiving crypto data from this peer we CANNOT decrypt, the peer
|
|
1731
|
+
// is holding a STALE copy of OUR session pubkey (it re-keyed, or we did,
|
|
1732
|
+
// and our reply handshake never reached it) — it encrypts to a key we no
|
|
1733
|
+
// longer have, so every data packet is "no session matched" and it keeps
|
|
1734
|
+
// retransmitting its handshake forever. Silently preserving deadlocks the
|
|
1735
|
+
// session PERMANENTLY (observed callpass↔mac: 11h, 20k undecryptable, IP
|
|
1736
|
+
// + messages both dead while presence shows "online"). Re-send our reply
|
|
1737
|
+
// handshake so the peer re-derives its shared key against our CURRENT
|
|
1738
|
+
// session pubkey. Rate-limited (peer retransmits ~1/s); a healthy session
|
|
1739
|
+
// never sets undecryptableRecvMs, so this can NEVER churn a working one.
|
|
1740
|
+
const now = Date.now();
|
|
1741
|
+
const peerSendingUndecryptable = state.undecryptableRecvMs !== undefined &&
|
|
1742
|
+
now - state.undecryptableRecvMs < FRIEND_TIMEOUT_MS;
|
|
1743
|
+
const resyncDue = now - (state.lastResyncHandshakeMs ?? 0) > 2000;
|
|
1744
|
+
if (peerSendingUndecryptable && resyncDue) {
|
|
1745
|
+
state.lastResyncHandshakeMs = now;
|
|
1746
|
+
state.lastPingRecvMs = now;
|
|
1747
|
+
const reply = createCryptoHandshake({
|
|
1748
|
+
recipientCookie: hs.embeddedCookie,
|
|
1749
|
+
baseNonce: state.ourBaseNonce,
|
|
1750
|
+
sessionPublicKey: state.ourSessionKeyPair.publicKey,
|
|
1751
|
+
senderRealSecretKey: this.#keyPair.secretKey,
|
|
1752
|
+
senderRealPublicKey: this.#keyPair.publicKey,
|
|
1753
|
+
senderDhtPublicKey: this.#keyPair.publicKey,
|
|
1754
|
+
receiverRealPublicKey: hs.senderRealPublicKey,
|
|
1755
|
+
receiverDhtPublicKey: hs.senderDhtPublicKey,
|
|
1756
|
+
localCookieSymmetricKey: this.#cookieSymmetricKey
|
|
1757
|
+
});
|
|
1758
|
+
const sendResync = () => this.#remoteIsTcp(remote)
|
|
1759
|
+
? Promise.resolve(this.#tcpRelays?.sendOobToFriend(hs.senderDhtPublicKey, reply) ?? 0)
|
|
1760
|
+
: this.#sendPacket(reply, { host: remote.address, port: remote.port });
|
|
1761
|
+
void sendResync()
|
|
1762
|
+
.then(() => this.#debugLog(`hs_recv duplicate but peer sent undecryptable data — re-sent our handshake to resync friend=${friendId}`))
|
|
1763
|
+
.catch((error) => this.#debugLog(`resync handshake failed for ${friendId}: ${error.message}`));
|
|
1764
|
+
return;
|
|
1765
|
+
}
|
|
1766
|
+
state.lastPingRecvMs = now;
|
|
1729
1767
|
this.#debugVerboseLog(`hs_recv duplicate friend=${friendId} remote=${remote.address}:${remote.port} (session preserved)`);
|
|
1730
1768
|
return;
|
|
1731
1769
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decentnetwork/peer",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.92",
|
|
4
4
|
"description": "Pure TypeScript port of Elastos Carrier (toxcore-derived) P2P messaging. DHT, onion routing, TCP relay, FlatBuffers app payloads, Express offline relay. Wire-compatible with iOS Beagle and the Carrier C SDK.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|