From 82efc8001de0504c042bc6dbb3ebb5986ceb412e Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Tue, 24 Feb 2015 21:35:00 -0300 Subject: [PATCH] fix airgapped --- README.md | 11 ++++++++--- bit-wallet/bit-import | 1 + bit-wallet/bit-sign | 21 ++++++++++++++++----- bit-wallet/cli-utils.js | 11 ++++++++++- lib/client/api.js | 5 ++++- lib/client/verifier.js | 2 ++ lib/walletutils.js | 4 ---- 7 files changed, 41 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index f692aaf..8821b58 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,10 @@ bit import output.dat ``` -# Airgapped Operation +# Airgapped Operation + + +## WARNING: THIS IS STILL WIP ## Air gapped (non connected) devices are supported. This setup can be useful is maximun security is needed, to prevent private keys to get compromissed. In this setup a device is installed without network access, and transactions are signed off-line. Transactions can be pulled from the server using a `proxy` device, then downloaded to a pendrive to be moved to the air-gapped device, signed there and then moved back the `proxy` device to be send back to the server. Note that Private keys are generated off-line in the airgapped device. @@ -133,10 +136,12 @@ Air gapped (non connected) devices are supported. This setup can be useful is ma # On the Air-gapped device airgapped$ bit genkey -airgapped$ bit export -o wallet.dat --readonly #(or --readwrite if you need the proxy to be able to propose transactions) +airgapped$ bit export -o toProxy --access readwrite #(or --readonly if proxy wont be allowed to propose transactions) # On the proxy machine -proxy$ bit join secret -i wallet.dat +proxy$ bit import toProxy +proxy$ bit join secret # Or bit create +proxy$ bit address # Only if readwrite access was granted proxy$ bit balance # Export pending transaction to be signed offline diff --git a/bit-wallet/bit-import b/bit-wallet/bit-import index 1a2d7df..2105a1f 100755 --- a/bit-wallet/bit-import +++ b/bit-wallet/bit-import @@ -9,6 +9,7 @@ program = utils.configureCommander(program); program .version('0.0.1') + .option('-n, --nopasswd [level]', 'Set access for no password usage: none(default), readonly, readwrite, full', 'none') .usage('import [options] ') .parse(process.argv); diff --git a/bit-wallet/bit-sign b/bit-wallet/bit-sign index 34988c7..9faad47 100755 --- a/bit-wallet/bit-sign +++ b/bit-wallet/bit-sign @@ -16,11 +16,8 @@ var args = program.args; var txpid = args[0] || ''; var client = utils.getClient(program); -client.getTxProposals({}, function(err, txps) { - utils.die(err); - - var txp = utils.findOneTxProposal(txps, txpid); +function end(txp) { if (program.output) { client.getSignatures(txp, function(err, signatures) { utils.die(err); @@ -34,6 +31,7 @@ client.getTxProposals({}, function(err, txps) { } else { if (program.input) { + var infile = JSON.parse(fs.readFileSync(program.input)); if (infile.id != txp.id) utils.die('Signatures does not match Transaction') @@ -49,4 +47,17 @@ client.getTxProposals({}, function(err, txps) { console.log('Transaction signed by you.'); }); } -}); + +}; + +if (program.input && program.output) { + var inFile = JSON.parse(fs.readFileSync(program.input)); + end(inFile.txps[0]); +} else { + client.getTxProposals({}, function(err, txps) { + utils.die(err); + var txp = utils.findOneTxProposal(txps, txpid); + utils.die(err); + end(txp); + }); +} diff --git a/bit-wallet/cli-utils.js b/bit-wallet/cli-utils.js index 91dc89f..f6c65e8 100644 --- a/bit-wallet/cli-utils.js +++ b/bit-wallet/cli-utils.js @@ -6,7 +6,11 @@ var Utils = function() {}; var die = Utils.die = function(err) { if (err) { - console.error(err); + if (err.code && err.code == 'ECONNREFUSED') { + console.error('Could not connect to Bicore Wallet Service'); + } else { + console.error(err); + } process.exit(1); } }; @@ -49,14 +53,19 @@ Utils.getClient = function(args) { if (args.nopasswd) c.setNopasswdAccess(args.nopasswd); + var setPassword; c.on('needPassword', function(cb) { if (args.password) { return cb(args.password); } else { + if (setPassword) + return cb(setPassword); + read({ prompt: 'Password for ' + args.file + ' : ', silent: true }, function(er, password) { + setPassword = password; return cb(password); }) } diff --git a/lib/client/api.js b/lib/client/api.js index 2dfc0f7..2abb69c 100644 --- a/lib/client/api.js +++ b/lib/client/api.js @@ -234,6 +234,7 @@ API.prototype.setNopasswdAccess = function(noPasswdAccess) { API.prototype._processWcdBeforeWrite = function(wcd, cb) { var self = this; + // Is any encrypted? if (this.noPasswdAccess == 'full') { return cb(null, wcd); @@ -257,6 +258,7 @@ API.prototype._load = function(opts, cb) { if (err && err.code == 'ENOENT') err = 'NOTFOUND'; return cb(err || 'NOTFOUND'); } + self._processWcdAfterRead(rawdata, opts.requiredAccess, cb); }); }; @@ -618,7 +620,7 @@ API.prototype.export = function(opts, cb) { if (err) return cb(err); var v = []; - var myXPubKey = (new Bitcore.HDPublicKey(wcd.xPrivKey)).toString(); + var myXPubKey = wcd.xPrivKey ? (new Bitcore.HDPublicKey(wcd.xPrivKey)).toString() : ''; _.each(WALLET_CRITICAL_DATA, function(k) { var d; @@ -679,6 +681,7 @@ API.prototype.import = function(str, cb) { return cb('Invalid source wallet'); wcd.network = wcd.publicKeyRing[0].substr(0, 4) == 'tpub' ? 'testnet' : 'livenet'; + self.save(wcd, function(err) { return cb(err, WalletUtils.accessFromData(wcd)); }); diff --git a/lib/client/verifier.js b/lib/client/verifier.js index f1a4897..e720074 100644 --- a/lib/client/verifier.js +++ b/lib/client/verifier.js @@ -66,6 +66,8 @@ Verifier.checkTxProposal = function(data, txp) { var hash = WalletUtils.getProposalHash(txp.toAddress, txp.amount, txp.encryptedMessage || txp.message); log.debug('Regenerating & verifying tx proposal hash -> Hash: ', hash, ' Signature: ', txp.proposalSignature); + + if (!WalletUtils.verifyMessage(hash, txp.proposalSignature, creatorSigningPubKey)) return false; diff --git a/lib/walletutils.js b/lib/walletutils.js index 88de849..70a983e 100644 --- a/lib/walletutils.js +++ b/lib/walletutils.js @@ -185,10 +185,6 @@ WalletUtils.encryptWallet = function(data, accessWithoutEncrytion, password) { var fieldsEncrypt = fieldsEncryptByLevel[accessWithoutEncrytion]; $.checkState(!_.isUndefined(fieldsEncrypt)); - if (!_.every(fieldsEncrypt, function(k) { - return data[k]; - })) throw new Error('Wallet does not contain necesary info to encrypt'); - var toEncrypt = _.pick(data, fieldsEncrypt); var enc = sjcl.encrypt(password, JSON.stringify(toEncrypt), WalletUtils.sjclOpts);