diff --git a/app/lib/ws2p/WS2PConnection.ts b/app/lib/ws2p/WS2PConnection.ts index fcce6a1f2f444702607e5c7208f7dcd918c5e167..638af812274bb3e02cf4bfde5ef881fa67f34c47 100644 --- a/app/lib/ws2p/WS2PConnection.ts +++ b/app/lib/ws2p/WS2PConnection.ts @@ -1,4 +1,5 @@ import {Key, verify} from "../common-libs/crypto/keyring" +import {WS2PMessageHandler} from "./impl/WS2PMessageHandler" const ws = require('ws') const nuuid = require('node-uuid'); @@ -179,7 +180,7 @@ export class WS2PPubkeyLocalAuth implements WS2PLocalAuth { } export interface WS2PRequest { - message:string + name:string } /** @@ -209,7 +210,7 @@ export class WS2PConnection { constructor( private ws:any, private onWsOpened:Promise<void>, - private onDataMessage:(json:any, ws:any)=>void, + private messageHandler:WS2PMessageHandler, private localAuth:WS2PLocalAuth, private remoteAuth:WS2PRemoteAuth, private options:{ @@ -224,7 +225,7 @@ export class WS2PConnection { static newConnectionToAddress( address:string, - onDataMessage:(json:any, ws:any)=>void, + messageHandler:WS2PMessageHandler, localAuth:WS2PLocalAuth, remoteAuth:WS2PRemoteAuth, options:{ @@ -240,12 +241,12 @@ export class WS2PConnection { const onWsOpened:Promise<void> = new Promise(res => { websocket.on('open', () => res()) }) - return new WS2PConnection(websocket, onWsOpened, onDataMessage, localAuth, remoteAuth, options, expectedPub) + return new WS2PConnection(websocket, onWsOpened, messageHandler, localAuth, remoteAuth, options, expectedPub) } static newConnectionFromWebSocketServer( websocket:any, - onDataMessage:(json:any, ws:any)=>void, + messageHandler:WS2PMessageHandler, localAuth:WS2PLocalAuth, remoteAuth:WS2PRemoteAuth, options:{ @@ -257,7 +258,7 @@ export class WS2PConnection { }, expectedPub:string = "") { const onWsOpened = Promise.resolve() - return new WS2PConnection(websocket, onWsOpened, onDataMessage, localAuth, remoteAuth, options, expectedPub) + return new WS2PConnection(websocket, onWsOpened, messageHandler, localAuth, remoteAuth, options, expectedPub) } get nbRequests() { @@ -389,7 +390,8 @@ export class WS2PConnection { // Request message else if (data.reqId && typeof data.reqId === "string") { - this.onDataMessage(data, this.ws) + const body = await this.messageHandler.handleRequestMessage(data) + this.ws.send(JSON.stringify({ resId: data.reqId, body })) } // Answer message @@ -407,7 +409,7 @@ export class WS2PConnection { // Push message else { this.nbPushsByRemoteCount++ - this.onDataMessage(data, this.ws) + await this.messageHandler.handlePushMessage(data) } } } diff --git a/app/lib/ws2p/WS2PRequester.ts b/app/lib/ws2p/WS2PRequester.ts new file mode 100644 index 0000000000000000000000000000000000000000..5f0cc3cc95c80377d4253963f75d6428b8a8de8d --- /dev/null +++ b/app/lib/ws2p/WS2PRequester.ts @@ -0,0 +1,25 @@ +import {WS2PConnection} from "./WS2PConnection" + +enum WS2P_REQ { + CURRENT +} + +export class WS2PRequester { + + private constructor( + protected ws2pc:WS2PConnection) {} + + static fromConnection(ws2pc:WS2PConnection) { + return new WS2PRequester(ws2pc) + } + + getCurrent() { + return this.query(WS2P_REQ.CURRENT) + } + + private query(req:WS2P_REQ) { + return this.ws2pc.request({ + name: WS2P_REQ[req] + }) + } +} \ No newline at end of file diff --git a/app/lib/ws2p/WS2PResponder.ts b/app/lib/ws2p/WS2PResponder.ts new file mode 100644 index 0000000000000000000000000000000000000000..8973e2ade1041862831d48f921f95145077c54df --- /dev/null +++ b/app/lib/ws2p/WS2PResponder.ts @@ -0,0 +1,39 @@ +import {WS2PReqMapper} from "./WS2PReqMapper" + +enum WS2P_REQ { + CURRENT +} + +export enum WS2P_REQERROR { + UNKNOWN_REQUEST +} + +export async function WS2PResponder(data:any, handler:WS2PReqMapper) { + + /********** + * REQUEST + *********/ + if (data.reqId && typeof data.reqId === "string") { + + let body:any = {} + + if (data.body && data.body.name) { + switch (data.body.name) { + case WS2P_REQ[WS2P_REQ.CURRENT]: + body = await handler.getCurrent() + break; + default: + throw Error(WS2P_REQERROR[WS2P_REQERROR.UNKNOWN_REQUEST]) + } + } + + return body + } + + /********** + * PUSH + *********/ + else { + + } +} \ No newline at end of file diff --git a/app/lib/ws2p/impl/WS2PMessageHandler.ts b/app/lib/ws2p/impl/WS2PMessageHandler.ts new file mode 100644 index 0000000000000000000000000000000000000000..8fdfdda6d75ffd30ac15adbcfbdc5b13e0c88f47 --- /dev/null +++ b/app/lib/ws2p/impl/WS2PMessageHandler.ts @@ -0,0 +1,6 @@ +import {WS2PResponse} from "./WS2PResponse" +export interface WS2PMessageHandler { + + handlePushMessage(json:any): Promise<void> + handleRequestMessage(json:any): Promise<WS2PResponse> +} \ No newline at end of file diff --git a/app/lib/ws2p/impl/WS2PReqMapperByServer.ts b/app/lib/ws2p/impl/WS2PReqMapperByServer.ts new file mode 100644 index 0000000000000000000000000000000000000000..b30496a4fdba04cc42f1b15378d09e7ddb43edd1 --- /dev/null +++ b/app/lib/ws2p/impl/WS2PReqMapperByServer.ts @@ -0,0 +1,11 @@ +import {Server} from "../../../../server" +import {WS2PReqMapper} from "../interface/WS2PReqMapper" + +export class WS2PReqMapperByServer implements WS2PReqMapper { + + private constructor(protected server:Server) {} + + async getCurrent() { + return this.server.BlockchainService.current() + } +} \ No newline at end of file diff --git a/app/lib/ws2p/impl/WS2PResponse.ts b/app/lib/ws2p/impl/WS2PResponse.ts new file mode 100644 index 0000000000000000000000000000000000000000..e26fc8ac30b6497fd35de59b1e52234ddf099954 --- /dev/null +++ b/app/lib/ws2p/impl/WS2PResponse.ts @@ -0,0 +1,3 @@ + +export interface WS2PResponse { +} \ No newline at end of file diff --git a/app/lib/ws2p/interface/WS2PReqMapper.ts b/app/lib/ws2p/interface/WS2PReqMapper.ts new file mode 100644 index 0000000000000000000000000000000000000000..dbe16a237c56e474aac994bb3203bd33ccc18261 --- /dev/null +++ b/app/lib/ws2p/interface/WS2PReqMapper.ts @@ -0,0 +1,6 @@ +import {BlockDTO} from "../../dto/BlockDTO" + +export interface WS2PReqMapper { + + getCurrent(): Promise<BlockDTO> +} \ No newline at end of file diff --git a/test/integration/tools/toolbox.ts b/test/integration/tools/toolbox.ts index 851081f3bd9475bf2c80beafca510ea72da267ed..a732ba052e629acc1151512498630723bfbabaa4 100644 --- a/test/integration/tools/toolbox.ts +++ b/test/integration/tools/toolbox.ts @@ -15,11 +15,16 @@ import {ConfDTO} from "../../../app/lib/dto/ConfDTO" import {FileDAL} from "../../../app/lib/dal/fileDAL" import {MembershipDTO} from "../../../app/lib/dto/MembershipDTO" import {TransactionDTO} from "../../../app/lib/dto/TransactionDTO" +import {Key} from "../../../app/lib/common-libs/crypto/keyring" +import {WS2PConnection, WS2PPubkeyLocalAuth, WS2PPubkeyRemoteAuth} from "../../../app/lib/ws2p/WS2PConnection" +import {WS2PResponse} from "../../../app/lib/ws2p/impl/WS2PResponse" +import {WS2PMessageHandler} from "../../../app/lib/ws2p/impl/WS2PMessageHandler" const assert = require('assert'); const _ = require('underscore'); const rp = require('request-promise'); const es = require('event-stream'); +const WebSocketServer = require('ws').Server const httpTest = require('../tools/http'); const sync = require('../tools/sync'); const commit = require('../tools/commit'); @@ -549,4 +554,42 @@ export class TestingServer { await farm.shutDownEngine() } } +} + +export async function newWS2PBidirectionnalConnection(k1:Key, k2:Key, serverHandler:WS2PMessageHandler) { + let i = 1 + let port = PORT++ + const wss = new WebSocketServer({ port }) + let s1:WS2PConnection + let c1:WS2PConnection + return await new Promise<{ + p1:WS2PConnection, + p2:WS2PConnection, + wss:any + }>(resolveBefore => { + wss.on('connection', async (ws:any) => { + switch (i) { + case 1: + s1 = WS2PConnection.newConnectionFromWebSocketServer(ws, serverHandler, new WS2PPubkeyLocalAuth(k1), new WS2PPubkeyRemoteAuth(k1), { + connectionTimeout: 100, + requestTimeout: 100 + }); + s1.connect().catch((e:any) => console.error('WS2P: newConnectionFromWebSocketServer connection error')) + break; + } + resolveBefore({ + p1: s1, + p2: c1, + wss + }) + i++ + }) + c1 = WS2PConnection.newConnectionToAddress('localhost:' + port, new (class EmptyHandler implements WS2PMessageHandler { + async handlePushMessage(json: any): Promise<void> { + } + async handleRequestMessage(json: any): Promise<WS2PResponse> { + return {} + } + }), new WS2PPubkeyLocalAuth(k2), new WS2PPubkeyRemoteAuth(k2)) + }) } \ No newline at end of file diff --git a/test/integration/ws2p_connection.ts b/test/integration/ws2p_connection.ts index 9075ac71d89c5c926aa270e68c6ce730a60931b7..c74fee3d917a78ab61d9a23efa6422d7e5e80d75 100644 --- a/test/integration/ws2p_connection.ts +++ b/test/integration/ws2p_connection.ts @@ -7,6 +7,8 @@ import { } from "../../app/lib/ws2p/WS2PConnection" import {Key, verify} from "../../app/lib/common-libs/crypto/keyring" import {assertThrows} from "./tools/toolbox" +import {WS2PMessageHandler} from "../../app/lib/ws2p/impl/WS2PMessageHandler" +import {WS2PResponse} from "../../app/lib/ws2p/impl/WS2PResponse" const assert = require('assert'); const WebSocketServer = require('ws').Server @@ -35,8 +37,8 @@ describe('WS2P', () => { }) it('should be able to create a connection', async () => { - const ws2p = WS2PConnection.newConnectionToAddress('localhost:20902', () => {}, new WS2PNoLocalAuth(), new WS2PNoRemoteAuth()) - const res = await ws2p.request({ message: 'head' }) + const ws2p = WS2PConnection.newConnectionToAddress('localhost:20902', new WS2PMutedHandler(), new WS2PNoLocalAuth(), new WS2PNoRemoteAuth()) + const res = await ws2p.request({ name: 'head' }) assert.deepEqual({ bla: 'aa' }, res) }) }) @@ -86,39 +88,39 @@ describe('WS2P', () => { it('should refuse the connection if the server does not answer', async () => { const keypair = new Key('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP') - const ws2p = WS2PConnection.newConnectionToAddress('localhost:20903', () => {}, new WS2PPubkeyLocalAuth(keypair), new WS2PPubkeyRemoteAuth(keypair), { + const ws2p = WS2PConnection.newConnectionToAddress('localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(keypair), new WS2PPubkeyRemoteAuth(keypair), { connectionTimeout: 100, requestTimeout: 100 }) - await assertThrows(ws2p.request({ message: 'a' }), "WS2P connection timeout") + await assertThrows(ws2p.request({ name: 'a' }), "WS2P connection timeout") }) it('should refuse the connection if the server answers with a wrong signature', async () => { const keypair = new Key('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP') - const ws2p = WS2PConnection.newConnectionToAddress('localhost:20903', () => {}, new WS2PPubkeyLocalAuth(keypair), new WS2PPubkeyRemoteAuth(keypair), { + const ws2p = WS2PConnection.newConnectionToAddress('localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(keypair), new WS2PPubkeyRemoteAuth(keypair), { connectionTimeout: 100, requestTimeout: 100 }) - await assertThrows(ws2p.request({ message: 'a' }), "Wrong signature from server ACK") + await assertThrows(ws2p.request({ name: 'a' }), "Wrong signature from server ACK") }) it('should refuse the connection if the server refuses our signature', async () => { const keypair = new Key('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP') - const ws2p = WS2PConnection.newConnectionToAddress('localhost:20903', () => {}, new WS2PPubkeyLocalAuth(keypair), new WS2PPubkeyRemoteAuth(keypair), { + const ws2p = WS2PConnection.newConnectionToAddress('localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(keypair), new WS2PPubkeyRemoteAuth(keypair), { connectionTimeout: 100, requestTimeout: 100 }) - await assertThrows(ws2p.request({ message: 'a' }), "WS2P connection timeout") + await assertThrows(ws2p.request({ name: 'a' }), "WS2P connection timeout") assert.equal('Wrong signature from client CONNECT', clientAskError) }) it('should accept the connection if the server answers with a good signature', async () => { const keypair = new Key('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP') - const ws2p = WS2PConnection.newConnectionToAddress('localhost:20903', () => {}, new WS2PPubkeyLocalAuth(keypair), new WS2PNoRemoteAuth(), { + const ws2p = WS2PConnection.newConnectionToAddress('localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(keypair), new WS2PNoRemoteAuth(), { connectionTimeout: 1000, requestTimeout: 1000 }) - const res = await ws2p.request({ message: 'head' }) + const res = await ws2p.request({ name: 'head' }) assert.deepEqual({ bla: 'aa' }, res) }) }) @@ -138,21 +140,24 @@ describe('WS2P', () => { wss.on('connection', (ws:any) => { switch (i) { case 0: - s1 = WS2PConnection.newConnectionFromWebSocketServer(ws, (obj:any, ws:any) => { - if (obj.reqId) { - ws.send(JSON.stringify({ resId: obj.reqId, body: { answer: 'world' } })) + s1 = WS2PConnection.newConnectionFromWebSocketServer(ws, new (class TmpHandler implements WS2PMessageHandler { + async handlePushMessage(json: any): Promise<void> { } - }, new WS2PNoLocalAuth(), new WS2PNoRemoteAuth()) + async handleRequestMessage(json: any): Promise<WS2PResponse> { + return { answer: 'world' } + } + }), new WS2PNoLocalAuth(), new WS2PNoRemoteAuth()) s1.connect().catch(e => console.error('WS2P: newConnectionFromWebSocketServer connection error')) break case 1: let j = 0 - s2 = WS2PConnection.newConnectionFromWebSocketServer(ws, (obj:any, ws:any) => { - if (obj.reqId) { - ws.send(JSON.stringify({ resId: obj.reqId, body: { answer: 'this is s2![j = ' + j + ']' } })) - j++ + s2 = WS2PConnection.newConnectionFromWebSocketServer(ws, new (class TmpHandler implements WS2PMessageHandler { + async handlePushMessage(json: any): Promise<void> { + } + async handleRequestMessage(json: any): Promise<WS2PResponse> { + return { answer: 'this is s2![j = ' + (j++) + ']' } } - }, new WS2PNoLocalAuth(), new WS2PNoRemoteAuth()) + }), new WS2PNoLocalAuth(), new WS2PNoRemoteAuth()) s2.connect().catch(e => console.error('WS2P: newConnectionFromWebSocketServer connection error')) break } @@ -166,9 +171,9 @@ describe('WS2P', () => { it('should be able to create connections and make several requests', async () => { // connection 1 - const c1 = WS2PConnection.newConnectionToAddress('localhost:20902', () => {}, new WS2PNoLocalAuth(), new WS2PNoRemoteAuth()) - assert.deepEqual({ answer: 'world' }, await c1.request({ message: 'hello!' })) - assert.deepEqual({ answer: 'world' }, await c1.request({ message: 'hello2!' })) + const c1 = WS2PConnection.newConnectionToAddress('localhost:20902', new WS2PMutedHandler(), new WS2PNoLocalAuth(), new WS2PNoRemoteAuth()) + assert.deepEqual({ answer: 'world' }, await c1.request({ name: 'hello!' })) + assert.deepEqual({ answer: 'world' }, await c1.request({ name: 'hello2!' })) assert.equal(s1.nbRequests, 0) assert.equal(c1.nbRequests, 2) assert.equal(s1.nbResponses, 0) @@ -178,10 +183,10 @@ describe('WS2P', () => { assert.equal(s1.nbPushsByRemote, 0) assert.equal(c1.nbPushsByRemote, 0) // connection 2 - const c2 = WS2PConnection.newConnectionToAddress('localhost:20902', () => {}, new WS2PNoLocalAuth(), new WS2PNoRemoteAuth()) - assert.deepEqual({ answer: 'this is s2![j = 0]' }, await c2.request({ message: 'test?' })) - assert.deepEqual({ answer: 'this is s2![j = 1]' }, await c2.request({ message: 'test!' })) - assert.deepEqual({ answer: 'this is s2![j = 2]' }, await c2.request({ message: 'test!!!' })) + const c2 = WS2PConnection.newConnectionToAddress('localhost:20902', new WS2PMutedHandler(), new WS2PNoLocalAuth(), new WS2PNoRemoteAuth()) + assert.deepEqual({ answer: 'this is s2![j = 0]' }, await c2.request({ name: 'test?' })) + assert.deepEqual({ answer: 'this is s2![j = 1]' }, await c2.request({ name: 'test!' })) + assert.deepEqual({ answer: 'this is s2![j = 2]' }, await c2.request({ name: 'test!!!' })) assert.equal(s1.nbRequests, 0) assert.equal(c2.nbRequests, 3) assert.equal(s1.nbResponses, 0) @@ -216,7 +221,7 @@ describe('WS2P', () => { wss.on('connection', async (ws:any) => { switch (i) { case 1: - resolveS1(WS2PConnection.newConnectionFromWebSocketServer(ws, () => {}, new WS2PPubkeyLocalAuth(serverKeypair), new WS2PPubkeyRemoteAuth(serverKeypair), { + resolveS1(WS2PConnection.newConnectionFromWebSocketServer(ws, new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(serverKeypair), new WS2PPubkeyRemoteAuth(serverKeypair), { connectionTimeout: 100, requestTimeout: 100 })); @@ -230,7 +235,7 @@ describe('WS2P', () => { } } - resolveS2(WS2PConnection.newConnectionFromWebSocketServer(ws, () => {}, new WS2PPubkeyLocalAuth(serverKeypair), new WS2PPubkeyNotAnsweringWithOKAuth(serverKeypair), { + resolveS2(WS2PConnection.newConnectionFromWebSocketServer(ws, new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(serverKeypair), new WS2PPubkeyNotAnsweringWithOKAuth(serverKeypair), { connectionTimeout: 100, requestTimeout: 100 })); @@ -238,7 +243,7 @@ describe('WS2P', () => { break case 3: - resolveS3(WS2PConnection.newConnectionFromWebSocketServer(ws, () => {}, new WS2PPubkeyLocalAuth(serverKeypair), new WS2PPubkeyRemoteAuth(serverKeypair), { + resolveS3(WS2PConnection.newConnectionFromWebSocketServer(ws, new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(serverKeypair), new WS2PPubkeyRemoteAuth(serverKeypair), { connectionTimeout: 100, requestTimeout: 100 })); @@ -246,7 +251,7 @@ describe('WS2P', () => { break case 4: - resolveS4(WS2PConnection.newConnectionFromWebSocketServer(ws, () => {}, new WS2PPubkeyLocalAuth(serverKeypair), new WS2PPubkeyRemoteAuth(serverKeypair), { + resolveS4(WS2PConnection.newConnectionFromWebSocketServer(ws, new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(serverKeypair), new WS2PPubkeyRemoteAuth(serverKeypair), { connectionTimeout: 100, requestTimeout: 100 })); @@ -254,13 +259,13 @@ describe('WS2P', () => { break case 5: - resolveS5(WS2PConnection.newConnectionFromWebSocketServer(ws, () => {}, new WS2PPubkeyLocalAuth(serverKeypair), new WS2PPubkeyRemoteAuth(serverKeypair))); + resolveS5(WS2PConnection.newConnectionFromWebSocketServer(ws, new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(serverKeypair), new WS2PPubkeyRemoteAuth(serverKeypair))); (await s5p).connect().catch((e:any) => console.error('WS2P: newConnectionFromWebSocketServer connection error')) break case 6: - resolveS6(WS2PConnection.newConnectionFromWebSocketServer(ws, () => {}, new WS2PPubkeyLocalAuth(serverKeypair), new WS2PPubkeyRemoteAuth(serverKeypair), { + resolveS6(WS2PConnection.newConnectionFromWebSocketServer(ws, new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(serverKeypair), new WS2PPubkeyRemoteAuth(serverKeypair), { connectionTimeout: 100, requestTimeout: 100 })); @@ -284,17 +289,17 @@ describe('WS2P', () => { } const keypair = new Key('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP') - const c1 = WS2PConnection.newConnectionToAddress('localhost:20903', () => {}, new WS2PPubkeyLocalAuth(keypair), new WS2PPubkeyNotAnsweringWithACKAuth(keypair)) + const c1 = WS2PConnection.newConnectionToAddress('localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(keypair), new WS2PPubkeyNotAnsweringWithACKAuth(keypair)) c1.connect() const s1 = await s1p - await assertThrows(s1.request({ message: 'something' }), "WS2P connection timeout") + await assertThrows(s1.request({ name: 'something' }), "WS2P connection timeout") }) it('should refuse the connection if the client not confirm with OK', async () => { const keypair = new Key('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP') - WS2PConnection.newConnectionToAddress('localhost:20903', () => {}, new WS2PPubkeyLocalAuth(keypair), new WS2PPubkeyRemoteAuth(keypair)) + WS2PConnection.newConnectionToAddress('localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(keypair), new WS2PPubkeyRemoteAuth(keypair)) const s2 = await s2p - await assertThrows(s2.request({ message: 'something' }), "WS2P connection timeout") + await assertThrows(s2.request({ name: 'something' }), "WS2P connection timeout") }) it('should refuse the connection if the client answers with a wrong signature', async () => { @@ -312,10 +317,10 @@ describe('WS2P', () => { } const keypair = new Key('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP') - const c3 = WS2PConnection.newConnectionToAddress('localhost:20903', () => {}, new WS2PPubkeyLocalAuth(keypair), new WS2PPubkeyAnsweringWithWrongSigForACK(keypair)) + const c3 = WS2PConnection.newConnectionToAddress('localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyLocalAuth(keypair), new WS2PPubkeyAnsweringWithWrongSigForACK(keypair)) c3.connect() const s3 = await s3p - await assertThrows(s3.request({ message: 'something' }), "Wrong signature from server ACK") + await assertThrows(s3.request({ name: 'something' }), "Wrong signature from server ACK") }) it('should refuse the connection if the client refuses our signature', async () => { @@ -335,21 +340,23 @@ describe('WS2P', () => { } const keypair = new Key('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP') - const c4 = WS2PConnection.newConnectionToAddress('localhost:20903', () => {}, new WS2PPubkeyRefusingACKSignature(keypair), new WS2PPubkeyRemoteAuth(keypair)) + const c4 = WS2PConnection.newConnectionToAddress('localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyRefusingACKSignature(keypair), new WS2PPubkeyRemoteAuth(keypair)) const s4 = await s4p await assertThrows(c4.connect(), "Wrong signature from server ACK") }) it('should accept the connection if everything is OK on both side', async () => { const keypair = new Key('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP') - const c5 = WS2PConnection.newConnectionToAddress('localhost:20903', (obj:any, ws:any) => { - if (obj.reqId) { - ws.send(JSON.stringify({ resId: obj.reqId, body: { answer: 'success!' } })) + const c5 = WS2PConnection.newConnectionToAddress('localhost:20903', new (class TmpHandler implements WS2PMessageHandler { + async handlePushMessage(json: any): Promise<void> { + } + async handleRequestMessage(json: any): Promise<WS2PResponse> { + return { answer: 'success!' } } - }, new WS2PPubkeyLocalAuth(keypair), new WS2PPubkeyRemoteAuth(keypair)) + }), new WS2PPubkeyLocalAuth(keypair), new WS2PPubkeyRemoteAuth(keypair)) await c5.connect() const s5 = await s5p - assert.deepEqual({ answer: 'success!' }, await s5.request({ message: 'connection?'} )) + assert.deepEqual({ answer: 'success!' }, await s5.request({ name: 'connection?'} )) }) it('should refuse the connection if the client does not send OK', async () => { @@ -360,10 +367,10 @@ describe('WS2P', () => { } const keypair = new Key('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP') - const c6 = WS2PConnection.newConnectionToAddress('localhost:20903', () => {}, new WS2PPubkeyNotAnsweringWithOKAuth(keypair), new WS2PPubkeyRemoteAuth(keypair)) + const c6 = WS2PConnection.newConnectionToAddress('localhost:20903', new WS2PMutedHandler(), new WS2PPubkeyNotAnsweringWithOKAuth(keypair), new WS2PPubkeyRemoteAuth(keypair)) c6.connect() const s6 = await s6p - await assertThrows(s6.request({ message: 'something' }), "WS2P connection timeout") + await assertThrows(s6.request({ name: 'something' }), "WS2P connection timeout") }) }) }) @@ -421,3 +428,13 @@ class WS2PNoRemoteAuth implements WS2PRemoteAuth { async authenticationIsDone(): Promise<void> { } } + +class WS2PMutedHandler implements WS2PMessageHandler { + + async handlePushMessage(json: any): Promise<void> { + } + + async handleRequestMessage(json: any): Promise<WS2PResponse> { + return {} + } +} diff --git a/test/integration/ws2p_exchange.ts b/test/integration/ws2p_exchange.ts new file mode 100644 index 0000000000000000000000000000000000000000..c80a4f4c37c55c68a01c566588a2bdefa445c3a4 --- /dev/null +++ b/test/integration/ws2p_exchange.ts @@ -0,0 +1,74 @@ +import {WS2PConnection} from "../../app/lib/ws2p/WS2PConnection" +import {Key} from "../../app/lib/common-libs/crypto/keyring" +import {newWS2PBidirectionnalConnection} from "./tools/toolbox" +import {WS2PRequester} from "../../app/lib/ws2p/WS2PRequester" +import {WS2PResponder} from "../../app/lib/ws2p/WS2PResponder" +import {WS2PReqMapper} from "../../app/lib/ws2p/WS2PReqMapper" +import {BlockDTO} from "../../app/lib/dto/BlockDTO" +import {WS2PMessageHandler} from "../../app/lib/ws2p/impl/WS2PMessageHandler" +import {WS2PResponse} from "../../app/lib/ws2p/impl/WS2PResponse" +const assert = require('assert'); + +describe('WS2P exchange', () => { + + let wss:any + let c1:WS2PConnection, s1:WS2PConnection + + before(async () => { + const serverPair = new Key('DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo', '64EYRvdPpTfLGGmaX5nijLXRqWXaVz8r1Z1GtaahXwVSJGQRn7tqkxLb288zwSYzELMEG5ZhXSBYSxsTsz1m9y8F') + const clientPair = new Key('HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd', '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP') + const res = await newWS2PBidirectionnalConnection(serverPair, clientPair, new (class TestingHandler implements WS2PMessageHandler { + + async handlePushMessage(json: any): Promise<void> { + } + + async handleRequestMessage(json: any): Promise<WS2PResponse> { + return await WS2PResponder(json, new (class TestingMapper implements WS2PReqMapper { + async getCurrent(): Promise<BlockDTO> { + return BlockDTO.fromJSONObject({ number: 1, hash: 'A' }) + } + })) + } + })) + s1 = res.p1 + c1 = res.p2 + wss = res.wss + }) + + after((done) => { + wss.close(done) + }) + + it('should accept the connection if everything is OK on both side', async () => { + const requester1 = WS2PRequester.fromConnection(c1) + assert.deepEqual(await requester1.getCurrent(), { + "actives": [], + "certifications": [], + "currency": "", + "dividend": null, + "excluded": [], + "fork": false, + "hash": "A", + "identities": [], + "issuer": "", + "issuersCount": null, + "issuersFrame": null, + "issuersFrameVar": null, + "joiners": [], + "leavers": [], + "medianTime": null, + "membersCount": null, + "monetaryMass": 0, + "nonce": null, + "number": 1, + "parameters": "", + "powMin": null, + "revoked": [], + "signature": "", + "time": null, + "transactions": [], + "unitbase": null, + "version": 10 + }) + }) +})