diff --git a/Tokenization/backend/wrapper/models/config.model.ts b/Tokenization/backend/wrapper/models/config.model.ts new file mode 100644 index 000000000..5f4c82a0f --- /dev/null +++ b/Tokenization/backend/wrapper/models/config.model.ts @@ -0,0 +1,29 @@ +/** + * @license + * Copyright 2019-2020 CERN and copyright holders of ALICE O2. + * See http://alice-o2.web.cern.ch/copyright for details of the copyright holders. + * All rights not expressly granted are reserved. + * + * This software is distributed under the terms of the GNU General Public + * License v3 (GPL Version 3), copied verbatim in the file "COPYING". + * + * In applying this license CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization + * or submit itself to any jurisdiction. + */ + +export interface CentralSystemConfig { + /** Path to the proto file defining the services. */ + protoPath: string; + /** Host/IP to bind the gRPC server on. Defaults to "0.0.0.0" which is docker-friendly. */ + host?: string; + /** Port to bind. Defaults to 50051. */ + port?: number; +} + +export interface gRPCWrapperConfig { + /** Path to the proto file defining the services. */ + protoPath: string; + /** Address of the CentralSystem server. */ + centralAddress: string; +} diff --git a/Tokenization/backend/wrapper/src/central/CentralSystemWrapper.ts b/Tokenization/backend/wrapper/src/central/CentralSystemWrapper.ts index 20f5e2457..f120048ec 100644 --- a/Tokenization/backend/wrapper/src/central/CentralSystemWrapper.ts +++ b/Tokenization/backend/wrapper/src/central/CentralSystemWrapper.ts @@ -15,6 +15,8 @@ import * as grpc from '@grpc/grpc-js'; import * as protoLoader from '@grpc/proto-loader'; import { LogManager } from '@aliceo2/web-ui'; +import * as fs from 'fs'; +import type { CentralSystemConfig } from '../models/config.model'; import type { DuplexMessageModel } from '../models/message.model'; /** @@ -24,11 +26,15 @@ export class CentralSystemWrapper { // Config private _protoPath: string; - // Utilities - private _logger = LogManager.getLogger('CentralSystemWrapper'); - // Class properties private _server: grpc.Server; + private _port: number; + + // Certificates paths + private _serverCerts: CentralSystemConfig['serverCerts']; + + // Utilities + private _logger = LogManager.getLogger('CentralSystemWrapper'); // Clients management private _clients = new Map>(); @@ -38,8 +44,15 @@ export class CentralSystemWrapper { * Initializes the Wrapper for CentralSystem. * @param port The port number to bind the gRPC server to. */ - constructor(protoPath: string, private port: number) { - this._protoPath = protoPath; + constructor(config: CentralSystemConfig) { + if (!config.protoPath || !config.serverCerts?.caCertPath || !config.serverCerts?.certPath || !config.serverCerts?.keyPath) { + throw new Error('Invalid CentralSystemConfig provided'); + } + + this._protoPath = config.protoPath; + this._serverCerts = config.serverCerts; + this._port = config.port ?? 50051; + this._server = new grpc.Server(); this.setupService(); } @@ -115,7 +128,7 @@ export class CentralSystemWrapper { // Handle stream error event call.on('error', (err) => { - this._logger.infoMessage(`Stream error from client ${clientIp}:`, err); + this._logger.errorMessage(`Stream error from client ${clientIp}:`, err); this.cleanupClient(peer); }); } @@ -168,10 +181,27 @@ export class CentralSystemWrapper { * Starts the gRPC server and binds it to the specified in class port. */ public listen() { - const addr = `localhost:${this.port}`; - this._server.bindAsync(addr, grpc.ServerCredentials.createInsecure(), (err, _port) => { + const addr = `localhost:${this._port}`; + + // Create mTLS secure gRPC server + const caCert = fs.readFileSync(this._serverCerts.caCertPath); + const centralKey = fs.readFileSync(this._serverCerts.keyPath); + const centralCert = fs.readFileSync(this._serverCerts.certPath); + + const sslCreds = grpc.ServerCredentials.createSsl( + caCert, + [ + { + private_key: centralKey, + cert_chain: centralCert, + }, + ], + true + ); + + this._server.bindAsync(addr, sslCreds, (err, _port) => { if (err) { - this._logger.infoMessage('Server bind error:', err); + this._logger.errorMessage('Server bind error:', err); return; } this._logger.infoMessage(`CentralSytem started listening on ${addr}`); diff --git a/Tokenization/backend/wrapper/src/client/connection/Connection.ts b/Tokenization/backend/wrapper/src/client/connection/Connection.ts index 3f27c31b5..38b09b19e 100644 --- a/Tokenization/backend/wrapper/src/client/connection/Connection.ts +++ b/Tokenization/backend/wrapper/src/client/connection/Connection.ts @@ -33,13 +33,35 @@ export class Connection { * @param token - The authentication token for the connection. * @param targetAddress - The unique address of the target client. * @param direction - The direction of the connection (e.g., sending or receiving). + * @param peerCtor - The constructor for the gRPC client to be used for communication. + * @param caCertPath - Path to the CA certificate file. + * @param clientCertPath - Path to the client certificate file. + * @param clientKeyPath - Path to the client key file. */ - constructor(token: string, targetAddress: string, direction: ConnectionDirection, peerCtor: any) { + constructor( + token: string, + targetAddress: string, + direction: ConnectionDirection, + peerCtor: any, + private readonly connectionCerts: { + caCert: NonSharedBuffer; + clientCert: NonSharedBuffer; + clientKey: NonSharedBuffer; + } + ) { this._token = token; this._targetAddress = targetAddress; - this._peerClient = new peerCtor(targetAddress, grpc.credentials.createInsecure()); this.direction = direction; + if (!connectionCerts.caCert || !connectionCerts.clientCert || !connectionCerts.clientKey) { + throw new Error('Connection certificates are required to create a Connection.'); + } + + // Create grpc credentials + const sslCreds = grpc.credentials.createSsl(this.connectionCerts.caCert, this.connectionCerts.clientKey, this.connectionCerts.clientCert); + + this._peerClient = new peerCtor(targetAddress, sslCreds); + this._status = ConnectionStatus.CONNECTED; } diff --git a/Tokenization/backend/wrapper/src/client/connectionManager/ConnectionManager.ts b/Tokenization/backend/wrapper/src/client/connectionManager/ConnectionManager.ts index fdbd20263..c73c6c9d0 100644 --- a/Tokenization/backend/wrapper/src/client/connectionManager/ConnectionManager.ts +++ b/Tokenization/backend/wrapper/src/client/connectionManager/ConnectionManager.ts @@ -14,15 +14,16 @@ import * as grpc from '@grpc/grpc-js'; import * as protoLoader from '@grpc/proto-loader'; +import * as fs from 'fs'; import { CentralConnection } from './CentralConnection'; import { CentralCommandDispatcher } from './eventManagement/CentralCommandDispatcher'; import { Connection } from '../connection/Connection'; import { LogManager } from '@aliceo2/web-ui'; -import type { Command, CommandHandler } from 'models/commands.model'; -import type { DuplexMessageEvent } from '../../models/message.model'; import { ConnectionDirection } from '../../models/message.model'; import { ConnectionStatus } from '../../models/connection.model'; import { peerListener } from '../../utils/connection/peerListener'; +import type { Command, CommandHandler } from 'models/commands.model'; +import type { DuplexMessageEvent } from '../../models/message.model'; /** * Manages the lifecycle and connection logic for a gRPC client communicating with the central system. @@ -49,6 +50,11 @@ export class ConnectionManager { private _peerServer: grpc.Server | undefined; private _baseAPIPath: string = ''; + // Client certificates + private _caCert: NonSharedBuffer; + private _clientCert: NonSharedBuffer; + private _clientKey: NonSharedBuffer; + /** * Initializes a new instance of the ConnectionManager class. * @@ -56,8 +62,11 @@ export class ConnectionManager { * * @param protoPath - The file path to the gRPC proto definition. * @param centralAddress - The address of the central gRPC server (default: "localhost:50051"). + * @param caCertPath - Path to the CA certificate file. + * @param clientCertPath - Path to the client certificate file. + * @param clientKeyPath - Path to the client key file. */ - constructor(protoPath: string, centralAddress: string = 'localhost:50051') { + constructor(protoPath: string, centralAddress: string = 'localhost:50051', caCertPath: string, clientCertPath: string, clientKeyPath: string) { const packageDef = protoLoader.loadSync(protoPath, { keepCase: true, longs: String, @@ -70,11 +79,18 @@ export class ConnectionManager { this._wrapper = proto.webui.tokenization; this._peerCtor = this._wrapper.Peer2Peer; - const client = new this._wrapper.CentralSystem(centralAddress, grpc.credentials.createInsecure()); + // Read certs + this._caCert = fs.readFileSync(caCertPath); + this._clientCert = fs.readFileSync(clientCertPath); + this._clientKey = fs.readFileSync(clientKeyPath); + + // Create grpc credentials + const sslCreds = grpc.credentials.createSsl(this._caCert, this._clientKey, this._clientCert); + const centralClient = new this._wrapper.CentralSystem(centralAddress, sslCreds); // Event dispatcher for central system events this._centralDispatcher = new CentralCommandDispatcher(); - this._centralConnection = new CentralConnection(client, this._centralDispatcher, centralAddress); + this._centralConnection = new CentralConnection(centralClient, this._centralDispatcher, centralAddress); } /** @@ -112,8 +128,28 @@ export class ConnectionManager { * @param direction Direction of connection * @param token Optional token for connection */ - createNewConnection(address: string, direction: ConnectionDirection, token?: string) { - const conn = new Connection(token ?? '', address, direction, this._peerCtor); + public async createNewConnection(address: string, direction: ConnectionDirection, token?: string) { + let conn: Connection | undefined; + + // Checks if connection already exists + conn = direction === ConnectionDirection.RECEIVING ? this._receivingConnections.get(address) : this._sendingConnections.get(address); + + // Return existing connection if found + if (conn) { + if (token) { + conn.token = token; + } + return conn; + } + + // Create new connection + conn = new Connection(token ?? '', address, direction, this._peerCtor, { + caCert: this._caCert, + clientCert: this._clientCert, + clientKey: this._clientKey, + }); + + conn.status = ConnectionStatus.CONNECTING; if (direction === ConnectionDirection.RECEIVING) { this._receivingConnections.set(address, conn); @@ -158,7 +194,7 @@ export class ConnectionManager { } /** Starts a listener server for p2p connections */ - public async listenForPeers(port: number, baseAPIPath?: string): Promise { + public async listenForPeers(port: number, listenerKey: NonSharedBuffer, listenerCert: NonSharedBuffer, baseAPIPath?: string): Promise { if (baseAPIPath) this._baseAPIPath = baseAPIPath; if (this._peerServer) { @@ -169,11 +205,22 @@ export class ConnectionManager { this._peerServer = new grpc.Server(); this._peerServer.addService(this._wrapper.Peer2Peer.service, { Fetch: async (call: grpc.ServerUnaryCall, callback: grpc.sendUnaryData) => - peerListener(call, callback, this._logger, this._receivingConnections, this._peerCtor, this._baseAPIPath), + peerListener(call, callback, this._logger, this._receivingConnections, this.createNewConnection.bind(this), this._baseAPIPath), }); + const sslCreds = grpc.ServerCredentials.createSsl( + this._caCert, + [ + { + private_key: listenerKey, + cert_chain: listenerCert, + }, + ], + true + ); + await new Promise((resolve, reject) => { - this._peerServer?.bindAsync(`localhost:${port}`, grpc.ServerCredentials.createInsecure(), (err) => (err ? reject(err) : resolve())); + this._peerServer?.bindAsync(`localhost:${port}`, sslCreds, (err) => (err ? reject(err) : resolve())); }); this._logger.infoMessage(`Peer server listening on localhost:${port}`); diff --git a/Tokenization/backend/wrapper/src/client/gRPCWrapper.ts b/Tokenization/backend/wrapper/src/client/gRPCWrapper.ts index 0622afe48..595742d2d 100644 --- a/Tokenization/backend/wrapper/src/client/gRPCWrapper.ts +++ b/Tokenization/backend/wrapper/src/client/gRPCWrapper.ts @@ -12,14 +12,17 @@ * or submit itself to any jurisdiction. */ +import * as fs from 'fs'; import { ConnectionManager } from './connectionManager/ConnectionManager'; import { RevokeTokenHandler } from './commands/revokeToken/revokeToken.handler'; import { ConnectionDirection, DuplexMessageEvent } from '../models/message.model'; import { NewTokenHandler } from './commands/newToken/newToken.handler'; +import { LogManager } from '@aliceo2/web-ui'; +import type { gRPCWrapperConfig } from '../models/config.model'; import type { Connection } from './connection/Connection'; /** - * @description Wrapper class for managing secure gRPC wrapper. + * Wrapper class for managing secure gRPC wrapper. * * @remarks * This class serves as a high-level abstraction over the underlying @@ -34,6 +37,9 @@ import type { Connection } from './connection/Connection'; */ export class gRPCWrapper { private _connectionManager: ConnectionManager; + private _listenerKey?: NonSharedBuffer; + private _listenerCert?: NonSharedBuffer; + private _logger = LogManager.getLogger('gRPCWrapper'); /** * Initializes an instance of gRPCWrapper class. @@ -41,8 +47,29 @@ export class gRPCWrapper { * @param protoPath - The file path to the gRPC proto definition. * @param centralAddress - The address of the central gRPC server (default: "localhost:4100"). */ - constructor(protoPath: string, centralAddress: string = 'localhost:4100') { - this._connectionManager = new ConnectionManager(protoPath, centralAddress); + constructor(config: gRPCWrapperConfig) { + if ( + !config.protoPath || + !config.centralAddress || + !config.clientCerts?.caCertPath || + !config.clientCerts?.certPath || + !config.clientCerts?.keyPath + ) { + throw new Error('Invalid gRPCWrapper configuration provided.'); + } + + if (config.listenerCertPaths?.keyPath && config.listenerCertPaths?.certPath) { + this._listenerKey = fs.readFileSync(config.listenerCertPaths.keyPath); + this._listenerCert = fs.readFileSync(config.listenerCertPaths.certPath); + } + + this._connectionManager = new ConnectionManager( + config.protoPath, + config.centralAddress, + config.clientCerts.caCertPath, + config.clientCerts.certPath, + config.clientCerts.keyPath + ); this._connectionManager.registerCommandHandlers([ { event: DuplexMessageEvent.MESSAGE_EVENT_REVOKE_TOKEN, @@ -83,8 +110,18 @@ export class gRPCWrapper { * @param baseAPIPath Optional base API path to forward requests to e.g. '/api'. * @returns A promise that resolves when the p2p listener server is started. */ - public async listenForPeers(port: number, baseAPIPath?: string): Promise { - return this._connectionManager.listenForPeers(port, baseAPIPath); + public async listenForPeers(port: number, baseAPIPath?: string, listenerCertPaths?: { keyPath: string; certPath: string }): Promise { + if (listenerCertPaths?.keyPath && listenerCertPaths?.certPath) { + this._listenerKey = fs.readFileSync(listenerCertPaths.keyPath); + this._listenerCert = fs.readFileSync(listenerCertPaths.certPath); + } + + if (!this._listenerKey || !this._listenerCert) { + this._logger.errorMessage('Listener certificates are required to start P2P listener. Please provide valid paths.'); + return; + } + + return this._connectionManager.listenForPeers(port, this._listenerKey, this._listenerCert, baseAPIPath); } /** diff --git a/Tokenization/backend/wrapper/src/models/config.model.ts b/Tokenization/backend/wrapper/src/models/config.model.ts new file mode 100644 index 000000000..6d6b18555 --- /dev/null +++ b/Tokenization/backend/wrapper/src/models/config.model.ts @@ -0,0 +1,46 @@ +/** + * @license + * Copyright 2019-2020 CERN and copyright holders of ALICE O2. + * See http://alice-o2.web.cern.ch/copyright for details of the copyright holders. + * All rights not expressly granted are reserved. + * + * This software is distributed under the terms of the GNU General Public + * License v3 (GPL Version 3), copied verbatim in the file "COPYING". + * + * In applying this license CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization + * or submit itself to any jurisdiction. + */ + +export interface CentralSystemConfig { + /** Path to the proto file defining the services. */ + protoPath: string; + /** Host/IP to bind the gRPC server on. Defaults to "0.0.0.0" which is docker-friendly. */ + host?: string; + /** Port to bind. Defaults to 50051. */ + port?: number; + + /** Central TLS certificates paths. */ + serverCerts: { + caCertPath: string; + certPath: string; + keyPath: string; + }; +} + +export interface gRPCWrapperConfig { + /** Path to the proto file defining the services. */ + protoPath: string; + /** Address of the CentralSystem server. */ + centralAddress: string; + + /** Client TLS certificates paths. */ + clientCerts: { + caCertPath: string; + keyPath: string; + certPath: string; + }; + + /** Optional listener TLS certificates paths. If provided, the gRPCWrapper will be able to accept incoming connections. */ + listenerCertPaths?: { keyPath: string; certPath: string }; +} diff --git a/Tokenization/backend/wrapper/src/test/central/CentralSystemWrapper.test.ts b/Tokenization/backend/wrapper/src/test/central/CentralSystemWrapper.test.ts index 4c7476cbb..9b5be6277 100644 --- a/Tokenization/backend/wrapper/src/test/central/CentralSystemWrapper.test.ts +++ b/Tokenization/backend/wrapper/src/test/central/CentralSystemWrapper.test.ts @@ -21,6 +21,7 @@ const mockServerInstance = { const logger = { infoMessage: jest.fn(), + errorMessage: jest.fn(), }; jest.mock( @@ -45,7 +46,7 @@ jest.mock('@grpc/grpc-js', () => { ...original, Server: jest.fn(() => mockServerInstance), ServerCredentials: { - createInsecure: jest.fn(() => 'mock-credentials'), + createSsl: jest.fn(() => 'mock-credentials'), }, loadPackageDefinition: jest.fn(() => ({ webui: { @@ -61,21 +62,26 @@ jest.mock('@grpc/grpc-js', () => { import { CentralSystemWrapper } from '../../central/CentralSystemWrapper'; import * as grpc from '@grpc/grpc-js'; +import { getTestCentralCertPaths } from '../testCerts/testCerts'; describe('CentralSystemWrapper', () => { let wrapper: CentralSystemWrapper; + const testCentralCertPaths = getTestCentralCertPaths(); beforeEach(() => { jest.clearAllMocks(); - wrapper = new CentralSystemWrapper('dummy.proto', 12345); + wrapper = new CentralSystemWrapper({ + protoPath: 'dummy.proto', + port: 12345, + serverCerts: testCentralCertPaths, + }); }); test('should set up gRPC service and add it to the server', () => { - const testWrapper = new CentralSystemWrapper('dummy.proto', 12345); expect(grpc.Server).toHaveBeenCalled(); expect(grpc.loadPackageDefinition).toHaveBeenCalled(); - expect(grpc.ServerCredentials.createInsecure).not.toHaveBeenCalled(); - expect(testWrapper).toBeDefined(); + expect(grpc.ServerCredentials.createSsl).not.toHaveBeenCalled(); + expect(wrapper).toBeDefined(); }); test('should call listen and bind the server', () => { @@ -92,7 +98,7 @@ describe('CentralSystemWrapper', () => { wrapper.listen(); - expect(logger.infoMessage).toHaveBeenCalledWith('Server bind error:', error); + expect(logger.errorMessage).toHaveBeenCalledWith('Server bind error:', error); }); test('should handle client stream events', () => { @@ -118,6 +124,6 @@ describe('CentralSystemWrapper', () => { expect(logger.infoMessage).toHaveBeenCalledWith(expect.stringContaining('Client client123')); expect(logger.infoMessage).toHaveBeenCalledWith('Client client123 ended stream.'); - expect(logger.infoMessage).toHaveBeenCalledWith('Stream error from client client123:', expect.any(Error)); + expect(logger.errorMessage).toHaveBeenCalledWith('Stream error from client client123:', expect.any(Error)); }); }); diff --git a/Tokenization/backend/wrapper/src/test/client/commands/newToken.test.ts b/Tokenization/backend/wrapper/src/test/client/commands/newToken.test.ts index fd5c23215..ffec6ed77 100644 --- a/Tokenization/backend/wrapper/src/test/client/commands/newToken.test.ts +++ b/Tokenization/backend/wrapper/src/test/client/commands/newToken.test.ts @@ -21,6 +21,7 @@ import { ConnectionDirection, DuplexMessageEvent } from '../../../models/message import * as grpc from '@grpc/grpc-js'; import * as protoLoader from '@grpc/proto-loader'; import path from 'path'; +import { getTestCerts } from '../../testCerts/testCerts'; /** * Helper to create a new token command with given address, direction, and token. @@ -65,7 +66,7 @@ describe('NewTokenHandler', () => { return undefined; }), createNewConnection: jest.fn(function (this: any, address: string, dir: ConnectionDirection, token: string) { - const conn = new Connection(token, address, dir, peerCtor); + const conn = new Connection(token, address, dir, peerCtor, getTestCerts()); if (dir === ConnectionDirection.SENDING) { this.sendingConnections.set(address, conn); } else { @@ -78,7 +79,8 @@ describe('NewTokenHandler', () => { it('should update token on existing SENDING connection', async () => { const targetAddress = 'peer-123'; - const conn = new Connection('old-token', targetAddress, ConnectionDirection.SENDING, peerCtor); + const conn = new Connection('old-token', targetAddress, ConnectionDirection.SENDING, peerCtor, getTestCerts()); + (manager as any).sendingConnections.set(targetAddress, conn); const handler = new NewTokenHandler(manager); diff --git a/Tokenization/backend/wrapper/src/test/client/commands/revokeToken.test.ts b/Tokenization/backend/wrapper/src/test/client/commands/revokeToken.test.ts index 3764d1724..38d076cd3 100644 --- a/Tokenization/backend/wrapper/src/test/client/commands/revokeToken.test.ts +++ b/Tokenization/backend/wrapper/src/test/client/commands/revokeToken.test.ts @@ -22,6 +22,7 @@ import { Command } from 'models/commands.model'; import * as grpc from '@grpc/grpc-js'; import * as protoLoader from '@grpc/proto-loader'; import path from 'path'; +import { getTestCerts } from '../../testCerts/testCerts'; describe('RevokeToken', () => { const protoPath = path.join(__dirname, '..', '..', '..', '..', '..', 'proto', 'wrapper.proto'); @@ -61,7 +62,7 @@ describe('RevokeToken', () => { it('should revoke token when connection found in sendingConnections', async () => { const targetAddress = 'peer-123'; - const conn = new Connection('valid-token', targetAddress, ConnectionDirection.SENDING, peerCtor); + const conn = new Connection('valid-token', targetAddress, ConnectionDirection.SENDING, peerCtor, getTestCerts()); (manager as any).sendingConnections!.set(targetAddress, conn); const handler = new RevokeTokenHandler(manager); @@ -75,7 +76,7 @@ describe('RevokeToken', () => { it('should revoke token when connection found in receivingConnections', async () => { const targetAddress = 'peer-456'; - const conn = new Connection('valid-token', targetAddress, ConnectionDirection.RECEIVING, peerCtor); + const conn = new Connection('valid-token', targetAddress, ConnectionDirection.RECEIVING, peerCtor, getTestCerts()); (manager as any).receivingConnections.set(targetAddress, conn); const handler = new RevokeTokenHandler(manager); diff --git a/Tokenization/backend/wrapper/src/test/client/connectionManager/ConnectionManager.test.ts b/Tokenization/backend/wrapper/src/test/client/connectionManager/ConnectionManager.test.ts index dff46c2c6..74b417f2c 100644 --- a/Tokenization/backend/wrapper/src/test/client/connectionManager/ConnectionManager.test.ts +++ b/Tokenization/backend/wrapper/src/test/client/connectionManager/ConnectionManager.test.ts @@ -62,10 +62,10 @@ jest.mock('@grpc/grpc-js', () => { ...original, loadPackageDefinition, credentials: { - createInsecure: jest.fn(() => ({})), + createSsl: jest.fn(() => ({})), }, ServerCredentials: { - createInsecure: jest.fn(() => ({})), + createSsl: jest.fn(() => ({})), }, status: { ...original.status, @@ -144,8 +144,11 @@ jest.mock( import { ConnectionManager } from '../../../client/connectionManager/ConnectionManager'; import { ConnectionDirection } from '../../../models/message.model'; import { ConnectionStatus } from '../../../models/connection.model'; +import { getTestCentralCertPaths, getTestCerts } from '../../../test/testCerts/testCerts'; describe('ConnectionManager', () => { + const { caCertPath, certPath, keyPath } = getTestCentralCertPaths(); + beforeEach(() => { jest.clearAllMocks(); capturedServerImpl = null; @@ -160,16 +163,16 @@ describe('ConnectionManager', () => { }); test('constructor: loads proto, builds wrapper/peerCtor and CentralSystem client', () => { - const cm = new ConnectionManager('proto/file.proto', 'central:5555'); + const cm = new ConnectionManager('proto/file.proto', 'central:5555', caCertPath, certPath, keyPath); expect(cm).toBeDefined(); expect((grpc as any).loadPackageDefinition).toHaveBeenCalled(); expect(CentralSystemClientMock).toHaveBeenCalledWith('central:5555', expect.any(Object)); - expect(grpc.credentials.createInsecure).toHaveBeenCalled(); + expect(grpc.credentials.createSsl).toHaveBeenCalled(); }); test('registerCommandHandlers: calls dispatcher.register for each item', () => { - const cm = new ConnectionManager('p.proto', 'c:1'); + const cm = new ConnectionManager('p.proto', 'c:1', caCertPath, certPath, keyPath); dispatcherRegisterMock.mockClear(); const handlers = [ @@ -185,7 +188,7 @@ describe('ConnectionManager', () => { }); test('connectToCentralSystem/disconnectFromCentralSystem delegate to CentralConnection', () => { - const cm = new ConnectionManager('p.proto', 'c:1'); + const cm = new ConnectionManager('p.proto', 'c:1', caCertPath, certPath, keyPath); // @ts-ignore cm['_peerCtor'] = Peer2PeerCtorMock; cm.connectToCentralSystem(); @@ -195,13 +198,13 @@ describe('ConnectionManager', () => { expect(centralDisconnectMock).toHaveBeenCalled(); }); - test('createNewConnection: adds to sending map, sets CONNECTED, logs', () => { - const cm = new ConnectionManager('p.proto', 'c:1'); + test('createNewConnection: adds to sending map, sets CONNECTED, logs', async () => { + const cm = new ConnectionManager('p.proto', 'c:1', caCertPath, certPath, keyPath); // @ts-ignore cm['_peerCtor'] = Peer2PeerCtorMock; - const conn = cm.createNewConnection('peer-A', ConnectionDirection.SENDING, 'tok123'); + const conn = await cm.createNewConnection('peer-A', ConnectionDirection.SENDING, 'tok123'); - expect(connectionCtorMock).toHaveBeenCalledWith('tok123', 'peer-A', ConnectionDirection.SENDING, expect.any(Function)); + expect(connectionCtorMock).toHaveBeenCalledWith('tok123', 'peer-A', ConnectionDirection.SENDING, expect.any(Function), expect.any(Object)); expect(conn.status).toBe(ConnectionStatus.CONNECTED); // Exposed via connections getter @@ -212,19 +215,19 @@ describe('ConnectionManager', () => { expect(infoMessageMock).toHaveBeenCalledWith(expect.stringContaining('Connection with peer-A has been estabilished')); }); - test('createNewConnection: adds to receiving map if direction is RECEIVING', () => { - const cm = new ConnectionManager('p.proto', 'c:1'); - cm.createNewConnection('peer-B', ConnectionDirection.RECEIVING); + test('createNewConnection: adds to receiving map if direction is RECEIVING', async () => { + const cm = new ConnectionManager('p.proto', 'c:1', caCertPath, certPath, keyPath); + await cm.createNewConnection('peer-B', ConnectionDirection.RECEIVING); const { sending, receiving } = cm.connections; expect(sending.length).toBe(0); expect(receiving.length).toBe(1); }); - test('getConnectionByAddress: returns by direction. Logs on invalid direction', () => { - const cm = new ConnectionManager('p.proto', 'c:1'); - const s = cm.createNewConnection('s-1', ConnectionDirection.SENDING); - const r = cm.createNewConnection('r-1', ConnectionDirection.RECEIVING); + test('getConnectionByAddress: returns by direction. Logs on invalid direction', async () => { + const cm = new ConnectionManager('p.proto', 'c:1', caCertPath, certPath, keyPath); + const s = await cm.createNewConnection('s-1', ConnectionDirection.SENDING); + const r = await cm.createNewConnection('r-1', ConnectionDirection.RECEIVING); expect(cm.getConnectionByAddress('s-1', ConnectionDirection.SENDING)).toBe(s); expect(cm.getConnectionByAddress('r-1', ConnectionDirection.RECEIVING)).toBe(r); @@ -235,10 +238,10 @@ describe('ConnectionManager', () => { expect(errorMessageMock).toHaveBeenCalledWith('Invalid connection direction: 999'); }); - test('connections getter: returns arrays (copies) of maps', () => { - const cm = new ConnectionManager('p.proto', 'c:1'); - cm.createNewConnection('a', ConnectionDirection.SENDING); - cm.createNewConnection('b', ConnectionDirection.RECEIVING); + test('connections getter: returns arrays (copies) of maps', async () => { + const cm = new ConnectionManager('p.proto', 'c:1', caCertPath, certPath, keyPath); + await cm.createNewConnection('a', ConnectionDirection.SENDING); + await cm.createNewConnection('b', ConnectionDirection.RECEIVING); const { sending, receiving } = cm.connections; expect(Array.isArray(sending)).toBe(true); @@ -248,8 +251,8 @@ describe('ConnectionManager', () => { }); test('listenForPeers: creates server, registers service, binds & logs', async () => { - const cm = new ConnectionManager('p.proto', 'c:1'); - await cm.listenForPeers(50099, 'http://localhost:41000/api/'); + const cm = new ConnectionManager('p.proto', 'c:1', caCertPath, certPath, keyPath); + await cm.listenForPeers(50099, getTestCerts().clientKey, getTestCerts().clientCert, 'http://localhost:41000/api/'); const ServerCtor = (grpc.Server as any).mock; expect(ServerCtor).toBeDefined(); @@ -266,24 +269,24 @@ describe('ConnectionManager', () => { }); test('listenForPeers: calling twice shuts previous server down', async () => { - const cm = new ConnectionManager('p.proto', 'c:1'); - await cm.listenForPeers(50100, 'http://localhost:41000/api/'); + const cm = new ConnectionManager('p.proto', 'c:1', caCertPath, certPath, keyPath); + await cm.listenForPeers(50100, getTestCerts().clientKey, getTestCerts().clientCert, 'http://localhost:41000/api/'); const firstServer = (grpc.Server as any).mock.results[0].value; - await cm.listenForPeers(50101, 'http://localhost:41000/api/'); + await cm.listenForPeers(50101, getTestCerts().clientKey, getTestCerts().clientCert, 'http://localhost:41000/api/'); expect(firstServer.forceShutdown).toHaveBeenCalled(); }); test('p2p Fetch: registers new incoming receiving connection, forwards to local API, maps response', async () => { - const cm = new ConnectionManager('p.proto', 'c:1'); - await cm.listenForPeers(50102, 'http://local/api/'); + const cm = new ConnectionManager('p.proto', 'c:1', caCertPath, certPath, keyPath); + await cm.listenForPeers(50102, getTestCerts().clientKey, getTestCerts().clientCert, 'http://local/api/'); // Prepare incoming call and callback const call = { getPeer: () => 'client-42', request: { method: 'post', - path: 'echo', + path: 'pong', headers: { 'content-type': 'application/json' }, body: Buffer.from(JSON.stringify({ ping: true })), }, @@ -306,7 +309,7 @@ describe('ConnectionManager', () => { const before = cm.connections.receiving.length; await capturedServerImpl.Fetch(call, callback); - expect(global.fetch).toHaveBeenCalledWith('http://local/api/echo', { + expect(global.fetch).toHaveBeenCalledWith('http://local/api/pong', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ ping: true }), @@ -330,10 +333,10 @@ describe('ConnectionManager', () => { }); test('p2p Fetch: uses existing receiving connection when present (no duplicate creation)', async () => { - const cm = new ConnectionManager('p.proto', 'c:1'); - await cm.listenForPeers(50103, 'http://local/api/'); + const cm = new ConnectionManager('p.proto', 'c:1', caCertPath, certPath, keyPath); + await cm.listenForPeers(50103, getTestCerts().clientKey, getTestCerts().clientCert, 'http://local/api/'); - cm.createNewConnection('client-77', ConnectionDirection.RECEIVING); + await cm.createNewConnection('client-77', ConnectionDirection.RECEIVING); // @ts-ignore global.fetch.mockResolvedValue({ @@ -374,8 +377,8 @@ describe('ConnectionManager', () => { }); test('p2p Fetch: on forward error returns INTERNAL and logs error', async () => { - const cm = new ConnectionManager('p.proto', 'c:1'); - await cm.listenForPeers(50104, 'http://local/api/'); + const cm = new ConnectionManager('p.proto', 'c:1', caCertPath, certPath, keyPath); + await cm.listenForPeers(50104, getTestCerts().clientKey, getTestCerts().clientCert, 'http://local/api/'); // @ts-ignore global.fetch.mockRejectedValue(new Error('err')); diff --git a/Tokenization/backend/wrapper/src/test/connection/Connection.test.ts b/Tokenization/backend/wrapper/src/test/connection/Connection.test.ts index 8937e9d5e..97f4556db 100644 --- a/Tokenization/backend/wrapper/src/test/connection/Connection.test.ts +++ b/Tokenization/backend/wrapper/src/test/connection/Connection.test.ts @@ -32,7 +32,7 @@ jest.mock( return { ...original, credentials: { - createInsecure: jest.fn(() => ({ insecure: true })), + createSsl: jest.fn(() => ({ insecure: true })), }, }; }, @@ -40,6 +40,7 @@ jest.mock( ); import * as grpc from '@grpc/grpc-js'; +import { getTestCerts } from '../testCerts/testCerts'; describe('Connection', () => { beforeEach(() => { @@ -48,9 +49,9 @@ describe('Connection', () => { }); test('constructor should create connection and set base state correctly', () => { - const conn = new Connection('tok', 'peer:50051', FAKE_DIRECTION, PeerCtorMock); + const conn = new Connection('tok', 'peer:50051', FAKE_DIRECTION, PeerCtorMock, getTestCerts()); - expect(grpc.credentials.createInsecure).toHaveBeenCalled(); + expect(grpc.credentials.createSsl).toHaveBeenCalled(); expect(PeerCtorMock).toHaveBeenCalledWith('peer:50051', { insecure: true }); expect(conn.token).toBe('tok'); @@ -60,21 +61,21 @@ describe('Connection', () => { }); test('getter/setter for token should work', () => { - const conn = new Connection('old', 'peer:1', FAKE_DIRECTION, PeerCtorMock); + const conn = new Connection('old', 'peer:1', FAKE_DIRECTION, PeerCtorMock, getTestCerts()); expect(conn.token).toBe('old'); conn.token = 'new-token'; expect(conn.token).toBe('new-token'); }); test('handleRevokeToken should clear token and status to UNAUTHORIZED', () => { - const conn = new Connection('secret', 'peer:x', FAKE_DIRECTION, PeerCtorMock); + const conn = new Connection('secret', 'peer:x', FAKE_DIRECTION, PeerCtorMock, getTestCerts()); conn.handleRevokeToken(); expect(conn.token).toBe(''); expect(conn.status).toBe(ConnectionStatus.UNAUTHORIZED); }); test('getter/setter for status should work', () => { - const conn = new Connection('t', 'a', FAKE_DIRECTION, PeerCtorMock); + const conn = new Connection('t', 'a', FAKE_DIRECTION, PeerCtorMock, getTestCerts()); conn.status = ConnectionStatus.UNAUTHORIZED; expect(conn.status).toBe(ConnectionStatus.UNAUTHORIZED); conn.status = ConnectionStatus.CONNECTED; @@ -82,12 +83,12 @@ describe('Connection', () => { }); test('getter for targetAddress should work', () => { - const conn = new Connection('t', 'host:1234', FAKE_DIRECTION, PeerCtorMock); + const conn = new Connection('t', 'host:1234', FAKE_DIRECTION, PeerCtorMock, getTestCerts()); expect(conn.targetAddress).toBe('host:1234'); }); test('fetch should throw if peer client is not attached', async () => { - const conn = new Connection('t', 'addr', FAKE_DIRECTION, PeerCtorMock); + const conn = new Connection('t', 'addr', FAKE_DIRECTION, PeerCtorMock, getTestCerts()); // @ts-ignore conn['_peerClient'] = undefined; @@ -95,7 +96,7 @@ describe('Connection', () => { }); test('fetch with defaults should work', async () => { - const conn = new Connection('t', 'addr', FAKE_DIRECTION, PeerCtorMock); + const conn = new Connection('t', 'addr', FAKE_DIRECTION, PeerCtorMock, getTestCerts()); lastPeerClient.Fetch.mockImplementation((req: any, cb: any) => { try { @@ -116,7 +117,7 @@ describe('Connection', () => { }); test('fetch builds request correctly and returns response', async () => { - const conn = new Connection('t', 'addr', FAKE_DIRECTION, PeerCtorMock); + const conn = new Connection('t', 'addr', FAKE_DIRECTION, PeerCtorMock, getTestCerts()); const body = Buffer.from('abc'); lastPeerClient.Fetch.mockImplementation((req: any, cb: any) => { @@ -142,7 +143,7 @@ describe('Connection', () => { }); test('fetch should convert Uint8Array to Buffer', async () => { - const conn = new Connection('t', 'addr', FAKE_DIRECTION, PeerCtorMock); + const conn = new Connection('t', 'addr', FAKE_DIRECTION, PeerCtorMock, getTestCerts()); const body = new Uint8Array([1, 2, 3]); lastPeerClient.Fetch.mockImplementation((req: any, cb: any) => { @@ -160,7 +161,7 @@ describe('Connection', () => { }); test('fetch should convert string to Buffer', async () => { - const conn = new Connection('t', 'addr', FAKE_DIRECTION, PeerCtorMock); + const conn = new Connection('t', 'addr', FAKE_DIRECTION, PeerCtorMock, getTestCerts()); const body = 'żółć & äöü'; // handling special chars lastPeerClient.Fetch.mockImplementation((req: any, cb: any) => { @@ -177,13 +178,13 @@ describe('Connection', () => { }); test('fetch should reject if body is not allowed', async () => { - const conn = new Connection('t', 'addr', FAKE_DIRECTION, PeerCtorMock); + const conn = new Connection('t', 'addr', FAKE_DIRECTION, PeerCtorMock, getTestCerts()); // @ts-ignore await expect(conn.fetch({ body: { not: 'allowed' } })).rejects.toThrow('Body must be a string/Buffer/Uint8Array'); }); test('fetch should propagate errors from peer', async () => { - const conn = new Connection('t', 'addr', FAKE_DIRECTION, PeerCtorMock); + const conn = new Connection('t', 'addr', FAKE_DIRECTION, PeerCtorMock, getTestCerts()); const err = new Error('err'); lastPeerClient.Fetch.mockImplementation((_req: any, cb: any) => cb(err)); @@ -191,7 +192,7 @@ describe('Connection', () => { }); test('fetch should map response', async () => { - const conn = new Connection('t', 'addr', FAKE_DIRECTION, PeerCtorMock); + const conn = new Connection('t', 'addr', FAKE_DIRECTION, PeerCtorMock, getTestCerts()); const payload = { a: 1, b: 'x' }; lastPeerClient.Fetch.mockImplementation((_req: any, cb: any) => diff --git a/Tokenization/backend/wrapper/src/test/testCerts/ca.crt b/Tokenization/backend/wrapper/src/test/testCerts/ca.crt new file mode 100644 index 000000000..899799b3c --- /dev/null +++ b/Tokenization/backend/wrapper/src/test/testCerts/ca.crt @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIUA3wFlpIAu9PcCYrsZQwml1VBbBIwDQYJKoZIhvcNAQEL +BQAwMzELMAkGA1UEBhMCUEwxDTALBgNVBAoMBFRlc3QxFTATBgNVBAMMDFRlc3Qg +Um9vdCBDQTAeFw0yNTA5MjUyMDQyMDlaFw0zNTA5MjMyMDQyMDlaMDMxCzAJBgNV +BAYTAlBMMQ0wCwYDVQQKDARUZXN0MRUwEwYDVQQDDAxUZXN0IFJvb3QgQ0EwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDwQYsYLOQyRG5nXHLzTuAXIDJl +nV6eoAOsDItqGCiOVy9T6Y0g+4RcSf99i2DRsOVLGg/jQHpAmo765XVObPiEmE+f +rxgLclXqXNlRQdiaK9LRPIUF0TCcyFJGTVMzHTFt0jHEdiP/2++egoAA/pP1al4y +XwJjWkGgLU7GA/Eou2Gfdc7mxZ4ZtmxkEh7OEqSOVgR+qi1fTfXfTyXF+s1PG4pu +tGNCg/zTh1rlMS9kWcoTF4Bk/RU5nKZ1zOAWOgffd72JiWyoGSYy0Yk2e1fhGgG5 +cWMZCDiOCAdNgwTtVKn8IfTgoZJpXhoegMVH44CDkfb7bkp3ETGfMzKncv4v5C2P +11HjWYOrmQ1bgpy+lR9RR+7Oem9So49UsayqqAYmquOCycnGT9wOX+4qsalnZd/O +J4mHtmUGiK0Lkvfh3X5T7wE7yLuiYJtG4XYwREZkBlusxGyX0lRvWJq3lI93EFqt +p7UWtB+1OjabUpCadypzkbvA19DJ4fhzaPh+A3tfn42RnlVAYAazNRiAy90G4/Mh +MPZzKqe0DTp2i2WG5/NTEivKoSVD27vVKp5Tk4LhgAMmZ/F4uFT0TBGva4q+tEUW +jv6mLKpCtQzgqsjNCSKL5pWnymDme7UN/mGe1ttU8xrI9pyGA5tSb9kO0VkBCcVd +R1mOOjZKx0iR3ctG+QIDAQABo2YwZDASBgNVHRMBAf8ECDAGAQH/AgEBMA4GA1Ud +DwEB/wQEAwIBBjAdBgNVHQ4EFgQU41jbLgGadHiLx0921bLDou0kHQEwHwYDVR0j +BBgwFoAU41jbLgGadHiLx0921bLDou0kHQEwDQYJKoZIhvcNAQELBQADggIBAN+W +xYNn4nGtkEfNaVP46GckMQU8Lq6asXIj/L830JHq+R0gJeiURBqBs5snRqBSx6/W +3Xn+IfFGUttnEPlAkxXsg5R/JnQnggfyQX7Hk3SwedKH0uUqX7NLqAv7tfZJPGU9 +HSuvOzThvSX8N3Vr0zLVJDT94WqXX69HoSp6BZnriVss5RWMvM51QsNirj5379CX +iU7BCQdKBQfGSCQW0Qr4GWZYZHuhpXHcsfrrQ66krdqGLgkOxe3xQgvFQSWEf4OU +d/pqlRIOCnku4g2JR/ph+tuLtxmHdidNBjP27mrtrKx4MsaqimxAYOuHTkni8cLF +01IDq95txBs1fShWE5ritJh5b03ZVmDS0uiVH2IGPBmxz08ysJdUAm6uGJWg3D5X +nJBpJbqzYe6wrZDB48s0yZwo6FX5gfoAG6OR0iWfXMsOrpMOxFz/A739JjxcoFDT +P5qct/z92obgFqp0w/RN/8Dotaw00l5P1IenCE42fLuARelrS8jFKrrjUr2+0Occ +CJ/3us1j7Ln5gYWSlWHTjDRwSyaji3Gi4mnduQUsdkIpI7grh4FGULNOLOZZf3Rj +fKlP9kW5m7MB196MYjQrQXTZM1ZUY5yEeCspsb0UaD78Oq5qXSFfGFZ63BmxPMvi +RzP8neThIVB948nZ0GYMc3SIHBFvwQpFZgkuz2+0 +-----END CERTIFICATE----- diff --git a/Tokenization/backend/wrapper/src/test/testCerts/centralSystem/central-system.crt b/Tokenization/backend/wrapper/src/test/testCerts/centralSystem/central-system.crt new file mode 100644 index 000000000..dd67e5dac --- /dev/null +++ b/Tokenization/backend/wrapper/src/test/testCerts/centralSystem/central-system.crt @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIExzCCAq+gAwIBAgIUG2HcUzPbDD8biqumq+ISyohyeYIwDQYJKoZIhvcNAQEL +BQAwMzELMAkGA1UEBhMCUEwxDTALBgNVBAoMBFRlc3QxFTATBgNVBAMMDFRlc3Qg +Um9vdCBDQTAeFw0yNTA5MjUyMDQ5NDRaFw0yNjA5MjUyMDQ5NDRaMEkxCzAJBgNV +BAYTAlBMMRcwFQYDVQQKDA5FeGFtcGxlQ28gVGVzdDEhMB8GA1UEAwwYY2VudHJh +bC5zeXN0ZW0uc3ZjLmxvY2FsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA6PdQdC5ol4niS1fiXwiJjEhfvPIAhj+LLLaHv1VG71sS9VmnsoEVJMfGqrkO +FkHrHFRFc1UJKi1se1r4NSlPsSPmTOj9KCgp5WSTxrww6X9hniWLCgC1S2fbmrWQ +O07D/qOGpO1GRgqL1KbVdHDZxhLa4MXevRnlgd2VcY1KaXT15BTQcJRJR+I9iIJF +HkUCdrLPjoJvS2G8gRezrRVC+EgrxTfJOQ2rcUunDDhn+f//cTulWjZ/R/Jy9Byy +qFTGPiwwnLkVBQGLhBSRNEYSvzxpgxipVOTLKPZYHNKyITibno3cYiaS+qCI0GG2 +wY7jrh44I6yQ/dCYMyuu7yxT0QIDAQABo4G8MIG5MAkGA1UdEwQCMAAwDgYDVR0P +AQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA9BgNVHREE +NjA0ghhjZW50cmFsLnN5c3RlbS5zdmMubG9jYWyCB2NlbnRyYWyCCWxvY2FsaG9z +dIcEfwAAATAdBgNVHQ4EFgQUYLT4W+0UJcnlfU4VQMjbSHS5gYkwHwYDVR0jBBgw +FoAU41jbLgGadHiLx0921bLDou0kHQEwDQYJKoZIhvcNAQELBQADggIBALXQVFHu +z1GDyGNUNN5fEonbv4V8MGO8RU6I0O4ccuYqVGBvDUWVSMFtT4Qc60CcXZF2V8p6 +3FP6PAmDK12mMswWuc7lvgAldxOC+PwC4K8fbu9fl+KbP8lsEikVwqiLWXWOGiRh +xlgFhzYTvgEwa3Ta5hqQPsCnY5+/ybF4l7yxZgL0Qp/OWQJgtYd8AeAWpVayhpzw +WojpJ6x56PIZI9vJ00RmMOQib5fl6e4fKKj2ACt8uorG9kL/sWId2BnCJKFjSl8d +4krZr4ocGYK+yK7KgrunqAXy/NPk1hC/oRryaSznC3oh+83P3emjuf//t0FYhSUQ +g8Urku1v9916ulTM8DsF/eSr8z6BMod60fDrpaDnSY+4hcpJuOMfN1pOWcmQVejW +TgX+pwyKpRnvIOlm7NRz+gv31xMEu/McMQQ/oC9qYh7frOsO5pHt1kI7bJ2X69Dj +rz+y7SoW4Ur/pbevfyWu4kBMdo8Dj1zF2GwYFHDzjU0R814fBHEnkN5Jxnk+ahYl +yNwWnjphabPSGRx3nIgCJ600HvgAK1uKgdTCRoiYhkDxcve3m5wEE9UCgLrcp8HL +ushY02iXu9TsPuIA/3bBeLVeI0JxnyxYjP1YuGF2i2fxF/rZxhVXl12xc2oJAytA +6CRc2j0K3JcjgG5jdt3H36LwPnvQ9HPfF200 +-----END CERTIFICATE----- diff --git a/Tokenization/backend/wrapper/src/test/testCerts/centralSystem/central-system.key b/Tokenization/backend/wrapper/src/test/testCerts/centralSystem/central-system.key new file mode 100644 index 000000000..22044072d --- /dev/null +++ b/Tokenization/backend/wrapper/src/test/testCerts/centralSystem/central-system.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDo91B0LmiXieJL +V+JfCImMSF+88gCGP4sstoe/VUbvWxL1WaeygRUkx8aquQ4WQescVEVzVQkqLWx7 +Wvg1KU+xI+ZM6P0oKCnlZJPGvDDpf2GeJYsKALVLZ9uatZA7TsP+o4ak7UZGCovU +ptV0cNnGEtrgxd69GeWB3ZVxjUppdPXkFNBwlElH4j2IgkUeRQJ2ss+Ogm9LYbyB +F7OtFUL4SCvFN8k5DatxS6cMOGf5//9xO6VaNn9H8nL0HLKoVMY+LDCcuRUFAYuE +FJE0RhK/PGmDGKlU5Mso9lgc0rIhOJuejdxiJpL6oIjQYbbBjuOuHjgjrJD90Jgz +K67vLFPRAgMBAAECggEABeW00KwYE7X214drAJLbwIRYgBT0NHHJWSFpwEstV4PL +sBBL8XXZDixMeCflFmUmyXnMpEXDzKCHvXupCtd33/kTrGC9f9W8ccUhBIfhCRgj +ZXh305H/BOClK35rH0U4KusCzov/GmjL718lyiPNL3lstwHrSIguSiJM1SoJdy/l +aCIif6v5l8/DItDSavQxgI97AC0u7lLJadB460XqeJi3vYPzBg6WxEMMdqRhzzOH +1XIsv+IzHabJmt5J3wFsv2lk1v0Irny+CtWtZTM5mTVr4FcgefNx0t8pVSxRXf9F +DjXXbTSrlPVjZVPENrAr6Sl5YyJeK/UABiRl/BLxDQKBgQD3SQ0qZw41JsCFj6W7 +DGyKwFVNvFibzO2Hb6grHwV3iJKHnppFFpanEMhLiZzgdeTGpQFpR4iM6Ne8ewFQ +zu2P91cGjMBP4HqP/RWtGStZ6X/Br2I66sra6BXTsXGNXSr330xzYiwbDrKtr7rv +Q79ySfRRlwWpTeT6RubbqxB3dwKBgQDxLRPlVYaALeJ1rxuds59NeC5bJGHS8+1h +kiXQgKmG1/5saLUyWXWAT5FJqG/xvtiN+vtmf8jL+KhUYpga0kJeuykR7loJRGdr +7h4uMYmzrP7+5P6tNOBqawGCDZzutXMq2TIJAwy1s+tVE4KWWcv0qE8op4on+/f2 +8A+5HWNw9wKBgHGjU3aJ92B7l3uJQMsNcY/txQW9KScn7HwR1sFCNzvwOg4y14gq +Uj8iGjmEWuBXrTOQPm7IHbtLgWCvUjJ1dXx0WLy8z9+lNA2Za22ppF9kS36Rf129 +6kzg3K70207wYr+YEUTw933Tqk7g89HiW0dFLw6TjVl5X2GYVZzbJu0PAoGBAL6b +BLVkIXeeS/L8YJQDSOx+BgzsNQ/2zm4lhhNCDDlQ7XgaTNItF4s/1zBimY5yaU3U +xOmeJkDmFYsTnOjdsaySuIO+X5QhZqdLOrkBV7YUDDfBHXIgbxhL15ZEUfnql8mO +fFfY/CuCtYO4dqWC9Ik4l88mki7FmZSk55hCnLvDAoGBAKEjQS4GVd+9Ku/HVi71 +OG2vfKEyGfTyyOB/3c99BMWNOkQfMNrxuHR8XhTPi2LvFE9nndBlMuCLcRS417iL +Gvd7FazAaO1lRO1tlqOym1z2gx/j2k+2BrIV+vOzg3PEJeXZAihLHTSsfhNIc4xW +ZeR3z5nE4Pz9AOr/YFKi9Xqm +-----END PRIVATE KEY----- diff --git a/Tokenization/backend/wrapper/src/test/testCerts/clientListener/client-b-client.crt b/Tokenization/backend/wrapper/src/test/testCerts/clientListener/client-b-client.crt new file mode 100644 index 000000000..08482178c --- /dev/null +++ b/Tokenization/backend/wrapper/src/test/testCerts/clientListener/client-b-client.crt @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIEuDCCAqCgAwIBAgIURLvrnhcyzZ0UTbuI1tHGoXXFWc0wDQYJKoZIhvcNAQEL +BQAwMzELMAkGA1UEBhMCUEwxDTALBgNVBAoMBFRlc3QxFTATBgNVBAMMDFRlc3Qg +Um9vdCBDQTAeFw0yNTA5MjUyMDU2MTdaFw0yNjA5MjUyMDU2MTdaMEYxCzAJBgNV +BAYTAlBMMRcwFQYDVQQKDA5FeGFtcGxlQ28gVGVzdDEeMBwGA1UEAwwVY2xpZW50 +LWItY2xpZW50LmxvY2FsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +xxqgLBJFeQgLcRvkPj6S16guSJsJN/MJxGAnmWQF3utr9neUXeID2KUEMNUT2b73 +EO/LD3z+8JvDhfG4J9Y1/ny/CuaAbmHKXH/ot0nIwWjd11yXjhWyXQuNqGHiuniX +2KaDH5+rIPXYU6eUjx+V3VX0iiYEFUizPRUhzmJ8AONSu43OuMdhZo7Frb4qUc4/ +ioVqhiAb3Sdm/nKDWI9OQR6Ux8Mc2OaPY3wQA4r3ZBz9oJU3G7BL85bclmk1PDZh +R6T0/oo09FiTj8zTZ8vooarJH+TAD2EBsTwfIdBT1yuECAueztxaos2q2TUsJz3f +6hQaEnOqiz6nZ8FceXudgQIDAQABo4GwMIGtMAkGA1UdEwQCMAAwDgYDVR0PAQH/ +BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMCMDsGA1UdEQQ0MDKCFWNsaWVudC1i +LWNsaWVudC5sb2NhbIIIY2xpZW50LWKCCWxvY2FsaG9zdIcEfwAABTAdBgNVHQ4E +FgQUTzAFrkegQMRXfjt4djXC5N4YHnYwHwYDVR0jBBgwFoAU41jbLgGadHiLx092 +1bLDou0kHQEwDQYJKoZIhvcNAQELBQADggIBAB+vXi5ThGYQt7RUx92Vjy2++Yiz +WztajTms/ac2B2JZbW9dl1PYv+t5hrkiXp8Q21eWq7ZPbd+7QbzvQsOxSGEKNBQp +0A4CeI67YkbYjJPzxjpDxiYo8+wmOtGgWRok9P4FLN5dGVo9/3JQHrn+3m20/6DT +FqTqm+mC3FkSjAJzPnd1wOmPxS2xENE/L5x4KHR91xkCeaHXjQky9gQs7vzY4uto +kiuB/elxFq2l4XN4BI6A65261AyelB15qpTKBGICGNO56hIcrGIjoFyYQnKyJrk4 +yylH0LtACnEV0lzS9l7FtRNERQ5xDBRvcqK7X7XCwkKqXfYN04STiVEEqhSoYDF2 +INJeV2FN7CJQueCuiKqG1S+zd7uXJ9a7dx5Qk3boJVBfX2WjK5BbiSpjoq+x7tCG +zwtHpBDaB8K6Ee0XICFcDZlPB214XaGjrx6iavs5ppP6261f20QMI3xtTVPapMjT +bmC2AoARTdaIxoQaSyCE+QImVxkhHYBePpIHAnAZhBPzF46u+APRAOpklTJ6J+uv +VWCwm71ebXUTSZ7alsScqH+zDmYMYpGuar3qcPHnOJDo0XDoSMYl3kLDrK0UoHci +mtjRzuYBlKyEX8LcqY9teVuarnvxaNtYGbF98L3nFSLGnUfzaCMIbA4xtJcZ7DXu +J9l3OBcmHYWG52f2 +-----END CERTIFICATE----- diff --git a/Tokenization/backend/wrapper/src/test/testCerts/clientListener/client-b.key b/Tokenization/backend/wrapper/src/test/testCerts/clientListener/client-b.key new file mode 100644 index 000000000..b2fc830da --- /dev/null +++ b/Tokenization/backend/wrapper/src/test/testCerts/clientListener/client-b.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDHGqAsEkV5CAtx +G+Q+PpLXqC5Imwk38wnEYCeZZAXe62v2d5Rd4gPYpQQw1RPZvvcQ78sPfP7wm8OF +8bgn1jX+fL8K5oBuYcpcf+i3ScjBaN3XXJeOFbJdC42oYeK6eJfYpoMfn6sg9dhT +p5SPH5XdVfSKJgQVSLM9FSHOYnwA41K7jc64x2FmjsWtvipRzj+KhWqGIBvdJ2b+ +coNYj05BHpTHwxzY5o9jfBADivdkHP2glTcbsEvzltyWaTU8NmFHpPT+ijT0WJOP +zNNny+ihqskf5MAPYQGxPB8h0FPXK4QIC57O3FqizarZNSwnPd/qFBoSc6qLPqdn +wVx5e52BAgMBAAECggEAA0i8JZ3ziWiJj8cO/7vWfjom8UmlYEfg/F09qfkNY7zs +Xfdg+h91QsiOBiQtnKTavGvIJKxCJEPdeMMg739ICreSCyL8MVXpmZb+hq9v4UjS +h+/eDBjthT1gi8t5iuvcTVWJyia/Et8bP13/RFEYDruROgogfR1i33oOwbG8K+OM +iDSIRo9swBaVNqFuWZKqZr1pjY9KUfh4jnSA+x1hueVHREJYt6qvX2KNhHFhyfyo +RRuLSKmz7Xx3sTu7qQD1NRKsD/8lM4oZWGPTit0F6qx+FfzbI0nBn9In8czmrPcm +VqwdgT5aR5I6lfzAj6kMHlmY2n0f4J0Hk6Ha6MgkJQKBgQD6AnjeToUw6PcIbTrJ +18mDfzOCMhQjQHDXipHrJ06K65B+4XX8/oTkRahyeqn4sbKKHP11e6bsDPVNRK0P +9G3wYw7nPNcGtF1pojWvh0HxBTJ/iugDgZT5ngtwbydvAT7+m6De3DicEJo5ZUPP +IAweL+qf9Nh30PtKiOSgJ2GrRwKBgQDL3+eX0sQg+dfYb3zAJmsLwXoY4fAOGc1o +KI4UI26Bq4TPrJv9guaDjSYNE62M7+H7vWudlG+KPxt6jNaxxpIo5J1c7qVl+gx6 +kTDZ053peVLtWJzLrRT9/e238bCYnKfFpKwRzUGT9kEkMvmFqb56lnhKBXS/OPuP +3dAOWHvE9wKBgAJM4YXSHSGdEyDNuHvA84a1NekdwtesMR2alcsfGnbmwfaY5ngE +c36SMYGUJVo3cFga+i4JjDihyeQDHMCH1DchAjMYeTYDlNRy/KF30iCAlr1brtTR +bWh6jspjC27XCRhYoDtMtWyiLnkWuHAAcHwansMIArHfh2BhMBFVK23jAoGAGwrf +GFdfppQdWlsnbAFsj4mhXW2SvvwTL+65MdilTtPmcPmPU2gqlWaClpd2nMww6Ihu +nt9SkD7gsTe/PqN9PaldajdJfyZUw2lA1pPoTVDHfC4V1jpmH26wOob3ira01lWK +cW4NdcfjSh7s1Br45h/RYtgobTjsvV+Jum1oNW8CgYAeY82AEydYzqjZRH66xAjQ +pSxaT6B2YS5JqJFbRAtHA/ndApHbW7ALX5vqoJ6EkJ+aORQQMZUkX32n3Y0WFNE2 +FR9JEcnBjimwmG+JTBRCk1luamsZZpH/sHZohH1bsq9+dGo9xIeeBdi5DPxpdsKM +6NuWljVhDbuJeRiamlo5tg== +-----END PRIVATE KEY----- diff --git a/Tokenization/backend/wrapper/src/test/testCerts/clientListener/client-b.pub.pem b/Tokenization/backend/wrapper/src/test/testCerts/clientListener/client-b.pub.pem new file mode 100644 index 000000000..cf74b90e7 --- /dev/null +++ b/Tokenization/backend/wrapper/src/test/testCerts/clientListener/client-b.pub.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxxqgLBJFeQgLcRvkPj6S +16guSJsJN/MJxGAnmWQF3utr9neUXeID2KUEMNUT2b73EO/LD3z+8JvDhfG4J9Y1 +/ny/CuaAbmHKXH/ot0nIwWjd11yXjhWyXQuNqGHiuniX2KaDH5+rIPXYU6eUjx+V +3VX0iiYEFUizPRUhzmJ8AONSu43OuMdhZo7Frb4qUc4/ioVqhiAb3Sdm/nKDWI9O +QR6Ux8Mc2OaPY3wQA4r3ZBz9oJU3G7BL85bclmk1PDZhR6T0/oo09FiTj8zTZ8vo +oarJH+TAD2EBsTwfIdBT1yuECAueztxaos2q2TUsJz3f6hQaEnOqiz6nZ8FceXud +gQIDAQAB +-----END PUBLIC KEY----- diff --git a/Tokenization/backend/wrapper/src/test/testCerts/clientListenerServer/client-b-server.crt b/Tokenization/backend/wrapper/src/test/testCerts/clientListenerServer/client-b-server.crt new file mode 100644 index 000000000..949b07297 --- /dev/null +++ b/Tokenization/backend/wrapper/src/test/testCerts/clientListenerServer/client-b-server.crt @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEqjCCApKgAwIBAgIUSKJ0QtJi4yK32QhGXdgKbfADC3owDQYJKoZIhvcNAQEL +BQAwMzELMAkGA1UEBhMCUEwxDTALBgNVBAoMBFRlc3QxFTATBgNVBAMMDFRlc3Qg +Um9vdCBDQTAeFw0yNTA5MjUyMDU2MDhaFw0yNjA5MjUyMDU2MDhaMD8xCzAJBgNV +BAYTAlBMMRcwFQYDVQQKDA5FeGFtcGxlQ28gVGVzdDEXMBUGA1UEAwwOY2xpZW50 +LWIubG9jYWwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDHGqAsEkV5 +CAtxG+Q+PpLXqC5Imwk38wnEYCeZZAXe62v2d5Rd4gPYpQQw1RPZvvcQ78sPfP7w +m8OF8bgn1jX+fL8K5oBuYcpcf+i3ScjBaN3XXJeOFbJdC42oYeK6eJfYpoMfn6sg +9dhTp5SPH5XdVfSKJgQVSLM9FSHOYnwA41K7jc64x2FmjsWtvipRzj+KhWqGIBvd +J2b+coNYj05BHpTHwxzY5o9jfBADivdkHP2glTcbsEvzltyWaTU8NmFHpPT+ijT0 +WJOPzNNny+ihqskf5MAPYQGxPB8h0FPXK4QIC57O3FqizarZNSwnPd/qFBoSc6qL +PqdnwVx5e52BAgMBAAGjgakwgaYwCQYDVR0TBAIwADAOBgNVHQ8BAf8EBAMCBaAw +EwYDVR0lBAwwCgYIKwYBBQUHAwEwNAYDVR0RBC0wK4IOY2xpZW50LWIubG9jYWyC +CGNsaWVudC1igglsb2NhbGhvc3SHBH8AAAQwHQYDVR0OBBYEFE8wBa5HoEDEV347 +eHY1wuTeGB52MB8GA1UdIwQYMBaAFONY2y4BmnR4i8dPdtWyw6LtJB0BMA0GCSqG +SIb3DQEBCwUAA4ICAQAfNbYmzhNKTJT+e4VZaJdqxFmsm2oHUtRXHVKHcPKYZEd5 +ujKtIjbdhjQ82Rhfmof9cydvAK8qEm+ydwUBvN/9q7Dd4V3rafKbsrVizB63HbSl +AZujvRxwIKF9Gzc3Sqliy1/LZYfk+FHHooUtzmL/K5cTVlHaBqT8m4zmqp4djFjQ +YnshmdaMBmgmgluO4/JyPswFHpRlKcp29GA8n39/+25yFyiIunryypCwPAFb/owh +sXVshhs04+JUwEdWGHoesbhjbIik706poPOlvUf9xHDcB6PXIwPmo08+1u2QEaV3 +Dqw4TjNcUA7OJdxzKhF0J4tVXAD1Hg2yrOYedtTeXDPntjgb3Uq4DWnAAJ+fMF1U +T1vJogzgzq6y5jl0KClqpSA9dOKt4IG2hL5WcoudyTk0ao4wkVdOQwR1vNz25Fub +LSl582PpHxvK3GYk4PegoPnHzz02IN4B+AxUDvXPH4HIZ4QtubnX4x4j8Kk4bPCK +ZBBA3t8K/6W/bjOB0Xh+LyXf9dIndVmFHC0iOf8YQgyNHhXhzpbpM/LWdDk3aEiG +6y99wNdWuu7F3T7wFk7dDhxxroHqxUjsP8921LD0JDqdryWQK6wE23fSpiThOEDN +o2FnBG3514QI/v6zlUWY4LtqJO2UCwPLbWAsuXd+AxWOO3urg0ucW0r1UNzmIQ== +-----END CERTIFICATE----- diff --git a/Tokenization/backend/wrapper/src/test/testCerts/clientListenerServer/client-b.key b/Tokenization/backend/wrapper/src/test/testCerts/clientListenerServer/client-b.key new file mode 100644 index 000000000..b2fc830da --- /dev/null +++ b/Tokenization/backend/wrapper/src/test/testCerts/clientListenerServer/client-b.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDHGqAsEkV5CAtx +G+Q+PpLXqC5Imwk38wnEYCeZZAXe62v2d5Rd4gPYpQQw1RPZvvcQ78sPfP7wm8OF +8bgn1jX+fL8K5oBuYcpcf+i3ScjBaN3XXJeOFbJdC42oYeK6eJfYpoMfn6sg9dhT +p5SPH5XdVfSKJgQVSLM9FSHOYnwA41K7jc64x2FmjsWtvipRzj+KhWqGIBvdJ2b+ +coNYj05BHpTHwxzY5o9jfBADivdkHP2glTcbsEvzltyWaTU8NmFHpPT+ijT0WJOP +zNNny+ihqskf5MAPYQGxPB8h0FPXK4QIC57O3FqizarZNSwnPd/qFBoSc6qLPqdn +wVx5e52BAgMBAAECggEAA0i8JZ3ziWiJj8cO/7vWfjom8UmlYEfg/F09qfkNY7zs +Xfdg+h91QsiOBiQtnKTavGvIJKxCJEPdeMMg739ICreSCyL8MVXpmZb+hq9v4UjS +h+/eDBjthT1gi8t5iuvcTVWJyia/Et8bP13/RFEYDruROgogfR1i33oOwbG8K+OM +iDSIRo9swBaVNqFuWZKqZr1pjY9KUfh4jnSA+x1hueVHREJYt6qvX2KNhHFhyfyo +RRuLSKmz7Xx3sTu7qQD1NRKsD/8lM4oZWGPTit0F6qx+FfzbI0nBn9In8czmrPcm +VqwdgT5aR5I6lfzAj6kMHlmY2n0f4J0Hk6Ha6MgkJQKBgQD6AnjeToUw6PcIbTrJ +18mDfzOCMhQjQHDXipHrJ06K65B+4XX8/oTkRahyeqn4sbKKHP11e6bsDPVNRK0P +9G3wYw7nPNcGtF1pojWvh0HxBTJ/iugDgZT5ngtwbydvAT7+m6De3DicEJo5ZUPP +IAweL+qf9Nh30PtKiOSgJ2GrRwKBgQDL3+eX0sQg+dfYb3zAJmsLwXoY4fAOGc1o +KI4UI26Bq4TPrJv9guaDjSYNE62M7+H7vWudlG+KPxt6jNaxxpIo5J1c7qVl+gx6 +kTDZ053peVLtWJzLrRT9/e238bCYnKfFpKwRzUGT9kEkMvmFqb56lnhKBXS/OPuP +3dAOWHvE9wKBgAJM4YXSHSGdEyDNuHvA84a1NekdwtesMR2alcsfGnbmwfaY5ngE +c36SMYGUJVo3cFga+i4JjDihyeQDHMCH1DchAjMYeTYDlNRy/KF30iCAlr1brtTR +bWh6jspjC27XCRhYoDtMtWyiLnkWuHAAcHwansMIArHfh2BhMBFVK23jAoGAGwrf +GFdfppQdWlsnbAFsj4mhXW2SvvwTL+65MdilTtPmcPmPU2gqlWaClpd2nMww6Ihu +nt9SkD7gsTe/PqN9PaldajdJfyZUw2lA1pPoTVDHfC4V1jpmH26wOob3ira01lWK +cW4NdcfjSh7s1Br45h/RYtgobTjsvV+Jum1oNW8CgYAeY82AEydYzqjZRH66xAjQ +pSxaT6B2YS5JqJFbRAtHA/ndApHbW7ALX5vqoJ6EkJ+aORQQMZUkX32n3Y0WFNE2 +FR9JEcnBjimwmG+JTBRCk1luamsZZpH/sHZohH1bsq9+dGo9xIeeBdi5DPxpdsKM +6NuWljVhDbuJeRiamlo5tg== +-----END PRIVATE KEY----- diff --git a/Tokenization/backend/wrapper/src/test/testCerts/clientSender/client-a-client.crt b/Tokenization/backend/wrapper/src/test/testCerts/clientSender/client-a-client.crt new file mode 100644 index 000000000..72ddb5561 --- /dev/null +++ b/Tokenization/backend/wrapper/src/test/testCerts/clientSender/client-a-client.crt @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIEuDCCAqCgAwIBAgIUTk9RrYkrtmjMiKjWusjyURgmSUEwDQYJKoZIhvcNAQEL +BQAwMzELMAkGA1UEBhMCUEwxDTALBgNVBAoMBFRlc3QxFTATBgNVBAMMDFRlc3Qg +Um9vdCBDQTAeFw0yNTA5MjUyMDU1MTVaFw0yNjA5MjUyMDU1MTVaMEYxCzAJBgNV +BAYTAlBMMRcwFQYDVQQKDA5FeGFtcGxlQ28gVGVzdDEeMBwGA1UEAwwVY2xpZW50 +LWEtY2xpZW50LmxvY2FsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +nJySLgwWLpLbt8EqFDfhKciKJGlxRUfcn/2u2EyxnkpKwwiLDSzKguZZ50xKviDt +Jao2FuZ251uyJDTfuPYt549OklkKIQYFSmP4MxNDAz501TVSJ45a9WQugScGc9lk +invmIADGBEa0rj2keRkT4MYvnWT2IGQJ91N99g9tDoQVPem5naHU1PxIwyxVVRIv +6mVCaro6OULqx6iFvDffvL0ef/5lbt8+vqX4QWwPH8rF5CvaV1KYYMkvQEXSn615 +8FE2YUepEN6wGEEDAIr98D5vNlgabkpLzxDULFT+tdk7v6Shb7bKql1W0QlBkEh/ +mFDCEkqOesGXLuzPG8pVAwIDAQABo4GwMIGtMAkGA1UdEwQCMAAwDgYDVR0PAQH/ +BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMCMDsGA1UdEQQ0MDKCFWNsaWVudC1h +LWNsaWVudC5sb2NhbIIIY2xpZW50LWGCCWxvY2FsaG9zdIcEfwAAAzAdBgNVHQ4E +FgQUScQWL/kot0/d3H9JQ9sZsO3xniAwHwYDVR0jBBgwFoAU41jbLgGadHiLx092 +1bLDou0kHQEwDQYJKoZIhvcNAQELBQADggIBALVJfl1YWb3mrXT51+pZ4pYJfY0Z +iXCGAMVLUtdnhgMmX5GVJhWvCAt+vwHggOJ+EA+1vw5CRe/GLDa5QurOtLtH6uBt +OjenYmOKRZ5f+mG8ZR20PyhH70m8DZ01OGlfuieFb8KgyYtEFNLCFZWxVDlvdwNL +2HVPSjM0JYudBELnTs4N8YZUTLGDRDZ9sz/KQYMJrSojN45k05qqr/EXWHwVDzVL +LefvuKi6H6DLzmU+oDy9TRcCydV4/h6i3MUxWm/IBrgoKIg4fmd/Evnen9KSc6md +yMHoKR6iHcha526txtUu4w0/0Le45yYxE1/eNm5jfMNwTFuoTbmlk+lItXd5Upn7 +1Pk+TF81WLl8prdvVoZPVYaKbj80JQlleQlWu76SaaY9ofkbRwP85npJmdl0wDCu +Bmil+ziBxzK73TT+UMBbRKRmXdeEh3fjQ8X4qlRNVPEarj1f2UiZ+45G/eFogA2r +EtVTqQ5MetNtWssgK0GFf2KeUIfXRdvYuFvLOhcd7uccxThq+o9KDFIulPzhy6uq +nu2AS8NELydQeHh6GjKqsxNoMS5l+YSzTGPvFWTYqzfRH5+h2J0H8Oex2Grb5C9A +35F8f35zLViv8C9mU32W9bSgcJElKaOumgBLbRtfrzHesFBFyOkTbtWnKJJJwXQH +7QZyDraKRsXdHAMr +-----END CERTIFICATE----- diff --git a/Tokenization/backend/wrapper/src/test/testCerts/clientSender/client-a-server.crt b/Tokenization/backend/wrapper/src/test/testCerts/clientSender/client-a-server.crt new file mode 100644 index 000000000..23fc77a5d --- /dev/null +++ b/Tokenization/backend/wrapper/src/test/testCerts/clientSender/client-a-server.crt @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEqjCCApKgAwIBAgIULDdlrJiTv9xZIx3QqggR9bBIgwswDQYJKoZIhvcNAQEL +BQAwMzELMAkGA1UEBhMCUEwxDTALBgNVBAoMBFRlc3QxFTATBgNVBAMMDFRlc3Qg +Um9vdCBDQTAeFw0yNTA5MjUyMDU1MDJaFw0yNjA5MjUyMDU1MDJaMD8xCzAJBgNV +BAYTAlBMMRcwFQYDVQQKDA5FeGFtcGxlQ28gVGVzdDEXMBUGA1UEAwwOY2xpZW50 +LWEubG9jYWwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCcnJIuDBYu +ktu3wSoUN+EpyIokaXFFR9yf/a7YTLGeSkrDCIsNLMqC5lnnTEq+IO0lqjYW5nbn +W7IkNN+49i3nj06SWQohBgVKY/gzE0MDPnTVNVInjlr1ZC6BJwZz2WSKe+YgAMYE +RrSuPaR5GRPgxi+dZPYgZAn3U332D20OhBU96bmdodTU/EjDLFVVEi/qZUJqujo5 +QurHqIW8N9+8vR5//mVu3z6+pfhBbA8fysXkK9pXUphgyS9ARdKfrXnwUTZhR6kQ +3rAYQQMAiv3wPm82WBpuSkvPENQsVP612Tu/pKFvtsqqXVbRCUGQSH+YUMISSo56 +wZcu7M8bylUDAgMBAAGjgakwgaYwCQYDVR0TBAIwADAOBgNVHQ8BAf8EBAMCBaAw +EwYDVR0lBAwwCgYIKwYBBQUHAwEwNAYDVR0RBC0wK4IOY2xpZW50LWEubG9jYWyC +CGNsaWVudC1hgglsb2NhbGhvc3SHBH8AAAIwHQYDVR0OBBYEFEnEFi/5KLdP3dx/ +SUPbGbDt8Z4gMB8GA1UdIwQYMBaAFONY2y4BmnR4i8dPdtWyw6LtJB0BMA0GCSqG +SIb3DQEBCwUAA4ICAQAKtTGDurzAkajMDN+WqhiA6daqIstsRzLz9VnBwqIlWcOr +c1As4ah+YZSf2Qw1AMZ387fpk4oF2QZD4ZG7kigZdn5ricFVhBRMZUzJV1ommu2H +8Mub+oRyKQ/TtRqkq1JJqLKz7rDxBMM9LxSBPR4Nj2C4IVioxI5KYXYxlmqMeoYA +sMglGi8c3loRSy9LNwvcQu+UPI6kcFG+J0rfXJlWx10GRWIURudXt8oAAIVBLvSt +HR29TXWjOTULwqun0y5V4eksJek5jEhGTWuODAdPmCSSjAE4VSLECex/jql6jNFB +zmE9Q7vcss4zR9TASMeJYT3S+mXVb9sNf4ps+9rhx63tluSCH1vwtpMoQXucbIgo +tBUz+5gCIA7n1bMUJ8b1MajnTVH0nJa1ZWi0zTYnSd6WL0S0Se5exZ5Ws1ZWnFl9 +lVPCn2Mt8agRu0s0VAT7t4nY4VjHTDqjj9Z99tcfUWCO8gAAR28kkqdRYxrgVMkx +pv8IwTt0tBldDnpwdCqBnXP75sta4Gq7IOpe0oQB6kizWqbII84tYSxUch9SkkaH +rE7BhGtUywAJxc+dnAFuePuu6BE2ZsQK86FpuHYIxR6DU7hH1i8258qxGt0/EVBg +ekhyT6tFaAWl5N+OVmEu1JvNdqNiw6sJc+xy9AcviWlAOvkGd2Aw0eTRNQLboQ== +-----END CERTIFICATE----- diff --git a/Tokenization/backend/wrapper/src/test/testCerts/clientSender/client-a.key b/Tokenization/backend/wrapper/src/test/testCerts/clientSender/client-a.key new file mode 100644 index 000000000..7377803ae --- /dev/null +++ b/Tokenization/backend/wrapper/src/test/testCerts/clientSender/client-a.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCcnJIuDBYuktu3 +wSoUN+EpyIokaXFFR9yf/a7YTLGeSkrDCIsNLMqC5lnnTEq+IO0lqjYW5nbnW7Ik +NN+49i3nj06SWQohBgVKY/gzE0MDPnTVNVInjlr1ZC6BJwZz2WSKe+YgAMYERrSu +PaR5GRPgxi+dZPYgZAn3U332D20OhBU96bmdodTU/EjDLFVVEi/qZUJqujo5QurH +qIW8N9+8vR5//mVu3z6+pfhBbA8fysXkK9pXUphgyS9ARdKfrXnwUTZhR6kQ3rAY +QQMAiv3wPm82WBpuSkvPENQsVP612Tu/pKFvtsqqXVbRCUGQSH+YUMISSo56wZcu +7M8bylUDAgMBAAECggEANyBDsjKt8inebjFvmttKhfchbQyygsT3S1ez3k4srT+Q +TlNpArOz+tyTY7+uhXs4jmv6CxiHXQuhSm5UG5qH8Py4FvqBfrtMTHGg8XWDvpYS +8OOKbgMFUGA5oFt4wXmRks9m4vfyu5mZysVG6htiLFoGc5wQqLkd6vF4Io8uf4+A +Dd/oY85K7x/JnrNQaF7LmpeqTMRlhtzSzGNVqEwT9b9FoQRADGHrg1ksY5xXixAw +Jf+wvJqd6AaoxzK0rDuZiQpVnjepJ6aeip61RL7coc+yAlkXhfDOWvzWCefRFUTf +Q/iTyOset8ejRg2mF8InLUKYC2kwKLeucVvFkijz2QKBgQDbgf5L2aK/lUEQVtQf +ueqCc89PJZHU34tEXRC0doGYLQnhZQPVvLeTv+CkZ7GibUxPiMLdtzzfyFxlLbs+ +gUxBXV540hI3acpDqdiiZmHeYtMPvyjUkkP1ymQSnLwwjOkBh7Wt/+zMBEHtO8hz +Mo5vfoV6JV+b+JQg2f7cyd1t2wKBgQC2pclNJ1Dj58Vgmfd2EZhZgG0XRVPfR7PT +QjEIcnFmmNvEiN83dYqYw8fVOegcXrCFMTP3aW6ONoGnk+owhTSBtEfYNCKOwIi9 +GHM+MJFNIgxxPM+xSvpxHtAF9meYFkMRqjMJPM8ICz04Uz3AsfbdveYwUNMudSap +znigNKfh+QKBgDCvvH+GXhqwOCYvnA0NZ35XwXuEkbvteS5IlhPw1P2zv6VGins1 +yGH1BRZyCWxFYc+iPdZ/dfkMr7GhWw6aDxfQZcvWjEPOKxam7W3X141DzhyIAb5k +Ur6JjXizWupJ1sSIHTvir9rwds7vm54xcHY6UdCtyW8Gy5QdxfGitIJRAoGAbJ2I +aT5RJ0bEJJ9K/saV39u0hBsxNl2QfbgmKozMDSQnxOdUPsnCgvgiVRXbh0t0E7Df +42iqWx3k2n/my7XbNKq98r+GMXgjmLf6iGgfcEwoNAriw97/sdeOA421q0bJ2a5q +LTshLvpoDJ/L4FS0psbwJZlbDIyUUnS7XSITGBkCgYBNvMefT86P85yN5nDyxRjO +lCitw08NjE+6WZWL6BTbRqVovFG2HAaWGEjG2+bpApy4S4AN3NmmOby38ZZDR7bJ +bQxCHRt61yqX6IphkRrzv8K7DbrN3jnKO2FN8TBWwcvFzx2d5hl8Nsv2OmEyixZZ +ySbU4WOBCdu/mJy/+Xb9gA== +-----END PRIVATE KEY----- diff --git a/Tokenization/backend/wrapper/src/test/testCerts/clientSender/client-a.pub.pem b/Tokenization/backend/wrapper/src/test/testCerts/clientSender/client-a.pub.pem new file mode 100644 index 000000000..f565de4a2 --- /dev/null +++ b/Tokenization/backend/wrapper/src/test/testCerts/clientSender/client-a.pub.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnJySLgwWLpLbt8EqFDfh +KciKJGlxRUfcn/2u2EyxnkpKwwiLDSzKguZZ50xKviDtJao2FuZ251uyJDTfuPYt +549OklkKIQYFSmP4MxNDAz501TVSJ45a9WQugScGc9lkinvmIADGBEa0rj2keRkT +4MYvnWT2IGQJ91N99g9tDoQVPem5naHU1PxIwyxVVRIv6mVCaro6OULqx6iFvDff +vL0ef/5lbt8+vqX4QWwPH8rF5CvaV1KYYMkvQEXSn6158FE2YUepEN6wGEEDAIr9 +8D5vNlgabkpLzxDULFT+tdk7v6Shb7bKql1W0QlBkEh/mFDCEkqOesGXLuzPG8pV +AwIDAQAB +-----END PUBLIC KEY----- diff --git a/Tokenization/backend/wrapper/src/test/testCerts/testCerts.ts b/Tokenization/backend/wrapper/src/test/testCerts/testCerts.ts new file mode 100644 index 000000000..dcb90aa19 --- /dev/null +++ b/Tokenization/backend/wrapper/src/test/testCerts/testCerts.ts @@ -0,0 +1,94 @@ +import { CentralSystemConfig, gRPCWrapperConfig } from "models/config.model"; +import path from "path"; +import * as fs from "fs"; + +export const getTestCentralCertPaths = + (): CentralSystemConfig["serverCerts"] => { + const CA_CERT_PATH = path.join(__dirname, "./ca.crt"); + const SERVER_CERT_PATH = path.join( + __dirname, + "./centralSystem/central-system.crt" + ); + const SERVER_KEY_PATH = path.join( + __dirname, + "./centralSystem/central-system.key" + ); + + return { + caCertPath: CA_CERT_PATH, + certPath: SERVER_CERT_PATH, + keyPath: SERVER_KEY_PATH, + }; + }; + +export const getTestClientListenerCertPaths = + (): gRPCWrapperConfig["clientCerts"] => { + const CA_CERT_PATH = path.join(__dirname, "./ca.crt"); + const CLIENT_CERT_PATH = path.join( + __dirname, + "./clientListener/client-b-client.crt" + ); + const CLIENT_KEY_PATH = path.join( + __dirname, + "./clientListener/client-b.key" + ); + + return { + caCertPath: CA_CERT_PATH, + certPath: CLIENT_CERT_PATH, + keyPath: CLIENT_KEY_PATH, + }; + }; + +export const getTestClientListenerServerCertPaths = + (): gRPCWrapperConfig["clientCerts"] => { + const CA_CERT_PATH = path.join(__dirname, "./ca.crt"); + const CLIENT_CERT_PATH = path.join( + __dirname, + "./clientListenerServer/client-b-server.crt" + ); + const CLIENT_KEY_PATH = path.join( + __dirname, + "./clientListenerServer/client-b.key" + ); + + return { + caCertPath: CA_CERT_PATH, + certPath: CLIENT_CERT_PATH, + keyPath: CLIENT_KEY_PATH, + }; + }; + +export const getTestClientSenderCertPaths = + (): gRPCWrapperConfig["clientCerts"] => { + const CA_CERT_PATH = path.join(__dirname, "./ca.crt"); + const CLIENT_CERT_PATH = path.join( + __dirname, + "./clientSender/client-a-client.crt" + ); + const CLIENT_KEY_PATH = path.join(__dirname, "./clientSender/client-a.key"); + + return { + caCertPath: CA_CERT_PATH, + certPath: CLIENT_CERT_PATH, + keyPath: CLIENT_KEY_PATH, + }; + }; + +export const getTestCerts = () => { + const CA_CERT_PATH = path.join(__dirname, "./ca.crt"); + const SERVER_CERT_PATH = path.join( + __dirname, + "./centralSystem/central-system.crt" + ); + const SERVER_KEY_PATH = path.join( + __dirname, + "./centralSystem/central-system.key" + ); + + const caCert = fs.readFileSync(CA_CERT_PATH); + const clientCert = fs.readFileSync(SERVER_CERT_PATH); + const clientKey = fs.readFileSync(SERVER_KEY_PATH); + + return { caCert, clientCert, clientKey }; +}; diff --git a/Tokenization/backend/wrapper/src/utils/connection/peerListener.ts b/Tokenization/backend/wrapper/src/utils/connection/peerListener.ts index 5fafb4f1d..d4c030fcc 100644 --- a/Tokenization/backend/wrapper/src/utils/connection/peerListener.ts +++ b/Tokenization/backend/wrapper/src/utils/connection/peerListener.ts @@ -12,9 +12,9 @@ * or submit itself to any jurisdiction. */ import * as grpc from '@grpc/grpc-js'; -import { Connection } from '../../client/connection/Connection'; import { ConnectionDirection } from '../../models/message.model'; import { ConnectionStatus } from '../../models/connection.model'; +import type { Connection } from '../../client/connection/Connection'; /** * Listens for incoming gRPC requests and forwards them to the local API endpoint. @@ -24,7 +24,7 @@ import { ConnectionStatus } from '../../models/connection.model'; * @param callback - The callback function to be called with the response. * @param logger - The logger object to write info and error messages. * @param receivingConnections - The map of existing incoming connections. - * @param peerCtor - The constructor function for the peer client. + * @param createNewConnection - Function to create a new Connection instance. * @param baseAPIPath - The base path of the local API endpoint. */ export const peerListener = async ( @@ -32,7 +32,7 @@ export const peerListener = async ( callback: grpc.sendUnaryData, logger: any, receivingConnections: Map, - peerCtor: any, + createNewConnection: (address: string, direction: ConnectionDirection, token?: string | undefined) => Promise, baseAPIPath: string ) => { try { @@ -42,7 +42,7 @@ export const peerListener = async ( let conn: Connection | undefined = receivingConnections.get(clientAddress); if (!conn) { - conn = new Connection('', clientAddress, ConnectionDirection.RECEIVING, peerCtor); + conn = await createNewConnection(clientAddress, ConnectionDirection.RECEIVING); conn.status = ConnectionStatus.CONNECTED; receivingConnections.set(clientAddress, conn); logger.infoMessage(`New incoming connection registered for: ${clientAddress}`);