diff --git a/package-lock.json b/package-lock.json index 6d6806a1f..3c5012f63 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "polykey", - "version": "1.21.2", + "version": "1.21.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "polykey", - "version": "1.21.2", + "version": "1.21.3", "license": "GPL-3.0", "dependencies": { "@matrixai/async-cancellable": "^1.1.1", diff --git a/package.json b/package.json index 692d73bdb..2224e37e7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "polykey", - "version": "1.21.2", + "version": "1.21.3", "homepage": "https://polykey.com", "author": "Matrix AI", "contributors": [ diff --git a/src/nodes/NodeConnectionManager.ts b/src/nodes/NodeConnectionManager.ts index fd43bd79a..2d426009a 100644 --- a/src/nodes/NodeConnectionManager.ts +++ b/src/nodes/NodeConnectionManager.ts @@ -1525,11 +1525,23 @@ class NodeConnectionManager { }> { // Need to get the connection details of the requester and add it to the message. // Then send the message to the target. - // This would only function with existing connections - const existingConnection = this.getConnection(targetNodeId); + // This would only function with existing connections that are authenticated + const nodeIdString = targetNodeId.toString() as NodeIdString; + const connectionsEntry = this.connections.get(nodeIdString); + if (connectionsEntry == null) { + throw new nodesErrors.ErrorNodeConnectionManagerConnectionNotFound(); + } + const existingConnection = + connectionsEntry.connections[connectionsEntry.activeConnection]; if (existingConnection == null) { throw new nodesErrors.ErrorNodeConnectionManagerConnectionNotFound(); } + if (connectionsEntry.authenticatedForward !== AuthenticatingState.SUCCESS) { + throw new nodesErrors.ErrorNodeConnectionManagerConnectionNotFound(); + } + if (connectionsEntry.authenticatedReverse !== AuthenticatingState.SUCCESS) { + throw new nodesErrors.ErrorNodeConnectionManagerConnectionNotFound(); + } const host = existingConnection.connection.host; const port = existingConnection.connection.port; // Do other checks. @@ -1598,7 +1610,17 @@ class NodeConnectionManager { limit: number = this.connectionGetClosestLimit, ): Array { const nodeIds: Array = []; - for (const nodeIdString of this.connections.keys()) { + for (const [nodeIdString, connectionsEntry] of this.connections.entries()) { + if ( + connectionsEntry.authenticatedForward !== AuthenticatingState.SUCCESS + ) { + continue; + } + if ( + connectionsEntry.authenticatedReverse !== AuthenticatingState.SUCCESS + ) { + continue; + } nodeIds.push(IdInternal.fromString(nodeIdString)); } // Sort and draw limit diff --git a/tests/nodes/NodeConnectionManager.test.ts b/tests/nodes/NodeConnectionManager.test.ts index c49c80608..7334ce2c5 100644 --- a/tests/nodes/NodeConnectionManager.test.ts +++ b/tests/nodes/NodeConnectionManager.test.ts @@ -58,7 +58,7 @@ describe(`${NodeConnectionManager.name}`, () => { ); const localHost = '127.0.0.1' as Host; const dummyManifest = {} as AgentServerManifest; - const timeoutTime = 2000; + const timeoutTime = 5000; test('NodeConnectionManager readiness', async () => { const keyPair = keysUtils.generateKeyPair(); @@ -1080,11 +1080,13 @@ describe(`${NodeConnectionManager.name}`, () => { localHost, ncmPeer1.port, ); + await ncmLocal.nodeConnectionManager.isAuthenticatedP(ncmPeer1.nodeId); await ncmPeer1.nodeConnectionManager.createConnection( [ncmPeer2.nodeId], localHost, ncmPeer2.port, ); + await ncmPeer1.nodeConnectionManager.isAuthenticatedP(ncmPeer2.nodeId); // Should be able to create connection from local to peer2 using peer1 as signaller await ncmLocal.nodeConnectionManager.createConnectionPunch( @@ -1113,6 +1115,7 @@ describe(`${NodeConnectionManager.name}`, () => { localHost, ncmPeer1.port, ); + await ncmLocal.nodeConnectionManager.isAuthenticatedP(ncmPeer1.nodeId); // Can't signal without signaler connected await testsUtils.expectRemoteError( ncmLocal.nodeConnectionManager.createConnectionPunch( @@ -1129,11 +1132,13 @@ describe(`${NodeConnectionManager.name}`, () => { localHost, ncmPeer1.port, ); + await ncmLocal.nodeConnectionManager.isAuthenticatedP(ncmPeer1.nodeId); await ncmPeer1.nodeConnectionManager.createConnection( [ncmPeer2.nodeId], localHost, ncmPeer2.port, ); + await ncmPeer1.nodeConnectionManager.isAuthenticatedP(ncmPeer2.nodeId); const holePunchSpy = jest.spyOn( ncmPeer2.nodeConnectionManager, 'holePunch', @@ -1168,16 +1173,19 @@ describe(`${NodeConnectionManager.name}`, () => { localHost, ncmPeer1.port, ); + await ncmLocal.nodeConnectionManager.isAuthenticatedP(ncmPeer1.nodeId); await ncmLocal.nodeConnectionManager.createConnection( [ncmPeer1.nodeId], localHost, ncmPeer1.port, ); + await ncmLocal.nodeConnectionManager.isAuthenticatedP(ncmPeer1.nodeId); await ncmLocal.nodeConnectionManager.createConnection( [ncmPeer2.nodeId], localHost, ncmPeer2.port, ); + await ncmLocal.nodeConnectionManager.isAuthenticatedP(ncmPeer2.nodeId); const result = ncmLocal.nodeConnectionManager.getClosestConnections( ncmPeer2.nodeId, @@ -1193,11 +1201,13 @@ describe(`${NodeConnectionManager.name}`, () => { localHost, ncmPeer1.port, ); + await ncmLocal.nodeConnectionManager.isAuthenticatedP(ncmPeer1.nodeId); await ncmPeer1.nodeConnectionManager.createConnection( [ncmPeer2.nodeId], localHost, ncmPeer2.port, ); + await ncmPeer1.nodeConnectionManager.isAuthenticatedP(ncmPeer2.nodeId); // Mock and block `handleNodesConnectionSignalFinal` const mockedHandleNodesConnectionSignalFinal = jest.spyOn( @@ -1227,11 +1237,13 @@ describe(`${NodeConnectionManager.name}`, () => { localHost, ncmPeer1.port, ); + await ncmLocal.nodeConnectionManager.isAuthenticatedP(ncmPeer1.nodeId); await ncmPeer1.nodeConnectionManager.createConnection( [ncmPeer2.nodeId], localHost, ncmPeer2.port, ); + await ncmPeer1.nodeConnectionManager.isAuthenticatedP(ncmPeer2.nodeId); // Excessive connections will fail due to rate limit const connectionsP = (async () => { const connectionPs: Array> = []; diff --git a/tests/nodes/NodeManager.test.ts b/tests/nodes/NodeManager.test.ts index 8d6aa1e92..a7394731f 100644 --- a/tests/nodes/NodeManager.test.ts +++ b/tests/nodes/NodeManager.test.ts @@ -72,7 +72,7 @@ describe(`${NodeManager.name}`, () => { ]); const password = 'password'; const localHost = '127.0.0.1' as Host; - const timeoutTime = 300; + const timeoutTime = 1000; const dummyAgentService = { nodesAuthenticateConnection: new DummyNodesAuthenticateConnection({}), } as AgentServerManifest; @@ -1185,6 +1185,7 @@ describe(`${NodeManager.name}`, () => { localHost, ncmB.port, ); + await ncmA.nodeConnectionManager.isAuthenticatedP(ncmB.nodeId); } async function quickLinkConnection(structure: Array>) { const linkPs: Array> = []; @@ -1411,6 +1412,7 @@ describe(`${NodeManager.name}`, () => { localHost, ncmPeers[0].port, ); + await nodeConnectionManager.isAuthenticatedP(ncmPeers[0].nodeId); const rateLimiter = new Semaphore(3); const result = await nodeManager.findNodeBySignal( @@ -1442,6 +1444,7 @@ describe(`${NodeManager.name}`, () => { localHost, ncmPeers[0].port, ); + await nodeConnectionManager.isAuthenticatedP(ncmPeers[0].nodeId); const rateLimiter = new Semaphore(3); const result = await nodeManager.findNodeBySignal( @@ -1473,6 +1476,7 @@ describe(`${NodeManager.name}`, () => { localHost, ncmPeers[0].port, ); + await nodeConnectionManager.isAuthenticatedP(ncmPeers[0].nodeId); const rateLimiter = new Semaphore(3); const result = await nodeManager.findNodeBySignal( @@ -1504,6 +1508,7 @@ describe(`${NodeManager.name}`, () => { localHost, ncmPeers[0].port, ); + await nodeConnectionManager.isAuthenticatedP(ncmPeers[0].nodeId); const rateLimiter = new Semaphore(3); const resultP = nodeManager.findNodeBySignal( @@ -1532,6 +1537,7 @@ describe(`${NodeManager.name}`, () => { localHost, ncmPeers[0].port, ); + await nodeConnectionManager.isAuthenticatedP(ncmPeers[0].nodeId); const rateLimiter = new Semaphore(3); const resultP = nodeManager.findNodeBySignal( @@ -1573,6 +1579,7 @@ describe(`${NodeManager.name}`, () => { localHost, ncmPeers[0].port, ); + await nodeConnectionManager.isAuthenticatedP(ncmPeers[0].nodeId); const rateLimiter = new Semaphore(3); const resultP = nodeManager.findNodeBySignal( @@ -1847,6 +1854,7 @@ describe(`${NodeManager.name}`, () => { localHost, ncmPeers[0].port, ); + await nodeConnectionManager.isAuthenticatedP(ncmPeers[0].nodeId); const result = await nodeManager.findNode({ nodeId: ncmPeers[4].nodeId, @@ -1874,6 +1882,7 @@ describe(`${NodeManager.name}`, () => { localHost, ncmPeers[0].port, ); + await nodeConnectionManager.isAuthenticatedP(ncmPeers[0].nodeId); const result = await nodeManager.findNode({ nodeId: ncmPeers[4].nodeId, @@ -1901,6 +1910,7 @@ describe(`${NodeManager.name}`, () => { localHost, ncmPeers[0].port, ); + await nodeConnectionManager.isAuthenticatedP(ncmPeers[0].nodeId); const result = await nodeManager.findNode({ nodeId: keyRing.getNodeId(), @@ -1936,6 +1946,7 @@ describe(`${NodeManager.name}`, () => { localHost, ncmPeers[0].port, ); + await nodeConnectionManager.isAuthenticatedP(ncmPeers[0].nodeId); const start = Date.now(); const result = await nodeManager.findNode({ @@ -2024,6 +2035,7 @@ describe(`${NodeManager.name}`, () => { localHost, ncmPeers[0].port, ); + await nodeConnectionManager.isAuthenticatedP(ncmPeers[0].nodeId); await Promise.all([ await ncmPeers[3].nodeConnectionManager.stop({ force: true }), @@ -2101,6 +2113,7 @@ describe(`${NodeManager.name}`, () => { localHost, ncmPeers[0].port, ); + await nodeConnectionManager.isAuthenticatedP(ncmPeers[0].nodeId); await nodeManager.refreshBucket(100, 1000); // Small networks less than 20 nodes will contact all nodes @@ -2133,6 +2146,7 @@ describe(`${NodeManager.name}`, () => { localHost, ncmPeers[0].port, ); + await nodeConnectionManager.isAuthenticatedP(ncmPeers[0].nodeId); expect(await nodeGraph.nodesTotal()).toBe(0); diff --git a/tests/nodes/agent/handlers/nodesClosestActiveConnectionsGet.test.ts b/tests/nodes/agent/handlers/nodesClosestActiveConnectionsGet.test.ts index 76f85f23b..8054bb842 100644 --- a/tests/nodes/agent/handlers/nodesClosestActiveConnectionsGet.test.ts +++ b/tests/nodes/agent/handlers/nodesClosestActiveConnectionsGet.test.ts @@ -14,7 +14,7 @@ import * as nodesUtils from '@/nodes/utils'; import * as testsUtils from '../../../utils'; describe('nodesClosestLocalNode', () => { - const logger = new Logger('nodesClosestLocalNode test', LogLevel.WARN, [ + const logger = new Logger('nodesClosestLocalNode test', LogLevel.INFO, [ new StreamHandler(), ]); const localHost = '127.0.0.1' as Host; @@ -143,6 +143,8 @@ describe('nodesClosestLocalNode', () => { const connectionId = `connectionId-${i}`; const entry = { activeConnection: connectionId, + authenticatedForward: 2, + authenticatedReverse: 2, connections: { [connectionId]: { connection: {