diff --git a/package-lock.json b/package-lock.json index 3bb9a0662..f269e7d02 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "polykey", - "version": "1.16.2", + "version": "1.16.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "polykey", - "version": "1.16.2", + "version": "1.16.3", "license": "GPL-3.0", "dependencies": { "@matrixai/async-cancellable": "^1.1.1", diff --git a/package.json b/package.json index 0cc1c5329..e80dfd576 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "polykey", - "version": "1.16.2", + "version": "1.16.3", "homepage": "https://polykey.com", "author": "Matrix AI", "contributors": [ diff --git a/src/PolykeyAgent.ts b/src/PolykeyAgent.ts index 9848bc7cb..b64a30b5d 100644 --- a/src/PolykeyAgent.ts +++ b/src/PolykeyAgent.ts @@ -806,7 +806,7 @@ class PolykeyAgent { if (nodeId == null) { utils.never(`failed to decode NodeId "${nodeIdEncoded}"`); } - const setNodeProm = this.nodeManager.setNode( + const setNodeP = this.nodeManager.setNode( nodeId, optionsDefaulted.seedNodes[nodeIdEncoded], { @@ -816,7 +816,7 @@ class PolykeyAgent { }, true, ); - setNodeProms.push(setNodeProm); + setNodeProms.push(setNodeP); } await Promise.all(setNodeProms); await this.nodeGraph.start({ fresh }); diff --git a/src/audit/Audit.ts b/src/audit/Audit.ts index 5fb0b863d..4ec611ab0 100644 --- a/src/audit/Audit.ts +++ b/src/audit/Audit.ts @@ -177,7 +177,7 @@ class Audit { promise.cancel(new auditErrors.ErrorAuditNotRunning()); } } - await Promise.all([...this.taskPromises]).catch(() => {}); + await Promise.allSettled([...this.taskPromises]); this.logger.info(`Stopped ${this.constructor.name}`); } @@ -333,6 +333,7 @@ class Audit { resolveBlockP = resolveP; blockPSignal = signal; }); + void blockP.catch(() => {}); this.taskPromises.add(blockP); const iterator = this.getAuditEvents(topicPath, { diff --git a/src/identities/IdentitiesManager.ts b/src/identities/IdentitiesManager.ts index 1f8c6d5f3..831c14d69 100644 --- a/src/identities/IdentitiesManager.ts +++ b/src/identities/IdentitiesManager.ts @@ -265,7 +265,8 @@ class IdentitiesManager { ); } // Create identity claim on our node - const publishedClaimProm = promise(); + const { p: publishedClaimP, resolveP: publishedClaimResolveP } = + promise(); await this.db.withTransactionF((tran) => this.sigchain.addClaim( { @@ -281,7 +282,7 @@ class IdentitiesManager { identityId, claim, ); - publishedClaimProm.resolveP(identitySignedClaim); + publishedClaimResolveP(identitySignedClaim); // Append the ProviderIdentityClaimId to the token const payload: ClaimLinkIdentity = { ...claim.payload, @@ -294,7 +295,7 @@ class IdentitiesManager { tran, ), ); - const publishedClaim = await publishedClaimProm.p; + const publishedClaim = await publishedClaimP; // Publish claim on identity const issNodeInfo = { nodeId: this.keyRing.getNodeId(), diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index bc24ab83b..17307cd03 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -571,25 +571,25 @@ class NodeConnectionManager { ); this.quicSocket.removeEventListener(EventAll.name, this.handleEventAll); - const destroyProms: Array> = []; + const destroyPs: Array> = []; for (const [nodeId] of this.connections) { // It exists so we want to destroy it - const destroyProm = this.destroyConnection( + const destroyP = this.destroyConnection( IdInternal.fromString(nodeId), force, ); - destroyProms.push(destroyProm); + destroyPs.push(destroyP); } - await Promise.all(destroyProms); - const signallingProms: Array | Promise> = []; + await Promise.all(destroyPs); + const signallingPs: Array | Promise> = []; for (const [, activePunch] of this.activeHolePunchPs) { - signallingProms.push(activePunch); + signallingPs.push(activePunch); activePunch.cancel(); } for (const activeSignal of this.activeSignalFinalPs) { - signallingProms.push(activeSignal); + signallingPs.push(activeSignal); } - await Promise.allSettled(signallingProms); + await Promise.allSettled(signallingPs); await this.quicServer.stop({ force: true }); await this.quicSocket.stop({ force: true }); await this.rpcServer.stop({ force: true }); @@ -1113,13 +1113,13 @@ class NodeConnectionManager { ): Promise { // We need to send a random data packet to the target until the process times out or a connection is established let ended = false; - const endedProm = utils.promise(); + const { p: endedP, resolveP: endedResolveP } = utils.promise(); if (ctx.signal.aborted) { - endedProm.resolveP(); + endedResolveP(); } const onAbort = () => { ended = true; - endedProm.resolveP(); + endedResolveP(); ctx.signal.removeEventListener('abort', onAbort); }; ctx.signal.addEventListener('abort', onAbort); @@ -1134,7 +1134,7 @@ class NodeConnectionManager { await this.quicSocket .send(Buffer.from(message), port, host) .catch(() => {}); - await Promise.race([utils.sleep(delay), endedProm.p]); + await Promise.race([utils.sleep(delay), endedP]); if (ended) break; delay *= 2; } @@ -1243,6 +1243,8 @@ class NodeConnectionManager { }); }, ); + // Prevent promise rejection leak + void holePunchAttempt.catch(() => {}); this.activeHolePunchPs.set(id, holePunchAttempt); } @@ -1299,7 +1301,7 @@ class NodeConnectionManager { this.keyRing.keyPair, data, ); - const connProm = this.withConnF(targetNodeId, async (conn) => { + const connectionSignalP = this.withConnF(targetNodeId, async (conn) => { const client = conn.getClient(); await client.methods.nodesConnectionSignalFinal({ sourceNodeIdEncoded: nodesUtils.encodeNodeId(sourceNodeId), @@ -1325,9 +1327,11 @@ class NodeConnectionManager { }, ) .finally(() => { - this.activeSignalFinalPs.delete(connProm); + this.activeSignalFinalPs.delete(connectionSignalP); }); - this.activeSignalFinalPs.add(connProm); + // Preventing promise rejection leak. + connectionSignalP.catch(() => {}); + this.activeSignalFinalPs.add(connectionSignalP); return { host, port, diff --git a/src/nodes/NodeConnectionQueue.ts b/src/nodes/NodeConnectionQueue.ts index 13b9af896..d82fb137f 100644 --- a/src/nodes/NodeConnectionQueue.ts +++ b/src/nodes/NodeConnectionQueue.ts @@ -189,6 +189,7 @@ export class NodeConnectionQueue { ctx: ContextCancellable, ): Promise { const abortP = utils.signalPromise(ctx.signal); + void abortP.catch(() => {}); try { while ( !this.connectionMade && diff --git a/src/nodes/NodeManager.ts b/src/nodes/NodeManager.ts index 8d7e72063..9287bf1e5 100644 --- a/src/nodes/NodeManager.ts +++ b/src/nodes/NodeManager.ts @@ -290,12 +290,12 @@ class NodeManager { const task = await this.updateRefreshBucketDelay(i, 0, false); refreshBuckets.push(task.promise()); } - const signalProm = utils.signalPromise(ctx.signal); - await Promise.race([Promise.all(refreshBuckets), signalProm]).finally( + const signalP = utils.signalPromise(ctx.signal); + await Promise.race([Promise.all(refreshBuckets), signalP]).finally( async () => { // Clean up signal promise when done - signalProm.cancel(); - await signalProm; + signalP.cancel(); + await signalP; }, ); }; @@ -1424,8 +1424,9 @@ class NodeManager { }; // Now we want to send our own claim signed - const halfSignedClaimProm = utils.promise(); - const claimProm = this.sigchain.addClaim( + const { p: halfSignedClaimP, resolveP: halfSignedClaimResolveP } = + utils.promise(); + const claimP = this.sigchain.addClaim( { typ: 'ClaimLinkNode', iss: nodesUtils.encodeNodeId(requestingNodeId), @@ -1436,7 +1437,7 @@ class NodeManager { const halfSignedClaim = token.toSigned(); const halfSignedClaimEncoded = claimsUtils.generateSignedClaim(halfSignedClaim); - halfSignedClaimProm.resolveP(halfSignedClaimEncoded); + halfSignedClaimResolveP(halfSignedClaimEncoded); const readStatus = await input.next(); if (readStatus.done) { throw new claimsErrors.ErrorEmptyStream(); @@ -1462,10 +1463,11 @@ class NodeManager { return fullySignedToken; }, ); + void claimP.catch(() => {}); yield { - signedTokenEncoded: await halfSignedClaimProm.p, + signedTokenEncoded: await halfSignedClaimP, }; - const [, claim] = await claimProm; + const [, claim] = await claimP; // With the claim created we want to add it to the gestalt graph const issNodeInfo = { nodeId: requestingNodeId, diff --git a/src/nodes/utils.ts b/src/nodes/utils.ts index a7d382aad..712dc44ab 100644 --- a/src/nodes/utils.ts +++ b/src/nodes/utils.ts @@ -314,6 +314,7 @@ function generateRandomNodeIdForBucket( * This is generally used to check the connection has failed * before cleaning it up. */ +// FIXME: need to include ErrorQUICConnectionIdleTimeout error in this list. function isConnectionError(e): boolean { return ( e instanceof nodesErrors.ErrorNodeConnectionDestroyed || @@ -323,7 +324,8 @@ function isConnectionError(e): boolean { e instanceof quicErrors.ErrorQUICConnectionPeer || e instanceof quicErrors.ErrorQUICConnectionLocal || e instanceof quicErrors.ErrorQUICConnectionNotRunning || - e instanceof quicErrors.ErrorQUICConnectionStopping + e instanceof quicErrors.ErrorQUICConnectionStopping || + e instanceof quicErrors.ErrorQUICConnectionIdleTimeout ); }