Last active
December 10, 2015 15:15
-
-
Save hitman401/0e6cfb7e2d1b7fff0dfd to your computer and use it in GitHub Desktop.
Handshake example code nodejs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var sodium = require('libsodium-wrappers'); | |
var log = require('npmlog'); | |
// These are the commandline parameters from the launcher while starting the application | |
// Assign these values at run time, if trying this example | |
var HOST, PORT, LAUNCHER_NONCE; | |
var ResponseBufferHandler = function(onResponseCallback) { | |
var bufferQueue = []; | |
var processing = false; | |
var expectedLength = 0; | |
var response = []; | |
var responseCallback = onResponseCallback || function() {/* no-op */}; | |
var readyToReadResponse = true; | |
var addToNextBuffer = function(buffer) { | |
bufferQueue[0] = bufferQueue.length === 0 ? buffer : Buffer.concat([buffer, bufferQueue[0]]); | |
}; | |
var reset = function (buff) { | |
var lengthBuff = buff.slice(0, 8); | |
buff = buff.slice(8); | |
var uintArray = new Uint8Array(lengthBuff); | |
var view = new DataView(uintArray.buffer); | |
expectedLength = view.getUint32(0, true); | |
response = []; | |
if (buff.length > 0) { | |
addToNextBuffer(buff); | |
} | |
}; | |
var read = function(buff) { | |
if (buff.length > expectedLength) { | |
addToNextBuffer(buff.slice(expectedLength)); | |
buff = buff.slice(0, expectedLength); | |
} | |
expectedLength -= buff.length; | |
response = response.concat(buff); | |
return expectedLength <= 0; | |
}; | |
var run = function() { | |
try { | |
while (bufferQueue.length !== 0) { | |
var buff; | |
if (bufferQueue[0].length < 8 && readyToReadResponse && bufferQueue.length === 1) { | |
continue; | |
} | |
buff = bufferQueue.splice(0, 1)[0]; | |
if (readyToReadResponse) { | |
readyToReadResponse = false; | |
reset(buff); | |
} else if (read(buff)) { | |
responseCallback(response); | |
readyToReadResponse = true; | |
} | |
} | |
} catch(e) { | |
console.log(e); | |
} | |
processing = false; | |
}; | |
this.addBuffer = function(buff) { | |
bufferQueue.push(buff); | |
if (!processing) { | |
processing = true; | |
run(); | |
} | |
}; | |
return this; | |
}; | |
var Connection = function() { | |
var net = require('net'); | |
var log = require('npmlog'); | |
var socket; | |
var onDataReceivedListener; | |
var onConnectionErrorListener; | |
var alive = false; | |
var HOST = 'localhost'; | |
var LENGTH_SIZE = 8; | |
var setOnDataRecievedListener = function(listnerCallback) { | |
onDataReceivedListener = listnerCallback; | |
}; | |
var setOnConnectionErrorListener = function(listnerCallback) { | |
onConnectionErrorListener = listnerCallback; | |
}; | |
var OPTIONS = { | |
'onData': setOnDataRecievedListener, | |
'onError': setOnConnectionErrorListener | |
}; | |
var setFromOptions = function(options) { | |
for (var key in OPTIONS) { | |
if (!options.hasOwnProperty(key)) { | |
continue; | |
} | |
OPTIONS[key](options[key]); | |
} | |
}; | |
var onDataReceived = function(data) { | |
log.verbose('Data received from launcher'); | |
if (!onDataReceivedListener) { | |
return; | |
} | |
responseBuffer.addBuffer(data); | |
}; | |
var onResponse = function(response) { | |
onDataReceivedListener(response); | |
}; | |
var responseBuffer = new ResponseBufferHandler(onResponse); | |
var onConnectionError = function() { | |
var connectionDroppedMsg = 'Connection with the launcher disconnected'; | |
var couldNotEstablishConMsg = 'Connection could not be established'; | |
log.error(alive ? connectionDroppedMsg : couldNotEstablishConMsg); | |
alive = false; | |
if (!onConnectionErrorListener) { | |
return; | |
} | |
onConnectionErrorListener(); | |
}; | |
/** | |
* connect function is invoked to connect to a port on the local machine | |
* callback will be invoked only when the connection is successful | |
* else the onClosed listener will be invoked if the connection fails | |
*/ | |
this.connect = function(host, portNumber, callback, options) { | |
if (options) { | |
setFromOptions(options); | |
} | |
host = host || HOST; | |
log.verbose('Connecting with the launcher at - ' + host + ':' + portNumber); | |
socket = new net.Socket(); | |
socket.on('data', onDataReceived); | |
//socket.on('error', onConnectionError); | |
socket.on('close', onConnectionError); | |
socket.connect(portNumber, host, function() { | |
alive = true; | |
log.verbose('Connected with the launcher at port : ' + portNumber); | |
callback(); | |
}); | |
}; | |
/** | |
* Write data to the launcher TCP connection | |
* Length(U64INT - Little Endian format) of the data is prepended as before the data. | |
* @param data - Object | |
*/ | |
this.send = function(data) { | |
var lengthAsLE = new Buffer(LENGTH_SIZE); | |
lengthAsLE.fill(0); | |
lengthAsLE.writeUInt32LE(data.length); | |
socket.write(lengthAsLE); | |
socket.write(data); | |
}; | |
this.isAlive = function() { | |
return alive; | |
}; | |
this.setOnDataRecievedListener = setOnDataRecievedListener; | |
this.setOnConnectionErrorListener = setOnConnectionErrorListener; | |
}; | |
var handshakeKeys = sodium.crypto_box_keypair(); | |
var handshakeNonce = sodium.randombytes_buf(sodium.crypto_box_NONCEBYTES); | |
var launcherConnection = new Connection(); | |
var onConnectionError = function(err) { | |
log.error(err); | |
}; | |
var onHandShakeComplete = function(handshakeResponse) { | |
handshakeResponse = JSON.parse(handshakeResponse); | |
var launcherPublicKey = new Uint8Array(new Buffer(handshakeResponse.data.launcher_public_key, 'base64')); | |
var uint8Array = new Uint8Array(new Buffer(handshakeResponse.data.encrypted_symm_key, 'base64')); | |
var decryptedSymmKey = sodium.crypto_box_open_easy(uint8Array, handshakeNonce, launcherPublicKey, handshakeKeys.privateKey); | |
var encryptionNonce = decryptedSymmKey.subarray(0, sodium.crypto_secretbox_NONCEBYTES); | |
var encryptionKey = decryptedSymmKey.subarray(sodium.crypto_secretbox_NONCEBYTES); | |
log.info('Symmetric keys for Communication obtained - Handshake completed'); | |
}; | |
var startHandshake = function() { | |
var assymNonce = new Buffer(handshakeNonce).toString('base64'); | |
var publicKey = new Buffer(handshakeKeys.publicKey).toString('base64'); | |
var request = { | |
"endpoint": "safe-api/v1.0/handshake/authenticate-app", | |
"data": { | |
"launcher_string": LAUNCHER_NONCE, | |
"asymm_nonce": assymNonce, | |
"asymm_pub_key": publicKey | |
} | |
}; | |
launcherConnection.send(JSON.stringify(request)); | |
}; | |
launcherConnection.connect(HOST, PORT, startHandshake, { | |
'onData': onHandShakeComplete, | |
'onError': onConnectionError | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment