Skip to content

Commit fcc3315

Browse files
committed
feat: moved QUICServer into NodeConnectionManager
* Related #527 [ci skip]
1 parent d75c416 commit fcc3315

8 files changed

Lines changed: 192 additions & 266 deletions

File tree

src/PolykeyAgent.ts

Lines changed: 43 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import type { FileSystem, PromiseDeconstructed } from './types';
22
import type { PolykeyWorkerManagerInterface } from './workers/types';
3-
import type { ConnectionData, Host, Port, TLSConfig } from './network/types';
3+
import type { ConnectionData, TLSConfig } from './network/types';
44
import type { SeedNodes } from './nodes/types';
5-
import type { CertificatePEM, CertManagerChangeData, Key } from './keys/types';
5+
import type { CertManagerChangeData, Key } from './keys/types';
66
import type { RecoveryCode, PrivateKey } from './keys/types';
77
import type { PasswordMemLimit, PasswordOpsLimit } from './keys/types';
8-
import type * as quicEvents from '@matrixai/quic/dist/events';
98
import type { ClientCrypto, QUICConfig, ServerCrypto } from '@matrixai/quic';
109
import path from 'path';
1110
import process from 'process';
@@ -124,7 +123,6 @@ class PolykeyAgent {
124123
webSocketServerClient,
125124
rpcServerAgent,
126125
quicSocket,
127-
quicServerAgent,
128126
fs = require('fs'),
129127
logger = new Logger(this.name),
130128
fresh = false,
@@ -176,7 +174,6 @@ class PolykeyAgent {
176174
webSocketServerClient?: WebSocketServer;
177175
rpcServerAgent?: RPCServer;
178176
quicSocket?: QUICSocket;
179-
quicServerAgent?: QUICServer;
180177
fs?: FileSystem;
181178
logger?: Logger;
182179
fresh?: boolean;
@@ -205,6 +202,7 @@ class PolykeyAgent {
205202
...config.defaults.quicServerConfig,
206203
...utils.filterEmptyObject(quicServerConfig),
207204
};
205+
// TODO: rename
208206
const quicClientConfig_ = {
209207
...config.defaults.quicClientConfig,
210208
...utils.filterEmptyObject(quicClientConfig),
@@ -358,29 +356,55 @@ class PolykeyAgent {
358356
logger: logger.getChild(QUICSocket.name),
359357
resolveHostname,
360358
});
361-
const clientCrypto: ClientCrypto = {
359+
const crypto: ServerCrypto & ClientCrypto = {
362360
randomBytes: async (data: ArrayBuffer) => {
363361
const randomBytes = keysUtils.getRandomBytes(data.byteLength);
364362
const dataBuf = Buffer.from(data);
365363
dataBuf.write(randomBytes.toString('binary'), 'binary');
366364
},
365+
async sign(key: ArrayBuffer, data: ArrayBuffer) {
366+
const cryptoKey = await webcrypto.subtle.importKey(
367+
'raw',
368+
key,
369+
{
370+
name: 'HMAC',
371+
hash: 'SHA-256',
372+
},
373+
true,
374+
['sign', 'verify'],
375+
);
376+
return webcrypto.subtle.sign('HMAC', cryptoKey, data);
377+
},
378+
async verify(key: ArrayBuffer, data: ArrayBuffer, sig: ArrayBuffer) {
379+
const cryptoKey = await webcrypto.subtle.importKey(
380+
'raw',
381+
key,
382+
{
383+
name: 'HMAC',
384+
hash: 'SHA-256',
385+
},
386+
true,
387+
['sign', 'verify'],
388+
);
389+
return webcrypto.subtle.verify('HMAC', cryptoKey, sig, data);
390+
},
391+
};
392+
const tlsConfig: TLSConfig = {
393+
keyPrivatePem: keysUtils.privateKeyToPEM(keyRing.keyPair.privateKey),
394+
certChainPem: await certManager.getCertPEMsChainPEM(),
367395
};
368396
nodeConnectionManager =
369397
nodeConnectionManager ??
370398
new NodeConnectionManager({
399+
handleStream: () => {},
371400
keyRing,
372401
nodeGraph,
373402
seedNodes,
374403
quicSocket,
375-
quicClientConfig: {
376-
...quicClientConfig_,
377-
key: keysUtils.privateKeyToPEM(keyRing.keyPair.privateKey),
378-
cert: await certManager.getCertPEMsChainPEM(),
379-
},
404+
quicConfig: quicClientConfig_,
380405
...nodeConnectionManagerConfig_,
381-
crypto: {
382-
ops: clientCrypto,
383-
},
406+
tlsConfig,
407+
crypto,
384408
logger: logger.getChild(NodeConnectionManager.name),
385409
});
386410
nodeManager =
@@ -474,10 +498,6 @@ class PolykeyAgent {
474498
logger: logger.getChild(RPCServer.name + 'Client'),
475499
});
476500
}
477-
const tlsConfig: TLSConfig = {
478-
keyPrivatePem: keysUtils.privateKeyToPEM(keyRing.keyPair.privateKey),
479-
certChainPem: await certManager.getCertPEMsChainPEM(),
480-
};
481501
webSocketServerClient =
482502
webSocketServerClient ??
483503
(await WebSocketServer.createWebSocketServer({
@@ -517,58 +537,8 @@ class PolykeyAgent {
517537
logger: logger.getChild(RPCServer.name + 'Agent'),
518538
});
519539
}
520-
const serverCrypto: ServerCrypto = {
521-
async sign(key: ArrayBuffer, data: ArrayBuffer) {
522-
const cryptoKey = await webcrypto.subtle.importKey(
523-
'raw',
524-
key,
525-
{
526-
name: 'HMAC',
527-
hash: 'SHA-256',
528-
},
529-
true,
530-
['sign', 'verify'],
531-
);
532-
return webcrypto.subtle.sign('HMAC', cryptoKey, data);
533-
},
534-
async verify(key: ArrayBuffer, data: ArrayBuffer, sig: ArrayBuffer) {
535-
const cryptoKey = await webcrypto.subtle.importKey(
536-
'raw',
537-
key,
538-
{
539-
name: 'HMAC',
540-
hash: 'SHA-256',
541-
},
542-
true,
543-
['sign', 'verify'],
544-
);
545-
return webcrypto.subtle.verify('HMAC', cryptoKey, sig, data);
546-
},
547-
};
548-
quicServerAgent =
549-
quicServerAgent ??
550-
new QUICServer({
551-
config: {
552-
...quicServerConfig_,
553-
key: tlsConfig.keyPrivatePem,
554-
cert: tlsConfig.certChainPem,
555-
verifyPeer: true,
556-
verifyAllowFail: true,
557-
},
558-
crypto: {
559-
key: keysUtils.generateKey(),
560-
ops: serverCrypto,
561-
},
562-
verifyCallback: networkUtils.verifyClientCertificateChain,
563-
logger: logger.getChild(QUICServer.name + 'Agent'),
564-
socket: quicSocket,
565-
resolveHostname,
566-
reasonToCode: utils.reasonToCode,
567-
codeToReason: utils.codeToReason,
568-
});
569540
} catch (e) {
570541
logger.warn(`Failed Creating ${this.name}`);
571-
await quicServerAgent?.stop({ force: true });
572542
await quicSocket?.stop({ force: true });
573543
await rpcServerAgent?.destroy(true);
574544
await rpcServerClient?.destroy();
@@ -612,7 +582,6 @@ class PolykeyAgent {
612582
webSocketServerClient,
613583
rpcServerAgent,
614584
quicSocket,
615-
quicServerAgent,
616585
events,
617586
fs,
618587
logger,
@@ -653,7 +622,6 @@ class PolykeyAgent {
653622
public readonly webSocketServerClient: WebSocketServer;
654623
public readonly rpcServerAgent: RPCServer;
655624
public readonly quicSocket: QUICSocket;
656-
public readonly quicServerAgent: QUICServer;
657625
protected workerManager: PolykeyWorkerManagerInterface | undefined;
658626

659627
constructor({
@@ -679,7 +647,6 @@ class PolykeyAgent {
679647
webSocketServerClient,
680648
rpcServerAgent,
681649
quicSocket,
682-
quicServerAgent,
683650
events,
684651
fs,
685652
logger,
@@ -706,7 +673,6 @@ class PolykeyAgent {
706673
webSocketServerClient: WebSocketServer;
707674
rpcServerAgent: RPCServer;
708675
quicSocket: QUICSocket;
709-
quicServerAgent: QUICServer;
710676
events: EventBus;
711677
fs: FileSystem;
712678
logger: Logger;
@@ -734,7 +700,6 @@ class PolykeyAgent {
734700
this.webSocketServerClient = webSocketServerClient;
735701
this.rpcServerAgent = rpcServerAgent;
736702
this.quicSocket = quicSocket;
737-
this.quicServerAgent = quicServerAgent;
738703
this.events = events;
739704
this.fs = fs;
740705
}
@@ -788,10 +753,7 @@ class PolykeyAgent {
788753
// We would need to shut down the Websocket server and re-create it with the new config.
789754
// Right now graceful shutdown is not supported.
790755
// this.grpcServerClient.setTLSConfig(tlsConfig);
791-
this.quicServerAgent.updateConfig({
792-
key: tlsConfig.keyPrivatePem,
793-
cert: tlsConfig.certChainPem,
794-
});
756+
this.nodeConnectionManager.updateTlsConfig(tlsConfig);
795757
this.logger.info(`${KeyRing.name} change propagated`);
796758
},
797759
);
@@ -876,79 +838,11 @@ class PolykeyAgent {
876838
port: _networkConfig.agentPort,
877839
ipv6Only: _networkConfig.ipv6Only,
878840
});
879-
// Setting up stream handling
880-
const handleStream = async (
881-
event: quicEvents.QUICConnectionStreamEvent,
882-
) => {
883-
// Streams are handled via the RPCServer.
884-
const stream = event.detail;
885-
this.rpcServerAgent.handleStream(stream);
886-
};
887-
888-
const handleConnection = async (
889-
event: quicEvents.QUICServerConnectionEvent,
890-
) => {
891-
// Needs to setup stream handler
892-
const connection = event.detail;
893-
try {
894-
// Dispatch connection event
895-
const remoteCertificates = connection.getRemoteCertsChain();
896-
if (remoteCertificates.length === 0) {
897-
throw Error('remote certificates were not provided');
898-
}
899-
const remoteCertPem = remoteCertificates[0];
900-
const remoteCert = keysUtils.certFromPEM(
901-
remoteCertPem as CertificatePEM,
902-
);
903-
if (remoteCert == null) throw Error('failed to parse certificate');
904-
const nodeId = keysUtils.certNodeId(remoteCert);
905-
if (nodeId == null) throw Error('failed to extract NodeId from cert');
906-
const data: ConnectionData = {
907-
remoteNodeId: nodeId,
908-
remoteHost: connection.remoteHost as Host,
909-
remotePort: connection.remotePort as Port,
910-
};
911-
await this.events.emitAsync(
912-
PolykeyAgent.eventSymbols.QUICServer,
913-
data,
914-
);
915-
} catch (e) {
916-
this.logger.error(e.message);
917-
await connection.stop({
918-
applicationError: true,
919-
errorMessage: e.message,
920-
force: true,
921-
});
922-
}
923-
924-
connection.addEventListener('connectionStream', handleStream);
925-
connection.addEventListener(
926-
'connectionStop',
927-
() => {
928-
connection.removeEventListener('connectionStream', handleStream);
929-
},
930-
{ once: true },
931-
);
932-
};
933-
this.quicServerAgent.addEventListener(
934-
'serverConnection',
935-
handleConnection,
936-
);
937-
this.quicServerAgent.addEventListener(
938-
'serverStop',
939-
() => {
940-
this.quicServerAgent.removeEventListener(
941-
'serverConnection',
942-
handleConnection,
943-
);
944-
},
945-
{ once: true },
946-
);
947-
// Finished setting up handling.
948-
// No host or port is provided here, it's configured in the shared QUICSocket.
949-
await this.quicServerAgent.start();
950841
await this.nodeManager.start();
951-
await this.nodeConnectionManager.start({ nodeManager: this.nodeManager });
842+
await this.nodeConnectionManager.start({
843+
nodeManager: this.nodeManager,
844+
handleStream: (stream) => this.rpcServerAgent.handleStream(stream),
845+
});
952846
await this.nodeGraph.start({ fresh });
953847
await this.nodeManager.syncNodeGraph(false);
954848
await this.discovery.start({ fresh });
@@ -989,7 +883,6 @@ class PolykeyAgent {
989883
await this.nodeGraph?.stop();
990884
await this.nodeConnectionManager?.stop();
991885
await this.nodeManager?.stop();
992-
await this.quicServerAgent.stop();
993886
await this.quicSocket.stop();
994887
await this.webSocketServerClient.stop(true);
995888
await this.identitiesManager?.stop();
@@ -1025,7 +918,6 @@ class PolykeyAgent {
1025918
await this.nodeConnectionManager.stop();
1026919
await this.nodeGraph.stop();
1027920
await this.nodeManager.stop();
1028-
await this.quicServerAgent.stop();
1029921
await this.quicSocket.stop();
1030922
await this.webSocketServerClient.stop(true);
1031923
await this.identitiesManager.stop();

src/bootstrap/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ async function bootstrapState({
161161
quicClientConfig: {} as any, // No connections are attempted
162162
crypto: {} as any, // No connections are attempted
163163
quicSocket: {} as any, // No connections are attempted
164-
logger: logger.getChild(NodeConnectionManager.name)
164+
logger: logger.getChild(NodeConnectionManager.name),
165165
});
166166
const nodeManager = new NodeManager({
167167
db,

0 commit comments

Comments
 (0)