Superalgos Network: handshakeProducedure implemented
This commit is contained in:
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) {
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
Reference in new issue
Block a user