Superalgos Network: handshakeProducedure implemented

This commit is contained in:
Luis Fernando Molina committed 2021-09-02 09:50:58 +02:00
1 parent b08828a092
commit ddb1af522f
5 files changed
+345 -55

No files matched your search

@@ -9,12 +9,16 @@ exports.newNetworkModulesWebSocketsInterface = function newNetworkModulesWebSock
let clientInterface
let peerInterface
let web3 = new SA.nodeModules.web3()
return thisObject
function finalize() {
socketServer = undefined
clientInterface = undefined
peerInterface = undefined
web3 = undefined
}
function initialize() {
@@ -31,6 +35,8 @@ exports.newNetworkModulesWebSocketsInterface = function newNetworkModulesWebSock
function onConnection(socket) {
let caller = {}
let calledTimestamp = (new Date()).valueOf()
socket.on('message', onMenssage)
async function onMenssage(message) {
@@ -60,7 +66,7 @@ exports.newNetworkModulesWebSocketsInterface = function newNetworkModulesWebSock
switch (messageHeader.messageType) {
case "Handshake": {
handshakeProducedure(socket, caller, messageHeader)
handshakeProducedure(socket, caller, calledTimestamp, messageHeader)
break
}
case "Request": {
@@ -95,75 +101,213 @@ exports.newNetworkModulesWebSocketsInterface = function newNetworkModulesWebSock
}
}
function handshakeProducedure(socket, caller, messageHeader) {
function handshakeProducedure(socket, caller, calledTimestamp, messageHeader) {
/*
The caller needs to identify itself as either a Network Client or Peer.
The handshage producedure have 2 steps, we need to know
now which one we are at.
*/
if (messageHeader.callerRole === undefined) {
if (messageHeader.step === undefined) {
let response = {
result: 'Error',
message: 'callerRole Not Provided.'
message: 'step Not Provided.'
}
socket.send(JSON.stringify(response))
return
}
if (messageHeader.callerRole !== 'Network Client' && messageHeader.callerRole !== 'Network Peer') {
if (messageHeader.step !== 'One' && messageHeader.step !== 'Two') {
let response = {
result: 'Error',
message: 'callerRole Not Supported.'
message: 'step Not Supported.'
}
socket.send(JSON.stringify(response))
return
}
switch (messageHeader.step) {
case 'One': {
handshakeStepOne()
break
}
case 'Two': {
handshakeStepTwo()
break
}
}
function handshakeStepOne() {
/*
The caller needs to identify itself as either a Network Client or Peer.
*/
if (messageHeader.callerRole === undefined) {
let response = {
result: 'Error',
message: 'callerRole Not Provided.'
}
socket.send(JSON.stringify(response))
return
}
if (messageHeader.callerRole !== 'Network Client' && messageHeader.callerRole !== 'Network Peer') {
let response = {
result: 'Error',
message: 'callerRole Not Supported.'
}
socket.send(JSON.stringify(response))
return
}
caller.role = messageHeader.callerRole
/*
The caller needs to provide it's User Profile Handle.
*/
if (messageHeader.callerProfileHandle === undefined) {
let response = {
result: 'Error',
message: 'callerProfileHandle Not Provided.'
}
socket.send(JSON.stringify(response))
return
}
caller.userProfileHandle = messageHeader.callerProfileHandle
/*
The caller needs to provide a callerTimestamp.
*/
if (messageHeader.callerTimestamp === undefined) {
let response = {
result: 'Error',
message: 'callerTimestamp Not Provided.'
}
socket.send(JSON.stringify(response))
return
}
/*
The callerTimestamp can not be more that 1 minute old.
*/
if (calledTimestamp - messageHeader.callerTimestamp > 60000) {
let response = {
result: 'Error',
message: 'callerTimestamp Too Old.'
}
socket.send(JSON.stringify(response))
return
}
/*
We will sign for the caller it's handle to prove our
Network Node identity.
*/
let signedMessage = {
callerProfileHandle: messageHeader.callerProfileHandle,
calledProfileHandle: NT.NETWORK_NODE_USER_PROFILE_HANDLE,
callerTimestamp: messageHeader.callerTimestamp,
calledTimestamp: calledTimestamp
}
let signature = web3.eth.accounts.sign(JSON.stringify(signedMessage), NT.NETWORK_NODE_USER_PROFILE_PRIVATE_KEY)
caller.role = messageHeader.callerRole
/*
We will identify the caller by the signature at the message.
*/
if (messageHeader.signature === undefined) {
let response = {
result: 'Error',
message: 'signature Not Provided.'
result: 'Ok',
message: 'Handshake Step One Complete',
signature: JSON.stringify(signature)
}
socket.send(JSON.stringify(response))
return
}
let web3 = new SA.nodeModules.web3()
let blockchainAccount = web3.eth.accounts.recover(messageHeader.signature)
function handshakeStepTwo() {
/*
We will check that the caller role has beed defined at Step One.
*/
if (caller.role === undefined) {
let response = {
result: 'Error',
message: 'Handshake Step One Not Completed.'
}
socket.se
}
/*
We will check the signature at the message.
*/
if (messageHeader.signature === undefined) {
let response = {
result: 'Error',
message: 'signature Not Provided.'
}
socket.send(JSON.stringify(response))
return
}
let signature = JSON.parse(messageHeader.signature)
let blockchainAccount = web3.eth.accounts.recover(signature)
if (caller.blockchainAccount === undefined) {
let response = {
result: 'Error',
message: 'Bad Signature.'
}
socket.send(JSON.stringify(response))
return
}
/*
The signature gives us the blockchain account, and the account the user profile.
*/
let witnessUserProfile = NT.projects.socialTrading.globals.memory.maps.USER_PROFILES_BY_BLOCHAIN_ACCOUNT.set(blockchainAccount)
if (witnessUserProfile === undefined) {
let response = {
result: 'Error',
message: 'userProfile Not Found.'
}
socket.send(JSON.stringify(response))
return
}
/*
The user profile based on the blockchain account, based on the signature,
it is our witness user profile, to validate the caller.
*/
let signedMessage = JSON.parse(signature.message)
if (signedMessage.callerProfileHandle !== witnessUserProfile.userProfileHandle) {
let response = {
result: 'Error',
message: 'callerProfileHandle Does Not Match witnessUserProfile.'
}
socket.send(JSON.stringify(response))
return
}
/*
We will check that the signature includes this Network Node handle, to avoid
man in the middle attackts.
*/
if (signedMessage.calledProfileHandle !== NT.NETWORK_NODE_USER_PROFILE_HANDLE) {
let response = {
result: 'Error',
message: 'calledProfileHandle Does Not Match This Network Node Handle.'
}
socket.send(JSON.stringify(response))
return
}
/*
We will check that the timestamp in the signature is the one we sent to the caller.
*/
if (signedMessage.calledTimestamp !== calledTimestamp) {
let response = {
result: 'Error',
message: 'calledTimestamp Does Not Match calledTimestamp On Record.'
}
socket.send(JSON.stringify(response))
return
}
/*
All validations have been completed, the Handshake Prcedure finished well.
*/
/*
We will remember the user profile behind this caller.
*/
caller.userProfile = witnessUserProfile
if (caller.blockchainAccount === undefined) {
let response = {
result: 'Error',
message: 'Bad signature.'
result: 'Ok',
message: 'Handshake Successful.'
}
socket.send(JSON.stringify(response))
return
}
/*
The signature gives us the blockchain account, and the account the user profile.
*/
let userProfile = NT.projects.socialTrading.globals.memory.maps.USER_PROFILES_BY_BLOCHAIN_ACCOUNT.set(blockchainAccount)
if (userProfile === undefined) {
let response = {
result: 'Error',
message: 'userProfile Not Found.'
}
socket.send(JSON.stringify(response))
return
}
/*
We will remember the user profile behind this caller.
*/
caller.userProfile = userProfile
let response = {
result: 'Ok',
message: 'Handshake Successful.'
}
socket.send(JSON.stringify(response))
}
} catch (err) {
+150 -9
View File
@@ -9,6 +9,10 @@ exports.newNetworkModulesWebSocketsClient = function newNetworkModulesWebSockets
let socketClient
let callbackFunction
let web3 = new SA.nodeModules.web3()
let called = {}
let selectedNetworkNode // This is a Network Node we pick to try to connect to.
return thisObject
function finalize() {
@@ -16,10 +20,25 @@ exports.newNetworkModulesWebSocketsClient = function newNetworkModulesWebSockets
socketClient = undefined
networkInterface = undefined
peerInterface = undefined
web3 = undefined
called = undefined
}
function initialize() {
socketClient = new SA.nodeModules.ws('ws://' + 'localhost' + ':' + global.env.NETWORK_WEB_SOCKETS_INTERFACE_PORT)
/*
Here we will pick a Network Node from all users profiles available that do have a Network Node running. // TODO
*/
selectedNetworkNode = {
userProfileId: "qeqdqxex1qexqexqwxeqweqxeqweqe",
userProfileHandle: "Luis-Fernando-Molina",
blockchainAccount: "asdasdasdasdasdasdasdaasdasdasdasdasdasdsd",
ranking: 0,
host: "localhost",
port: global.env.NETWORK_WEB_SOCKETS_INTERFACE_PORT
}
socketClient = new SA.nodeModules.ws('ws://' + selectedNetworkNode.host + ':' + selectedNetworkNode.port)
//networkInterface = SA.projects.socialTrading.modules.networkInterface.newSocialTradingModulesNetworkInterface()
setUpWebsocketClient()
@@ -30,15 +49,137 @@ exports.newNetworkModulesWebSocketsClient = function newNetworkModulesWebSockets
let handshakeDone = false
socketClient.onopen = () => { onConnection() }
socketClient.onmessage = socketMessage => { onMenssage(socketMessage) }
socketClient.onerror = err => { onError(err) }
function onConnection() {
/*
Send Handshake Message
*/
socketClient.send('Handshake Message')
console.log('Handshake Message Sent')
handshakeProcedure()
function handshakeProcedure() {
let callerTimestamp
stepOneRequest()
function stepOneRequest() {
/*
Send Handshake Message Step One:
At Step One we will just say hello, identify ourselves
as a Network Client, and send the Network Node our
User Profile Handle.
This Handle will be signed by the Network Node to prove
it's ouwn identity, and later we will sign it's own handle
to prove ours.
*/
socketClient.onmessage = socketMessage => { stepOneResponse(socketMessage) }
callerTimestamp = (new Date()).valueOf()
let message = {
messageType: 'Handshake',
callerRole: 'Network Client',
userProfileHandle: DK.NETWORK_CLIENT_USER_PROFILE_HANDLE,
callerTimestamp: callerTimestamp,
step: 'One'
}
socketClient.send(message)
}
function stepOneResponse(socketMessage) {
let response = JSON.parse(socketMessage.data)
if (response.result !== 'Ok') {
console.log('[ERROR] Web Sockets Client -> stepOneResponse -> response.message = ' + response.message)
return
}
let signature = JSON.parse(response.signature)
called.blockchainAccount = web3.eth.accounts.recover(signature)
/*
We will check that the signature received produces a valid Blockchain Account.
*/
if (called.blockchainAccount === undefined) {
console.log('[ERROR] Web Sockets Client -> stepOneResponse -> Signature does not produce a valid Blockchain Account.')
return
}
/*
We will check that the blockchain account taken from the signature matches
the one we have on record for the user profile of the Network Node we are calling.
*/
if (called.blockchainAccount !== selectedNetworkNode.blockchainAccount) {
console.log('[ERROR] Web Sockets Client -> stepOneResponse -> The Network Node called does not have the expected Profile Handle.')
return
}
let signedMessage = JSON.parse(signature.message)
/*
We will check that the Network Node that responded has the same User Profile Handle
that we have on record, otherwise something is wrong and we should not proceed.
*/
if (signedMessage.calledProfileHandle !== selectedNetworkNode.userProfileHandle) {
console.log('[ERROR] Web Sockets Client -> stepOneResponse -> The Network Node called does not have the expected Profile Handle.')
return
}
/*
We will check that the profile handle we sent to the Network Node, is returned at the
signed message, to avoid man in the middle attackts.
*/
if (signedMessage.callerProfileHandle !== DK.NETWORK_CLIENT_USER_PROFILE_HANDLE) {
console.log('[ERROR] Web Sockets Client -> stepOneResponse -> The Network Node callerProfileHandle does not match my own userProfileHandle.')
return
}
/*
We will also check that the callerTimestamp we sent to the Network Node, is returned at the
signed message, also to avoid man in the middle attackts.
*/
if (signedMessage.callerTimestamp !== callerTimestamp) {
console.log('[ERROR] Web Sockets Client -> stepOneResponse -> The Network Node callerTimestamp does not match my own callerTimestamp.')
return
}
/*
All validations passed, it seems we can continue with Step Two.
*/
stepTwoRequest(signedMessage)
}
function stepTwoRequest(signedMessage) {
/*
Send Handshake Message Step Two:
Here we will sign a message with the Network Node profile
handle and timestamp to prove our own identity.
*/
socketClient.onmessage = socketMessage => { stepTwoResponse(socketMessage) }
let signature = web3.eth.accounts.sign(JSON.stringify(signedMessage), DK.NETWORK_CLIENT_USER_PROFILE_PRIVATE_KEY)
let message = {
messageType: 'Handshake',
signature: JSON.stringify(signature),
step: 'Two'
}
socketClient.send(message)
}
function stepTwoResponse(socketMessage) {
let response = JSON.parse(socketMessage.data)
if (response.result !== 'Ok') {
console.log('[ERROR] Web Sockets Client -> stepOneResponse -> response.message = ' + response.message)
return
}
/*
This was the end of the Handshake producere. We are connected to the
Network Node and from now on, all response messages will be received
at this following function.
*/
socketClient.onmessage = socketMessage => { onMenssage(socketMessage) }
}
}
}
async function onMenssage(socketMessage) {
@@ -53,10 +194,10 @@ exports.newNetworkModulesWebSocketsClient = function newNetworkModulesWebSockets
handshakeDone = true
return
} else {
console.log('[ERROR] Web Sockets Client -> onMenssage -> handshakeDone -> message.response = ' + response.message)
console.log('[ERROR] Web Sockets Client -> onMenssage -> handshakeDone -> response.message = ' + response.message)
return
}
}
}
callbackFunction.receiveResponse(message)
callbackFunction = undefined
@@ -105,7 +105,6 @@ exports.newSocialTradingModulesQueriesEvents = function newSocialTradingModulesQ
}
}
}
/*
Test #2 : The Emitter or Traget profile must be at the Following map of the Context Profile.
*/
+3
View File
@@ -45,6 +45,9 @@ SA.nodeModules = {
ws: require('ws')
}
DK.NETWORK_CLIENT_USER_PROFILE_HANDLE = "Julian-Molina" // TODO: remove this.
DK.NETWORK_CLIENT_USER_PROFILE_PRIVATE_KEY = "dasdasdjhakdhakhdkalshdkashdka" // TODO: remove this.
DK.app = require('./Desktop/DesktopApp.js').newDesktopApp()
DK.app.run()
+3
View File
@@ -46,6 +46,9 @@ SA.nodeModules = {
ws: require('ws')
}
NT.NETWORK_NODE_USER_PROFILE_HANDLE = "Luis-Fernando-Molina" // TODO: remove this.
NT.NETWORK_NODE_USER_PROFILE_PRIVATE_KEY = "blablablablablablablablablablablablablablablablabla" // TODO: remove this.
NT.app = require('./Network/NetwokNode.js').newNetworkNode()
NT.app.run()