diff --git a/Desktop/DesktopApp.js b/Desktop/DesktopApp.js index 3c225154c..ea5bceab3 100644 --- a/Desktop/DesktopApp.js +++ b/Desktop/DesktopApp.js @@ -6,21 +6,16 @@ exports.newDesktopApp = function newDesktopApp() { return thisObject - function run() { + async function run() { +/* + let socialGraphService = NT.projects.network.modules.socialGraph.newSocialGraph() + await socialGraphService.initialize() +*/ /* Let's start the Network Interfaces */ DK.webSocketsClient = SA.projects.network.modules.webSocketsClient.newNetworkModulesWebSocketsClient() DK.webSocketsClient.initialize() - - return - start() - - async function start() { - let socialGraphService = NT.projects.network.modules.socialGraph.newSocialGraph() - await socialGraphService.initialize() - } - } } diff --git a/Projects/Governance/Plugins/User-Profiles/Test-Network-Client-Profile.json b/Projects/Governance/Plugins/User-Profiles/Test-Network-Client-Profile.json new file mode 100644 index 000000000..d8721b28c --- /dev/null +++ b/Projects/Governance/Plugins/User-Profiles/Test-Network-Client-Profile.json @@ -0,0 +1,84 @@ +{ + "type": "User Profile", + "name": "Test-Network-Client-Profile", + "config": "{\n \"signature\": {\n \"message\": \"Test-Network-Client-Profile\",\n \"messageHash\": \"0xd768f828a837f3fa0c3e9bb8090820c415ff08be93cad759a53bc2115487c5d7\",\n \"v\": \"0x1c\",\n \"r\": \"0x1401b80eec441aa9789580848e0179f36485acab9562fe184bca5e2fd9e77887\",\n \"s\": \"0x06400cef3453437805fb9b086c246d7def27a146ed975450edf7dcc46795a57d\",\n \"signature\": \"0x1401b80eec441aa9789580848e0179f36485acab9562fe184bca5e2fd9e7788706400cef3453437805fb9b086c246d7def27a146ed975450edf7dcc46795a57d1c\"\n }\n}", + "project": "Governance", + "tokenPowerSwitch": { + "type": "Token Power Switch", + "name": "New Token Power Switch", + "config": "{}", + "project": "Governance", + "tokenPowerSwitch": [], + "id": "c2a1f8b1-0eb3-457a-9508-2e0c813ced37", + "savedPayload": { + "position": { + "x": 13282, + "y": 11240.5 + }, + "targetPosition": { + "x": 13327, + "y": 11256.5 + }, + "floatingObject": { + "isPinned": false, + "isFrozen": false, + "isCollapsed": false, + "angleToParent": 1, + "distanceToParent": 3, + "arrangementStyle": 0 + }, + "uiObject": { + "isRunning": false + } + } + }, + "tokensMined": { + "type": "Tokens Mined", + "name": "New Tokens Mined", + "project": "Governance", + "id": "e796be1b-7d10-47f1-8b1a-4d7ce962a113", + "savedPayload": { + "position": { + "x": 13400, + "y": 11204.5 + }, + "targetPosition": { + "x": 13327, + "y": 11256.5 + }, + "floatingObject": { + "isPinned": false, + "isFrozen": false, + "isCollapsed": false, + "angleToParent": 1, + "distanceToParent": 3, + "arrangementStyle": 0 + }, + "uiObject": { + "isRunning": false + } + } + }, + "id": "baa2f02c-2920-4edb-a103-d452fc61d82f", + "savedPayload": { + "position": { + "x": 13327, + "y": 11256.5 + }, + "targetPosition": { + "x": 13297, + "y": 11290.5 + }, + "floatingObject": { + "isPinned": false, + "isFrozen": false, + "isCollapsed": false, + "angleToParent": 1, + "distanceToParent": 3, + "arrangementStyle": 0 + }, + "uiObject": { + "isRunning": false + } + } +} \ No newline at end of file diff --git a/Projects/Governance/Plugins/User-Profiles/Test-Network-Node-Profile.json b/Projects/Governance/Plugins/User-Profiles/Test-Network-Node-Profile.json new file mode 100644 index 000000000..23fb48537 --- /dev/null +++ b/Projects/Governance/Plugins/User-Profiles/Test-Network-Node-Profile.json @@ -0,0 +1,84 @@ +{ + "type": "User Profile", + "name": "Test-Network-Node-Profile", + "config": "{\n \"signature\": {\n \"message\": \"Test-Network-Node-Profile\",\n \"messageHash\": \"0xa05026b7c6c2a2375480d5d24949621749cc48e461e6e80278a9ef1b6dc7c5f1\",\n \"v\": \"0x1c\",\n \"r\": \"0x8f28f992b0074e4d50007cdfbf18980ca58b4969e04a54d06e4d4798bb982c9a\",\n \"s\": \"0x1c11951a92a1beffe8f3ddd06426ebe1b89875b56d5e374426100d5f59245ea3\",\n \"signature\": \"0x8f28f992b0074e4d50007cdfbf18980ca58b4969e04a54d06e4d4798bb982c9a1c11951a92a1beffe8f3ddd06426ebe1b89875b56d5e374426100d5f59245ea31c\"\n }\n}", + "project": "Governance", + "tokenPowerSwitch": { + "type": "Token Power Switch", + "name": "New Token Power Switch", + "config": "{}", + "project": "Governance", + "tokenPowerSwitch": [], + "id": "11f69cbe-00c8-4fac-9fcc-701a7600c92c", + "savedPayload": { + "position": { + "x": 13516, + "y": 11661 + }, + "targetPosition": { + "x": 13486, + "y": 11579 + }, + "floatingObject": { + "isPinned": false, + "isFrozen": false, + "isCollapsed": false, + "angleToParent": 1, + "distanceToParent": 3, + "arrangementStyle": 0 + }, + "uiObject": { + "isRunning": false + } + } + }, + "tokensMined": { + "type": "Tokens Mined", + "name": "New Tokens Mined", + "project": "Governance", + "id": "501f456f-b4b5-4b7e-9118-0f26215dd20e", + "savedPayload": { + "position": { + "x": 13470, + "y": 11657 + }, + "targetPosition": { + "x": 13486, + "y": 11579 + }, + "floatingObject": { + "isPinned": false, + "isFrozen": false, + "isCollapsed": false, + "angleToParent": 1, + "distanceToParent": 3, + "arrangementStyle": 0 + }, + "uiObject": { + "isRunning": false + } + } + }, + "id": "36c2b050-631f-4291-987c-418adc94317d", + "savedPayload": { + "position": { + "x": 13486, + "y": 11579 + }, + "targetPosition": { + "x": 13413, + "y": 11508 + }, + "floatingObject": { + "isPinned": false, + "isFrozen": false, + "isCollapsed": false, + "angleToParent": 1, + "distanceToParent": 3, + "arrangementStyle": 0 + }, + "uiObject": { + "isRunning": false + } + } +} \ No newline at end of file diff --git a/Projects/Network/NT/Modules/WebSocketsInterface.js b/Projects/Network/NT/Modules/WebSocketsInterface.js index a1a286d87..f40faaed3 100644 --- a/Projects/Network/NT/Modules/WebSocketsInterface.js +++ b/Projects/Network/NT/Modules/WebSocketsInterface.js @@ -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,214 @@ 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.send(JSON.stringify(response)) + return + } + /* + 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) + caller.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.get(caller.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) { diff --git a/Projects/Network/SA/Modules/WebSocketsClient.js b/Projects/Network/SA/Modules/WebSocketsClient.js index 01e53f1ed..d5925aae7 100644 --- a/Projects/Network/SA/Modules/WebSocketsClient.js +++ b/Projects/Network/SA/Modules/WebSocketsClient.js @@ -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,29 @@ 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 + In the meantime, we will assume that we have chosen the following Network Node to connect to. + { + "githubUsername": "Test-Network-Node-Profile", + "address": "0xa153469c57A91F5a59Fc6c45A37aD8dbad85e417" + } + */ + selectedNetworkNode = { + userProfileHandle: "Test-Network-Node-Profile", + blockchainAccount: "0xa153469c57A91F5a59Fc6c45A37aD8dbad85e417", + 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 +53,138 @@ 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', + callerProfileHandle: DK.TEST_NETWORK_CLIENT_USER_PROFILE_HANDLE, + callerTimestamp: callerTimestamp, + step: 'One' + } + socketClient.send(JSON.stringify(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.TEST_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.TEST_NETWORK_CLIENT_USER_PROFILE_PRIVATE_KEY) + + let message = { + messageType: 'Handshake', + signature: JSON.stringify(signature), + step: 'Two' + } + socketClient.send(JSON.stringify(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 + } + console.log('[INFO] Web Sockets Client -> stepTwoResponse -> response.message = ' + response.message) + /* + 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 +199,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 diff --git a/Projects/Social-Trading/NT/Modules/Queries/Events.js b/Projects/Social-Trading/NT/Modules/Queries/Events.js index 0565bf027..a68d7215b 100644 --- a/Projects/Social-Trading/NT/Modules/Queries/Events.js +++ b/Projects/Social-Trading/NT/Modules/Queries/Events.js @@ -78,11 +78,9 @@ exports.newSocialTradingModulesQueriesEvents = function newSocialTradingModulesQ /* The context is a User Profile */ - if (emitterUserProfile !== undefined) { - if (emitterUserProfile.userProfileId === thisObject.profile.userProfileId) { - addToResponse(event) - return - } + if (emitterUserProfile.userProfileId === thisObject.profile.userProfileId) { + addToResponse(event) + return } if (targetUserProfile !== undefined) { if (targetUserProfile.userProfileId === thisObject.profile.userProfileId) { @@ -107,7 +105,6 @@ exports.newSocialTradingModulesQueriesEvents = function newSocialTradingModulesQ } } } - /* Test #2 : The Emitter or Traget profile must be at the Following map of the Context Profile. */ @@ -115,11 +112,9 @@ exports.newSocialTradingModulesQueriesEvents = function newSocialTradingModulesQ /* The context is a User Profile */ - if (emitterUserProfile !== undefined) { - if (thisObject.profile.following.get(emitterUserProfile.userProfileId) !== undefined) { - addToResponse(event) - return - } + if (thisObject.profile.following.get(emitterUserProfile.userProfileId) !== undefined) { + addToResponse(event) + return } if (targetUserProfile !== undefined) { if (thisObject.profile.following.get(targetUserProfile.userProfileId) !== undefined) { diff --git a/runDesktop.js b/runDesktop.js index 96c4c24c5..96d54c44b 100644 --- a/runDesktop.js +++ b/runDesktop.js @@ -45,6 +45,18 @@ SA.nodeModules = { ws: require('ws') } +/* +We will use this User Profile for Testing Purposes. +{ + "githubUsername": "Test-Network-Client-Profile", + "address": "0xA0dCDA81b42C5EBDc45EC2875C72274B67560246", + "privateKey": "0x5fed4817a87431c8a328d0936561e63f45b6db289adac6125b9306ded644dfe9" +} +*/ + +DK.TEST_NETWORK_CLIENT_USER_PROFILE_HANDLE = "Test-Network-Client-Profile" +DK.TEST_NETWORK_CLIENT_USER_PROFILE_PRIVATE_KEY = "0x5fed4817a87431c8a328d0936561e63f45b6db289adac6125b9306ded644dfe9" + DK.app = require('./Desktop/DesktopApp.js').newDesktopApp() DK.app.run() diff --git a/runNetwork.js b/runNetwork.js index 9aae83d5e..a0b0b2c33 100644 --- a/runNetwork.js +++ b/runNetwork.js @@ -46,6 +46,17 @@ SA.nodeModules = { ws: require('ws') } +/* +We will use this User Profile for testing purposes. +{ + "githubUsername": "Test-Network-Node-Profile", + "address": "0xa153469c57A91F5a59Fc6c45A37aD8dbad85e417", + "privateKey": "0xac498ae59407e6b68429a814f64da2339550f93a767578e28c161ff119159271" +} +*/ +NT.NETWORK_NODE_USER_PROFILE_HANDLE = "Test-Network-Node-Profile" +NT.NETWORK_NODE_USER_PROFILE_PRIVATE_KEY = "0xac498ae59407e6b68429a814f64da2339550f93a767578e28c161ff119159271" + NT.app = require('./Network/NetwokNode.js').newNetworkNode() NT.app.run()