Skip to content

Commit

Permalink
Add sample script to init and call the secure owner API from node.js (#…
Browse files Browse the repository at this point in the history
…335)

* add sample script to init and call the secure owner API from node

* fix xiaojay's name.. thanks xiaojay!
  • Loading branch information
yeastplume authored Feb 18, 2020
1 parent da064ac commit 1ced899
Show file tree
Hide file tree
Showing 4 changed files with 291 additions and 0 deletions.
115 changes: 115 additions & 0 deletions doc/samples/v3_api_node/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions doc/samples/v3_api_node/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "node-sample",
"version": "0.0.1",
"description": "Sample of connecting to the secure OwnerAPI via node",
"main": "src/index.js",
"scripts": {
"test": "npm test"
},
"author": "",
"license": "ISC",
"dependencies": {
"jayson": "^3.2.0"
}
}
28 changes: 28 additions & 0 deletions doc/samples/v3_api_node/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Connecting to the wallet's V3 Owner API from Node

This is a small sample with code that demonstrates how to initialize the Wallet V3's Secure API and call API functions through it.

To run this sample:

First run the Owner API:

```.sh
grin-wallet owner_api
```

This sample doesn't use the authentication specified in the wallet's `.api_secret`, so before running the owner_api please ensure api authentication is commented out in `grin-wallet.toml`. Including the authentication token as part of the request is a function of your json-rpc client library of choice, so it's not included in the sample to make setup a bit simpler.

ensure the client url in `src\index.js` is set correctly:

```.sh
const client = jayson.client.http('http://localhost:3420/v3/owner');
```

Then (assuming node.js and npm are installed on the system):

```.sh
npm install
node src/index.json
```

Feel free to play around with the sample, modifying it to call whatever functions you'd like to see in operation!
134 changes: 134 additions & 0 deletions doc/samples/v3_api_node/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/* Sample Code for connecting to the V3 Secure API via Node
*
* With thanks to xiaojay of Niffler Wallet:
* https://github.com/grinfans/Niffler/blob/gw3/src/shared/walletv3.js
*
*/

const jayson = require('jayson/promise');
const crypto = require('crypto');

const client = jayson.client.http('http://localhost:3420/v3/owner');

// Demo implementation of using `aes-256-gcm` with node.js's `crypto` lib.
const aes256gcm = (shared_secret) => {
const ALGO = 'aes-256-gcm';

// encrypt returns base64-encoded ciphertext
const encrypt = (str, nonce) => {
let key = Buffer.from(shared_secret, 'hex')
const cipher = crypto.createCipheriv(ALGO, key, nonce)
const enc = Buffer.concat([cipher.update(str, 'utf8'), cipher.final()])
const tag = cipher.getAuthTag()
return Buffer.concat([enc, tag]).toString('base64')
};

// decrypt decodes base64-encoded ciphertext into a utf8-encoded string
const decrypt = (enc, nonce) => {
//key,nonce is all buffer type; data is base64-encoded string
let key = Buffer.from(shared_secret, 'hex')
const data_ = Buffer.from(enc, 'base64')
const decipher = crypto.createDecipheriv(ALGO, key, nonce)
const len = data_.length
const tag = data_.slice(len-16, len)
const text = data_.slice(0, len-16)
decipher.setAuthTag(tag)
const dec = decipher.update(text, 'binary', 'utf8') + decipher.final('utf8');
return dec
};

return {
encrypt,
decrypt,
};
};

class JSONRequestEncrypted {
constructor(id, method, params) {
this.jsonrpc = '2.0'
this.method = method
this.id = id
this.params = params
}

async send(key){
const aesCipher = aes256gcm(key);
const nonce = new Buffer.from(crypto.randomBytes(12));
let enc = aesCipher.encrypt(JSON.stringify(this), nonce);
console.log("Encrypted: " + enc)
let params = {
'nonce': nonce.toString('hex'),
'body_enc': enc,
}
let response = await client.request('encrypted_request_v3', params);

if (response.err) {
throw response.err
}

const nonce2 = Buffer.from(response.result.Ok.nonce, 'hex');
const data = Buffer.from(response.result.Ok.body_enc, 'base64');

let dec = aesCipher.decrypt(data, nonce2)
return dec
}
}

async function initSecure() {
let ecdh = crypto.createECDH('secp256k1')
ecdh.generateKeys()
let publicKey = ecdh.getPublicKey('hex', 'compressed')
const params = {
'ecdh_pubkey': publicKey
}
let response = await client.request('init_secure_api', params);
if (response.err) {
throw response.err
}

return ecdh.computeSecret(response.result.Ok, 'hex', 'hex')
}

function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}

async function main() {
let shared_key = await initSecure();

let response = await new JSONRequestEncrypted(1, 'open_wallet', {
"name": null,
"password": "",
}).send(shared_key);

let token = JSON.parse(response).result.Ok;

let iterations = 1;

for (i=0; i<iterations*2; i+=2) {
let info_response = await new JSONRequestEncrypted(i, 'retrieve_summary_info', {
"token": token,
"refresh_from_node": true,
"minimum_confirmations": 1,
}).send(shared_key)

console.log("Info Response: ", info_response);
await sleep(2000)

let txs_response = await new JSONRequestEncrypted(i+1, 'retrieve_txs', {
"token": token,
"refresh_from_node": true,
"tx_id": null,
"tx_slate_id": null,
}).send(shared_key)

console.log("Txs Response: ", txs_response);
await sleep(2000)
}
}



main();


0 comments on commit 1ced899

Please sign in to comment.