commit
2ae7033866
11
README.md
11
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
|
||||
|
|
|
@ -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] <file>')
|
||||
.parse(process.argv);
|
||||
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue