indy-request
Advanced tools
Comparing version 0.0.2 to 0.1.0
155
index.js
let bs58 = require('bs58') | ||
let nacl = require('tweetnacl') | ||
let sodium = require('libsodium-wrappers') | ||
let zmq = require('zeromq') | ||
@@ -20,3 +20,3 @@ let EventEmitter = require('events') | ||
GET_SCHEMA: '107', | ||
GET_CLAIM_DEF: '108' | ||
GET_CRED_DEF: '108' | ||
} | ||
@@ -32,73 +32,85 @@ | ||
function IndyReq (conf) { | ||
if (typeof conf.timeout !== 'number') { | ||
conf.timeout = 1000 * 60 | ||
} | ||
let zsock = zmq.socket('dealer') | ||
let keypair = zmq.zmqCurveKeypair() | ||
zsock.identity = keypair.public | ||
zsock.curve_publickey = keypair.public | ||
zsock.curve_secretkey = keypair.secret | ||
zsock.curve_serverkey = conf.serverKey | ||
zsock.linger = 0 // TODO set correct timeout | ||
zsock.connect('tcp://' + conf.host + ':' + conf.port) | ||
let nextReqId = 1 | ||
let reqs = {} | ||
let api = new EventEmitter() | ||
zsock.on('message', function (msg) { | ||
try { | ||
let str = msg.toString('utf8') | ||
if (str === 'po') { | ||
api.emit('pong') | ||
return | ||
const initZmqSocket = (async function () { | ||
await sodium.ready | ||
if (typeof conf.timeout !== 'number') { | ||
conf.timeout = 1000 * 60 | ||
} | ||
if (conf.genesisTxn) { | ||
if (typeof conf.genesisTxn === 'string') { | ||
conf.genesisTxn = JSON.parse(conf.genesisTxn) | ||
} | ||
let data = JSON.parse(str) | ||
let reqId, err | ||
switch (data.op) { | ||
case 'REQACK': | ||
reqId = data.reqId | ||
if (reqs[reqId]) { | ||
reqs[reqId].ack = Date.now() | ||
} | ||
break | ||
case 'REQNACK': | ||
case 'REJECT': | ||
reqId = data.reqId | ||
err = new Error(data.reason) | ||
err.data = data | ||
if (reqs[reqId]) { | ||
reqs[reqId].reject(err) | ||
} else { | ||
api.emit('error', err) | ||
} | ||
break | ||
case 'REPLY': | ||
if (data.result && data.result.txn && data.result.txn.metadata) { | ||
reqId = data.result.txn.metadata.reqId | ||
} else { | ||
reqId = data.result.reqId | ||
} | ||
const dest = bs58.decode(conf.genesisTxn.txn.data.dest) | ||
conf.serverKey = sodium.crypto_sign_ed25519_pk_to_curve25519(dest) | ||
conf.host = conf.genesisTxn.txn.data.data.client_ip | ||
conf.port = conf.genesisTxn.txn.data.data.client_port | ||
} | ||
let zsock = zmq.socket('dealer') | ||
if (reqs[reqId]) { | ||
reqs[reqId].resolve(data) | ||
delete reqs[reqId] | ||
} else { | ||
let err = new Error('reqId not found: ' + reqId) | ||
let keypair = zmq.zmqCurveKeypair() | ||
zsock.identity = keypair.public | ||
zsock.curve_publickey = keypair.public | ||
zsock.curve_secretkey = keypair.secret | ||
zsock.curve_serverkey = conf.serverKey | ||
zsock.linger = 0 // TODO set correct timeout | ||
zsock.connect('tcp://' + conf.host + ':' + conf.port) | ||
zsock.on('message', function (msg) { | ||
try { | ||
let str = msg.toString('utf8') | ||
if (str === 'po') { | ||
api.emit('pong') | ||
return | ||
} | ||
let data = JSON.parse(str) | ||
let reqId, err | ||
switch (data.op) { | ||
case 'REQACK': | ||
reqId = data.reqId | ||
if (reqs[reqId]) { | ||
reqs[reqId].ack = Date.now() | ||
} | ||
break | ||
case 'REQNACK': | ||
case 'REJECT': | ||
reqId = data.reqId | ||
err = new Error(data.reason) | ||
err.data = data | ||
if (reqs[reqId]) { | ||
reqs[reqId].reject(err) | ||
} else { | ||
api.emit('error', err) | ||
} | ||
break | ||
case 'REPLY': | ||
if (data.result && data.result.txn && data.result.txn.metadata) { | ||
reqId = data.result.txn.metadata.reqId | ||
} else { | ||
reqId = data.result.reqId | ||
} | ||
if (reqs[reqId]) { | ||
reqs[reqId].resolve(data) | ||
delete reqs[reqId] | ||
} else { | ||
let err = new Error('reqId not found: ' + reqId) | ||
err.data = data | ||
api.emit('error', err) | ||
} | ||
break | ||
default: | ||
err = new Error('op not handled: ' + data.op) | ||
err.data = data | ||
api.emit('error', err) | ||
} | ||
break | ||
default: | ||
err = new Error('op not handled: ' + data.op) | ||
err.data = data | ||
api.emit('error', err) | ||
} | ||
} catch (err) { | ||
// TODO try MsgPack | ||
api.emit('error', err) | ||
} | ||
} catch (err) { | ||
// TODO try MsgPack | ||
api.emit('error', err) | ||
} | ||
}) | ||
}) | ||
return zsock | ||
}()) | ||
@@ -114,6 +126,9 @@ let checkTimeouts = setInterval(function () { | ||
api.ping = function ping () { | ||
api.ping = async function ping () { | ||
const zsock = await initZmqSocket | ||
zsock.send('pi') | ||
} | ||
api.send = function send (data, signKey) { | ||
api.send = async function send (data, signKey) { | ||
const zsock = await initZmqSocket | ||
let reqId = nextReqId++ | ||
@@ -123,4 +138,5 @@ data.reqId = reqId | ||
if (signKey) { | ||
await sodium.ready | ||
let serialized = serializeForSignature(data, true) | ||
data.signature = bs58.encode(Buffer.from(nacl.sign(Buffer.from(serialized, 'utf8'), signKey).slice(0, 64))) | ||
data.signature = bs58.encode(Buffer.from(sodium.crypto_sign(Buffer.from(serialized, 'utf8'), signKey).slice(0, 64))) | ||
} | ||
@@ -140,5 +156,6 @@ | ||
} | ||
api.close = function close () { | ||
api.close = async function close () { | ||
clearInterval(checkTimeouts) | ||
const zsock = await initZmqSocket | ||
zsock.close() | ||
clearInterval(checkTimeouts) | ||
Object.keys(reqs).forEach(function (reqId) { | ||
@@ -145,0 +162,0 @@ reqs[reqId].reject(new Error('Closed')) |
{ | ||
"name": "indy-request", | ||
"version": "0.0.2", | ||
"version": "0.1.0", | ||
"description": "Make requests to Indy (i.e. Sovrin) nodes", | ||
@@ -29,9 +29,9 @@ "main": "index.js", | ||
"bs58": "^4.0.1", | ||
"tweetnacl": "^1.0.0", | ||
"libsodium-wrappers": "^0.7.4", | ||
"zeromq": "^5.1.0" | ||
}, | ||
"devDependencies": { | ||
"ava": "^0.25.0", | ||
"ava": "^1.4.1", | ||
"standard": "^12.0.1" | ||
} | ||
} |
@@ -11,5 +11,3 @@ # indy-request | ||
let node = IndyReq({ | ||
host: '127.0.0.1', | ||
port: 9702, | ||
serverKey: bs58.decode('HXrfcFWDjWusENBoXhV8mARzq51f1npWYWaA1GzfeMDG') | ||
genesisTxn: '{"reqSignature":{},"txn":{"data":{"data":{"alias":"Node1","blskey":"4N8aUNHSgjQVgkpm8nhNEfDf6txHznoYREg9kirmJrkivgL4oSEimFF6nsQ6M41QvhM2Z33nves5vfSn9n1UwNFJBYtWVnHYMATn76vLuL3zU88KyeAYcHfsih3He6UHcXDxcaecHVz6jhCYz1P2UZn2bDVruL5wXpehgBfBaLKm3Ba","blskey_pop":"RahHYiCvoNCtPTrVtP7nMC5eTYrsUA8WjXbdhNc8debh1agE9bGiJxWBXYNFbnJXoXhWFMvyqhqhRoq737YQemH5ik9oL7R4NTTCz2LEZhkgLJzB3QRQqJyBNyv7acbdHrAT8nQ9UkLbaVL9NBpnWXBTw4LEMePaSHEw66RzPNdAX1","client_ip":"127.0.0.1","client_port":9702,"node_ip":"127.0.0.1","node_port":9701,"services":["VALIDATOR"]},"dest":"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv"},"metadata":{"from":"Th7MpTaRZVRYnPiabds81Y"},"type":"0"},"txnMetadata":{"seqNo":1,"txnId":"fea82e10e894419fe2bea7d96296a6d46f50f93f9eeda954ec461b2ed2950b62"},"ver":"1"}' | ||
}) | ||
@@ -38,2 +36,3 @@ | ||
* `conf.timeout` (optional) how long to wait for responses in ms. Default is 1min. | ||
* `conf.genesisTxn` instead of host+port+serverKey you can simply pass a line from the genesis transaction to the node you wish to connect to. | ||
@@ -40,0 +39,0 @@ ### p = node.send(data) |
41
test.js
let test = require('ava') | ||
let IndyReq = require('./') | ||
let bs58 = require('bs58') | ||
let nacl = require('tweetnacl') | ||
let sodium = require('libsodium-wrappers') | ||
let serializeForSignature = require('./serializeForSignature') | ||
@@ -138,4 +138,5 @@ | ||
let my1 = nacl.sign.keyPair.fromSeed(Buffer.from('00000000000000000000000000000My1', 'utf8')) | ||
let sender = nacl.sign.keyPair.fromSeed(Buffer.from('000000000000000000000000Trustee1', 'utf8')) | ||
await sodium.ready | ||
let my1 = sodium.crypto_sign_seed_keypair(Buffer.from('00000000000000000000000000000My1', 'utf8')) | ||
let sender = sodium.crypto_sign_seed_keypair(Buffer.from('000000000000000000000000Trustee1', 'utf8')) | ||
@@ -154,3 +155,3 @@ let my1DID = bs58.encode(Buffer.from(my1.publicKey.slice(0, 16))) | ||
protocolVersion: 2 | ||
}, sender.secretKey) | ||
}, sender.privateKey) | ||
@@ -181,3 +182,3 @@ t.is(resp.op, 'REPLY') | ||
protocolVersion: 2 | ||
}, my1.secretKey) | ||
}, my1.privateKey) | ||
@@ -194,3 +195,3 @@ t.is(resp.result.txn.data.raw, '{"some":"one"}') | ||
protocolVersion: 2 | ||
}, my1.secretKey) | ||
}, my1.privateKey) | ||
@@ -229,5 +230,5 @@ t.is(resp.result.txn.data.raw, '{"another":"thing"}') | ||
}, | ||
identifier: senderDID, | ||
identifier: my1DID, | ||
protocolVersion: 2 | ||
}, sender.secretKey) | ||
}, my1.privateKey) | ||
@@ -242,3 +243,3 @@ resp = await node.send({ | ||
protocolVersion: 2 | ||
}, my1.secretKey) | ||
}, my1.privateKey) | ||
@@ -255,3 +256,3 @@ t.is(resp.result.txn.data.raw, '{"some":"one"}') | ||
protocolVersion: 2 | ||
}, my1.secretKey) | ||
}, my1.privateKey) | ||
@@ -286,1 +287,21 @@ t.is(resp.result.txn.data.raw, '{"another":"thing"}') | ||
}) | ||
test.cb('genesisTxn', function (t) { | ||
let node = IndyReq({ | ||
genesisTxn: '{"reqSignature":{},"txn":{"data":{"data":{"alias":"Node1","blskey":"4N8aUNHSgjQVgkpm8nhNEfDf6txHznoYREg9kirmJrkivgL4oSEimFF6nsQ6M41QvhM2Z33nves5vfSn9n1UwNFJBYtWVnHYMATn76vLuL3zU88KyeAYcHfsih3He6UHcXDxcaecHVz6jhCYz1P2UZn2bDVruL5wXpehgBfBaLKm3Ba","blskey_pop":"RahHYiCvoNCtPTrVtP7nMC5eTYrsUA8WjXbdhNc8debh1agE9bGiJxWBXYNFbnJXoXhWFMvyqhqhRoq737YQemH5ik9oL7R4NTTCz2LEZhkgLJzB3QRQqJyBNyv7acbdHrAT8nQ9UkLbaVL9NBpnWXBTw4LEMePaSHEw66RzPNdAX1","client_ip":"127.0.0.1","client_port":9702,"node_ip":"127.0.0.1","node_port":9701,"services":["VALIDATOR"]},"dest":"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv"},"metadata":{"from":"Th7MpTaRZVRYnPiabds81Y"},"type":"0"},"txnMetadata":{"seqNo":1,"txnId":"fea82e10e894419fe2bea7d96296a6d46f50f93f9eeda954ec461b2ed2950b62"},"ver":"1"}' | ||
}) | ||
t.plan(2) | ||
node.on('error', t.fail) | ||
node.on('pong', function () { | ||
t.pass('got pong') | ||
node.close() | ||
}) | ||
node.on('close', function () { | ||
t.pass('got close') | ||
t.end() | ||
}) | ||
node.ping() | ||
}) |
Sorry, the diff of this file is not supported yet
18682
8
478
64
+ Addedlibsodium-wrappers@^0.7.4
+ Addedlibsodium@0.7.15(transitive)
+ Addedlibsodium-wrappers@0.7.15(transitive)
- Removedtweetnacl@^1.0.0
- Removedtweetnacl@1.0.3(transitive)