fix conflicts

This commit is contained in:
Mario Colque 2014-04-20 17:18:20 -03:00
commit 74f7271310
28 changed files with 653 additions and 761 deletions

10
.gitignore vendored
View File

@ -28,15 +28,6 @@ npm-debug.log
.DS_Store .DS_Store
public/lib/* public/lib/*
db/txs/*
db/txs
db/testnet/txs/*
db/testnet/txs
db/blocks/*
db/blocks
db/testnet/blocks/*
db/testnet/blocks
public/js/angularjs-all.js public/js/angularjs-all.js
public/js/main.js public/js/main.js
public/js/vendors.js public/js/vendors.js
@ -49,3 +40,4 @@ lib/*
!lib/socket.io.js !lib/socket.io.js
js/copayBundle.js js/copayBundle.js
js/config.js

View File

@ -58,7 +58,6 @@ body {
.header { .header {
background: #111; background: #111;
color: white; color: white;
overflow: hidden;
margin-bottom: 30px; margin-bottom: 30px;
} }
@ -71,6 +70,10 @@ body {
color: #fff; color: #fff;
} }
.top-bar {
height: auto;
}
.panel { .panel {
color: #333; color: #333;
background: #FFFFFF; background: #FFFFFF;
@ -164,7 +167,7 @@ span.panel-res {
color: #FBE500; color: #FBE500;
} }
.alert-box.warning { .alert-box.warning, .alert-box.error {
background-color: #C0392A; background-color: #C0392A;
border-color: #C0392A; border-color: #C0392A;
color: #fff; color: #fff;
@ -174,6 +177,14 @@ span.panel-res {
color:#C0392A; color:#C0392A;
} }
small.is-valid {
color: #04B404;
}
small.has-error {
color: #f04124;
}
hr { margin: 2.25rem 0;} hr { margin: 2.25rem 0;}
button.primary { background-color: #111; } button.primary { background-color: #111; }
@ -203,4 +214,4 @@ button.secondary:hover { background-color: #FFDF00 !important;}
.p20h {padding: 0 20px;} .p20h {padding: 0 20px;}
.m30v {margin: 30px 0;} .m30v {margin: 30px 0;}
.m30a {margin: 30px auto;} .m30a {margin: 30px auto;}
.br100 {border-radius: 100%;} .br100 {border-radius: 100%;}

View File

@ -45,11 +45,14 @@
</div> </div>
<div ng-if='$root.flashMessage.message' class="panel callout radius" style="color:red" > <div class="row" ng-if='$root.flashMessage.message'>
{{$root.flashMessage.type}}: <div class="small-8 large-centered columns">
{{$root.flashMessage.message}} <div data-alert class="alert-box round {{$root.flashMessage.type}}">
<a ng-click="clearFlashMessage()" class="button tiny">Dismiss</a> {{$root.flashMessage.message}}
<a ng-click="clearFlashMessage()" class="close">&times;</a>
</div>
</div> </div>
</div>
<div class="row"> <div class="row">
<div ng-if='$root.wallet && !$root.wallet.publicKeyRing.isComplete() && !loading' data-alert class="alert-box warning round" > <div ng-if='$root.wallet && !$root.wallet.publicKeyRing.isComplete() && !loading' data-alert class="alert-box warning round" >
@ -61,14 +64,14 @@
<span ng-show="$root.wallet.publicKeyRing.totalCopayers - $root.wallet.publicKeyRing.registeredCopayers()==1"> <span ng-show="$root.wallet.publicKeyRing.totalCopayers - $root.wallet.publicKeyRing.registeredCopayers()==1">
One key is One key is
</span> </span>
missing. Ask your copayers to join your session: <b>{{$root.wallet.network.peerId}}</b> missing. Share this secret with your other copayers for them to join your wallet: <b>{{$root.wallet.getMyPeerId()}}</b>
</div> </div>
</div> </div>
</div> </div>
<div class="row m30a"> <div class="row">
<div class="large-12 columns" ng-view></div> <div class="large-12 columns" ng-view></div>
</div> </div>
@ -81,8 +84,9 @@
<div ng-show="!loading"> <div ng-show="!loading">
<div class="row"> <div class="row">
<div class="large-6 columns"> <div class="large-6 columns">
<h3>Join a Network Wallet</h3> <h3>Join Wallet Creation</h3>
<input type="text" class="form-control" placeholder="Peer ID" ng-model="connectionId" autofocus> <input type="text" class="form-control" placeholder="Paste secret here"
ng-model="connectionId" autofocus>
</div> </div>
<div class="large-3 columns"> <div class="large-3 columns">
<button class="button primary expand round" type="button" ng-click="join(connectionId)">Join</button> <button class="button primary expand round" type="button" ng-click="join(connectionId)">Join</button>
@ -109,7 +113,7 @@
<div ng-show="walletIds.length>0"> <div ng-show="walletIds.length>0">
<div class="row"> <div class="row">
<div class="large-6 columns"> <div class="large-6 columns">
<h3>Open a Existing Wallet</h3> <h3>Open Existing Wallet</h3>
<select class="form-control" ng-model="selectedWalletId" ng-options="walletId for walletId in walletIds"> <select class="form-control" ng-model="selectedWalletId" ng-options="walletId for walletId in walletIds">
</select> </select>
</div> </div>
@ -234,20 +238,27 @@
<div class="row" ng-show='$root.wallet.publicKeyRing.isComplete()'> <div class="row" ng-show='$root.wallet.publicKeyRing.isComplete()'>
<div class="large-12 columns"> <div class="large-12 columns">
<h3>Pending Transactions <small>({{txs.length}})</small></h3> <h3>Pending Transactions <small>({{txs.length}})</small></h3>
<div class="panel pending" ng-repeat="txp in txs"> <div class="panel pending" ng-repeat="tx in txs">
<div class="row" ng-repeat="o in txs.outs"> NTXID: {{tx.ntxid}}
<p class="large-5 columns"> {{o.address}}</p> CREATOR: {{tx.creator}}
<i class="large-2 columns fi-arrow-right size-16 text-center"></i> CREATED_TS: {{tx.createdTs}}
<div class="row" ng-repeat="o in tx.outs">
<p class="large-5 columns"> {{o.value}} BTC </p> <p class="large-5 columns"> {{o.value}} BTC </p>
<i class="large-2 columns fi-arrow-right size-16 text-center"></i>
<p class="large-5 columns"> {{o.address}}</p>
</div> </div>
<div class="large-12 columns m0 panel panel-sign" ng-show="txp.signedByUs"> <div class="large-12 columns m0 panel panel-sign" ng-show="tx.signedByUs">
<i class="fi-check size-40"></i> YOU SIGNED! <i class="fi-check size-40"></i> Signed by you already
</div> </div>
<div class="large-12 columns m0" ng-show="!txp.signedByUs"> <div class="large-12 columns m0" ng-show="!tx.signedByUs">
<div class="line"></div> <div class="line"></div>
<button class="primary round large-4 columns"><i class="large-2 columns fi-x size-16 text-center"></i> Ignore</button> <button class="primary round large-4 columns"><i class="large-2 columns fi-x size-16 text-center"></i> Ignore</button>
<small class="large-4 columns text-center">Faltan 3 cosigners</small> <small class="large-4 columns text-center">
<button class="secondary round large-4 columns" ng-click="sign(txp.ntxid)"><i class="large-2 columns fi-check size-16 text-center"></i> Sign</button> <span ng-show="tx.missingSignatures==1"> One signature </span>
<span ng-show="tx.missingSignatures>1"> {{tx.missingSignatures}} signatures </span>
missing
</small>
<button class="secondary round large-4 columns" ng-click="sign(tx.ntxid)"><i class="large-2 columns fi-check size-16 text-center"></i> Sign</button>
</div> </div>
</div> <!-- end of row --> </div> <!-- end of row -->
</div> <!-- end of pending --> </div> <!-- end of pending -->
@ -295,21 +306,51 @@
<script type="text/ng-template" id="send.html"> <script type="text/ng-template" id="send.html">
<div class="send" data-ng-controller="SendController"> <div class="send" data-ng-controller="SendController">
<div class="row" ng-show='$root.wallet.publicKeyRing.isComplete()'> <div class="row" ng-show='$root.wallet.publicKeyRing.isComplete()'>
<div class="large-8 columns"> <div class="small-6 large-centered columns">
<form> <h1>{{title}}</h1>
<label for="address">To <form name="sendForm" ng-submit="submitForm(sendForm)" novalidate>
<input type="text" id="address" placeholder="Send to"> <div class="row">
</label> <div class="large-12 columns">
<label for="amount">Amount <label for="address">To address
<input type="text" id="amount" placeholder="Amount"> <small ng-hide="!sendForm.address.$pristine">required</small>
<select class="form-control"> <small class="is-valid" ng-show="!sendForm.address.$invalid && !sendForm.address.$pristine">is valid!</small>
<option>mBTC</option> <small class="has-error" ng-show="sendForm.address.$invalid && !sendForm.address.$pristine">
<option>BTC</option> is not valid</small>
</select> </label>
</label> <input type="text" id="address" name="address" placeholder="Send to" ng-model="address" ng-minlength="20" ng-maxlength="37" required>
<button class="button primary round" type="button" ng-click="sendTest()">sendTest</button> </div>
<button type="submit" class="button secondary round right">send</button> </div>
<div class="row">
<div class="large-6 columns">
<div class="row collapse">
<label for="amount">Amount
<small ng-hide="!sendForm.amount.$pristine">required</small>
<small class="is-valid" ng-show="!sendForm.amount.$invalid && !sendForm.amount.$pristine">is valid!</small>
<small class="has-error" ng-show="sendForm.amount.$invalid && !sendForm.amount.$pristine">
is not valid</small>
</label>
<div class="small-9 columns">
<input type="number" id="amount" name="amount" placeholder="Amount" ng-model="amount" min="0.0001" max="10000000" required>
</div>
<div class="small-3 columns">
<span class="postfix">BTC</span>
</div>
</div>
</div>
</div>
<div class="row">
<div class="large-4 columns">
<button type="submit" class="button secondary round text-center" ng-disabled="sendForm.$invalid">
Send
</button>
</div>
</div>
</form> </form>
<hr>
<div class="text-center">
<a ng-click="sendTest()">sendTest</a>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -3,12 +3,12 @@
var config = { var config = {
networkName: 'testnet', networkName: 'testnet',
network: { network: {
key: 'lwjd5qra8257b9', // key: 'lwjd5qra8257b9',
// This is for running local peerJs with params: ./peerjs -p 10009 -k 'sdfjhwefh' // This is for running local peerJs with params: ./peerjs -p 10009 -k 'sdfjhwefh'
// key: 'sdfjhwefh', key: 'sdfjhwefh',
// host: 'localhost', host: 'localhost',
// port: 10009, port: 10009,
// path: '/', path: '/',
maxPeers: 3, maxPeers: 3,
debug: 3, debug: 3,
}, },

View File

@ -10,11 +10,12 @@ angular.module('copay.home').controller('HomeController',
var _updateBalance = function () { var _updateBalance = function () {
w.getBalance(function (balance, balanceByAddr) { w.getBalance(function (balance, balanceByAddr) {
$rootScope.$apply(function() { if (balanceByAddr && Object.keys(balanceByAddr).length) {
$rootScope.balanceByAddr = balanceByAddr; $scope.balanceByAddr = balanceByAddr;
$scope.addrs = Object.keys(balanceByAddr); $scope.addrs = Object.keys(balanceByAddr);
$scope.selectedAddr = $scope.addrs[0]; $scope.selectedAddr = $scope.addrs[0];
}); $scope.$digest();
}
}); });
}; };
@ -30,4 +31,5 @@ angular.module('copay.home').controller('HomeController',
}; };
_updateBalance(); _updateBalance();
w.on('refresh',_updateBalance);
}); });

View File

@ -4,8 +4,35 @@ angular.module('copay.send').controller('SendController',
function($scope, $rootScope, $location) { function($scope, $rootScope, $location) {
$scope.title = 'Send'; $scope.title = 'Send';
$scope.unitIds = ['BTC','mBTC'];
$scope.selectedUnit = $scope.unitIds[0];
$scope.submitForm = function(form) {
if (form.$invalid) {
$rootScope.flashMessage = { message: 'You can not send a proposal transaction. Please, try again', type: 'error'};
return;
}
var address = form.address.$modelValue;
var amount = (form.amount.$modelValue * 100000000).toString(); // satoshi to string
var w = $rootScope.wallet;
w.createTx( address, amount,function() {
$rootScope.$digest();
});
// reset fields
$scope.address = null;
$scope.amount = null;
form.address.$pristine = true;
form.amount.$pristine = true;
// TODO: check if createTx has an error.
$rootScope.flashMessage = { message: 'You send a proposal transaction succefully', type: 'success'};
};
$scope.sendTest = function() { $scope.sendTest = function() {
var w = $rootScope.wallet; var w = $rootScope.wallet;
w.createTx( 'mimoZNLcP2rrMRgdeX5PSnR7AjCqQveZZ4', '12345',function() { w.createTx( 'mimoZNLcP2rrMRgdeX5PSnR7AjCqQveZZ4', '12345',function() {
$rootScope.$digest(); $rootScope.$digest();
}); });

View File

@ -34,7 +34,6 @@ angular.module('copay.setup').controller('SetupController',
}; };
var w = walletFactory.create(opts); var w = walletFactory.create(opts);
controllerUtils.setupUxHandlers(w); controllerUtils.setupUxHandlers(w);
w.netStart();
}; };
}); });

View File

@ -10,23 +10,26 @@ angular.module('copay.signin').controller('SigninController',
$location.path('setup'); $location.path('setup');
}; };
$scope.open = function(walletId) { $scope.open = function(walletId, opts) {
$scope.loading = true; $scope.loading = true;
var w = walletFactory.open(walletId); console.log('[signin.js.23:walletId:]',walletId); //TODO
var w = walletFactory.open(walletId, opts);
controllerUtils.setupUxHandlers(w); controllerUtils.setupUxHandlers(w);
w.netStart(); w.netStart();
}; };
$scope.join = function(peerId) { $scope.join = function(secret) {
$scope.loading = true; $scope.loading = true;
walletFactory.network.on('openError', function() {
controllerUtils.onError($scope); walletFactory.network.on('joinError', function() {
$rootScope.$digest(); controllerUtils.onErrorDigest($scope);
}); });
walletFactory.connectTo(peerId, function(w) {
walletFactory.joinCreateSession(secret, function(w) {
console.log('[signin.js.33] joinCreateSession RETURN', w); //TODO
controllerUtils.setupUxHandlers(w); controllerUtils.setupUxHandlers(w);
w.netStart(); w.setupNetHandlers();
}); });
}; };
}); });

View File

@ -1,4 +1,5 @@
'use strict'; 'use strict';
var bitcore = require('bitcore');
angular.module('copay.transactions').controller('TransactionsController', angular.module('copay.transactions').controller('TransactionsController',
function($scope, $rootScope, $location) { function($scope, $rootScope, $location) {
@ -9,7 +10,7 @@ angular.module('copay.transactions').controller('TransactionsController',
var _updateTxs = function() { var _updateTxs = function() {
var w =$rootScope.wallet; var w =$rootScope.wallet;
var inT = w.getTxProposals(); var inT = w.getTxProposals();
var ts = []; var txs = [];
inT.forEach(function(i){ inT.forEach(function(i){
var b = i.txp.builder; var b = i.txp.builder;
@ -18,28 +19,49 @@ angular.module('copay.transactions').controller('TransactionsController',
feeSat: b.feeSat, feeSat: b.feeSat,
}; };
var outs = []; var outs = [];
var bitcore = require('bitcore');
tx.outs.forEach(function(o) { tx.outs.forEach(function(o) {
var s = o.getScript(); var addr = bitcore.Address.fromScriptPubKey(o.getScript(), config.networkName)[0].toString();
var aStr = bitcore.Address.fromScript(s, config.networkName).toString(); if (!w.addressIsOwn(addr)) {
if (!w.addressIsOwn(aStr))
outs.push({ outs.push({
address: aStr, address: addr,
value: bitcore.util.valueToBigInt(o.getValue())/bitcore.util.COIN, value: bitcore.util.valueToBigInt(o.getValue())/bitcore.util.COIN,
}); });
}
}); });
one.outs = outs; one.outs = outs;
ts.push(one);
});
$scope.txs = ts;
};
_updateTxs(); // TOD: check missingSignatures === in al inputs?
one.missingSignatures = tx.countInputMissingSignatures(0);
one.signedByUs = i.signedByUs;
one.ntxid = i.ntxid;
one.creator = i.txp.creator,
one.createdTs = i.txp.createdTs;
txs.push(one);
});
$scope.txs = txs;
};
$scope.sign = function (ntxid) { $scope.sign = function (ntxid) {
var w = $rootScope.wallet; var w = $rootScope.wallet;
var ret = w.sign(ntxid); var ret = w.sign(ntxid);
$rootScope.flashMessage = {type:'success', message: 'Transactions SEND! : ' + ret}; _updateTxs();
var p = w.getTxProposal(ntxid);
if (p.txp.builder.isFullySigned()) {
w.sendTx(ntxid, function(txid) {
$rootScope.flashMessage = txid
? {type:'success', message: 'Transactions SENT! txid:' + txid}
: {type:'error', message: 'There was an error sending the Transaction'}
;
});
}
else {
$rootScope.flashMessage = ret
? {type:'success', message: 'Transactions signed'}
: {type:'error', message: 'There was an error signing the Transaction'}
;
}
_updateTxs(); _updateTxs();
}; };
}); });

View File

@ -102,7 +102,7 @@ Insight.prototype._request = function(options, callback) {
return callback({message: 'Wrong response from insight'}); return callback({message: 'Wrong response from insight'});
} }
} else { } else {
return callback({message: 'Error ' + response.statusCode}); return callback({message: 'Error ' + request.status});
} }
} }
}; };

View File

@ -16,13 +16,17 @@ function PrivateKey(opts) {
var init = opts.extendedPrivateKeyString || this.network.name; var init = opts.extendedPrivateKeyString || this.network.name;
this.bip = opts.BIP32 || new BIP32(init); this.bip = opts.BIP32 || new BIP32(init);
this.privateKeyCache = opts.privateKeyCache || {}; this.privateKeyCache = opts.privateKeyCache || {};
this._calcId();
}; };
PrivateKey.prototype._calcId = function() { PrivateKey.prototype.getId = function(prefix) {
this.id = util.ripe160(this.bip.extendedPublicKey).toString('hex'); var buf = this.bip.extendedPublicKey;
if (prefix) {
buf = Buffer.concat([prefix, buf]);
}
return util.ripe160(buf).toString('hex');
}; };
PrivateKey.fromObj = function(obj) { PrivateKey.fromObj = function(obj) {
return new PrivateKey(obj); return new PrivateKey(obj);
}; };

View File

@ -9,6 +9,7 @@ var Address = bitcore.Address;
var Script = bitcore.Script; var Script = bitcore.Script;
var coinUtil = bitcore.util; var coinUtil = bitcore.util;
var Transaction = bitcore.Transaction; var Transaction = bitcore.Transaction;
var util = bitcore.util;
var Storage = imports.Storage || require('../storage/Base.js'); var Storage = imports.Storage || require('../storage/Base.js');
var storage = Storage.default(); var storage = Storage.default();
@ -76,6 +77,17 @@ PublicKeyRing.prototype.serialize = function () {
return JSON.stringify(this.toObj()); return JSON.stringify(this.toObj());
}; };
PublicKeyRing.prototype.getCopayerId = function(i, prefix) {
var buf = this.copayersBIP32[i].extendedPublicKey;
if (prefix) {
buf = Buffer.concat([prefix, buf]);
}
return util.ripe160(buf).toString('hex');
};
PublicKeyRing.prototype.myCopayerId = function(i, prefix) {
return this.getCopayerId(0,prefix);
};
PublicKeyRing.prototype.registeredCopayers = function () { PublicKeyRing.prototype.registeredCopayers = function () {
return this.copayersBIP32.length; return this.copayersBIP32.length;
@ -225,12 +237,12 @@ PublicKeyRing.prototype._checkInPRK = function(inPKR, ignoreId) {
if ( if (
this.requiredCopayers && inPKR.requiredCopayers && this.requiredCopayers && inPKR.requiredCopayers &&
(this.requiredCopayers !== inPKR.requiredCopayers)) (this.requiredCopayers !== inPKR.requiredCopayers))
throw new Error('inPRK requiredCopayers mismatch'); throw new Error('inPRK requiredCopayers mismatch '+this.requiredCopayers+'!='+inPKR.requiredCopayers);
if ( if (
this.totalCopayers && inPKR.totalCopayers && this.totalCopayers && inPKR.totalCopayers &&
(this.totalCopayers !== inPKR.totalCopayers)) (this.totalCopayers !== inPKR.totalCopayers))
throw new Error('inPRK requiredCopayers mismatch'); throw new Error('inPRK totalCopayers mismatch'+this.totalCopayers+'!='+inPKR.requiredCopayers);
}; };

View File

@ -14,10 +14,27 @@ var Storage = imports.Storage || require('../storage/Base');
var storage = Storage.default(); var storage = Storage.default();
function TxProposal(opts) { function TxProposal(opts) {
this.creator = opts.creator;
this.createdTs = opts.createdTs;
this.seenBy = opts.seenBy || {}; this.seenBy = opts.seenBy || {};
this.signedBy = opts.signedBy || {}; this.signedBy = opts.signedBy || {};
this.builder = opts.builder; this.builder = opts.builder;
}
TxProposal.prototype.toObj = function() {
var o = JSON.parse(JSON.stringify(this));
delete o['builder'];
o.builderObj = this.builder.toObj();
return o;
}; };
TxProposal.fromObj = function(o) {
var t = new TxProposal(o);
var b = new Builder.fromObj(o.builderObj);
t.builder = b;
return t;
};
module.exports = require('soop')(TxProposal); module.exports = require('soop')(TxProposal);
@ -26,7 +43,7 @@ function TxProposals(opts) {
this.walletId = opts.walletId; this.walletId = opts.walletId;
this.network = opts.networkName === 'livenet' ? this.network = opts.networkName === 'livenet' ?
bitcore.networks.livenet : bitcore.networks.testnet; bitcore.networks.livenet : bitcore.networks.testnet;
this.txps = []; this.txps = {};
} }
TxProposals.fromObj = function(o) { TxProposals.fromObj = function(o) {
@ -34,12 +51,10 @@ TxProposals.fromObj = function(o) {
networkName: o.networkName, networkName: o.networkName,
walletId: o.walletId, walletId: o.walletId,
}); });
o.txps.forEach(function(t) { o.txps.forEach(function(o2) {
ret.txps.push({ var t = TxProposal.fromObj(o2);
seenBy: t.seenBy, var id = t.builder.build().getNormalizedHash().toString('hex');
signedBy: t.signedBy, ret.txps[id] = t;
builder: new Builder.fromObj(t.builderObj),
});
}); });
return ret; return ret;
}; };
@ -47,13 +62,10 @@ TxProposals.fromObj = function(o) {
TxProposals.prototype.toObj = function() { TxProposals.prototype.toObj = function() {
var ret = []; var ret = [];
this.txps.forEach(function(t) { for(var id in this.txps){
ret.push({ var t = this.txps[id];
seenBy: t.seenBy, ret.push(t.toObj());
signedBy: t.signedBy, }
builderObj: t.builder.toObj(),
});
});
return { return {
txps: ret, txps: ret,
walletId: this.walletId, walletId: this.walletId,
@ -62,36 +74,27 @@ TxProposals.prototype.toObj = function() {
}; };
TxProposals.prototype._getNormHash = function(txps) {
var ret = {};
txps.forEach(function(txp) {
var hash = txp.builder.build().getNormalizedHash().toString('hex');
ret[hash]=txp;
});
return ret;
};
TxProposals.prototype._startMerge = function(myTxps, theirTxps) { TxProposals.prototype._startMerge = function(myTxps, theirTxps) {
var fromUs=0, fromTheirs=0, merged =0; var fromUs=0, fromTheirs=0, merged =0;
var toMerge = {}, ready=[]; var toMerge = {}, ready={};
Object.keys(theirTxps).forEach(function(hash) { for(var hash in theirTxps){
if (!myTxps[hash]) { if (!myTxps[hash]) {
ready.push(theirTxps[hash]); // only in theirs; ready[hash]=theirTxps[hash]; // only in theirs;
fromTheirs++; fromTheirs++;
} }
else { else {
toMerge[hash]=theirTxps[hash]; // need Merging toMerge[hash]=theirTxps[hash]; // need Merging
merged++; merged++;
} }
}); }
Object.keys(myTxps).forEach(function(hash) { for(var hash in myTxps){
if(!toMerge[hash]) { if(!toMerge[hash]) {
ready.push(myTxps[hash]); // only in myTxps; ready[hash]=myTxps[hash]; // only in myTxps;
fromUs++; fromUs++;
} }
}); }
return { return {
stats: { stats: {
@ -124,42 +127,48 @@ TxProposals.prototype._mergeMetadata = function(myTxps, theirTxps, mergeInfo) {
TxProposals.prototype._mergeBuilder = function(myTxps, theirTxps, mergeInfo) { TxProposals.prototype._mergeBuilder = function(myTxps, theirTxps, mergeInfo) {
var self = this;
var toMerge = mergeInfo.toMerge; var toMerge = mergeInfo.toMerge;
Object.keys(toMerge).forEach(function(hash) { for(var hash in toMerge){
var v0 = myTxps[hash].builder; var v0 = myTxps[hash].builder;
var v1 = toMerge[hash].builder; var v1 = toMerge[hash].builder;
v0.merge(v1); v0.merge(v1);
}); };
}; };
TxProposals.prototype.add = function(data) { TxProposals.prototype.add = function(data) {
this.txps.push( new TxProposal(data) ); var id = data.builder.build().getNormalizedHash().toString('hex');
this.txps[id] = new TxProposal(data);
}; };
TxProposals.prototype.remove = function(ntxid) {
console.log('[TxProposals.js.147] DELETING:', ntxid); //TODO
delete this.txps[ntxid];
};
TxProposals.prototype.merge = function(t) { TxProposals.prototype.merge = function(t) {
if (this.network.name !== t.network.name) if (this.network.name !== t.network.name)
throw new Error('network mismatch in:', t); throw new Error('network mismatch in:', t);
var res = []; var res = [];
var myTxps = this._getNormHash(this.txps); var myTxps = this.txps;
var theirTxps = this._getNormHash(t.txps); var theirTxps = t.txps;
var mergeInfo = this._startMerge(myTxps, theirTxps); var mergeInfo = this._startMerge(myTxps, theirTxps);
this._mergeMetadata(myTxps, theirTxps, mergeInfo); this._mergeMetadata(myTxps, theirTxps, mergeInfo);
this._mergeBuilder(myTxps, theirTxps, mergeInfo); this._mergeBuilder(myTxps, theirTxps, mergeInfo);
Object.keys(mergeInfo.toMerge).forEach(function(hash) { Object.keys(mergeInfo.toMerge).forEach(function(hash) {
mergeInfo.ready.push(myTxps[hash]); mergeInfo.ready[hash] = myTxps[hash];
}); });
this.txps=mergeInfo.ready; this.txps=mergeInfo.ready;
return mergeInfo.stats; return mergeInfo.stats;
}; };
module.exports = require('soop')(TxProposals); module.exports = require('soop')(TxProposals);

View File

@ -48,17 +48,19 @@ Wallet.prototype._handlePublicKeyRing = function(senderId, data, isInbound) {
var shouldSend = false; var shouldSend = false;
var recipients, pkr = this.publicKeyRing; var recipients, pkr = this.publicKeyRing;
var inPKR = copay.PublicKeyRing.fromObj(data.publicKeyRing); var inPKR = copay.PublicKeyRing.fromObj(data.publicKeyRing);
if (pkr.merge(inPKR, true) && !data.isBroadcast) {
var hasChanged = pkr.merge(inPKR, true);
if (hasChanged) {
this.log('### BROADCASTING PKR'); this.log('### BROADCASTING PKR');
recipients = null; recipients = null;
shouldSend = true; shouldSend = true;
} }
else if (isInbound && !data.isBroadcast) { // else if (isInbound && !data.isBroadcast) {
// always replying to connecting peer // // always replying to connecting peer
this.log('### REPLYING PKR TO:', senderId); // this.log('### REPLYING PKR TO:', senderId);
recipients = senderId; // recipients = senderId;
shouldSend = true; // shouldSend = true;
} // }
if (shouldSend) { if (shouldSend) {
this.sendPublicKeyRing(recipients); this.sendPublicKeyRing(recipients);
@ -76,17 +78,18 @@ Wallet.prototype._handleTxProposals = function(senderId, data, isInbound) {
var mergeInfo = this.txProposals.merge(inTxp, true); var mergeInfo = this.txProposals.merge(inTxp, true);
var addSeen = this.addSeenToTxProposals(); var addSeen = this.addSeenToTxProposals();
if ((mergeInfo.merged && !data.isBroadcast) || addSeen) { // if ((mergeInfo.merged && !data.isBroadcast) || addSeen) {
if (mergeInfo.merged || addSeen) {
this.log('### BROADCASTING txProposals. ' ); this.log('### BROADCASTING txProposals. ' );
recipients = null; recipients = null;
shouldSend = true; shouldSend = true;
} }
else if (isInbound && !data.isBroadcast) { // else if (isInbound && !data.isBroadcast) {
// always replying to connecting peer // // always replying to connecting peer
this.log('### REPLYING txProposals TO:', senderId); // this.log('### REPLYING txProposals TO:', senderId);
recipients = senderId; // recipients = senderId;
shouldSend = true; // shouldSend = true;
} // }
if (shouldSend) if (shouldSend)
this.sendTxProposals(recipients); this.sendTxProposals(recipients);
@ -95,7 +98,7 @@ Wallet.prototype._handleTxProposals = function(senderId, data, isInbound) {
}; };
Wallet.prototype._handleData = function(senderId, data, isInbound) { Wallet.prototype._handleData = function(senderId, data, isInbound) {
// TODO check message signature
if (this.id !== data.walletId) { if (this.id !== data.walletId) {
this.emit('badMessage',senderId); this.emit('badMessage',senderId);
this.log('badMessage FROM:', senderId); //TODO this.log('badMessage FROM:', senderId); //TODO
@ -103,6 +106,12 @@ Wallet.prototype._handleData = function(senderId, data, isInbound) {
} }
this.log('[Wallet.js.98]' , data.type); //TODO this.log('[Wallet.js.98]' , data.type); //TODO
switch(data.type) { switch(data.type) {
case 'walletReady':
console.log('[Wallet.js.109] RECV WALLETREADY'); //TODO
this.sendPublicKeyRing(senderId);
this.sendTxProposals(senderId);
break;
case 'publicKeyRing': case 'publicKeyRing':
this._handlePublicKeyRing(senderId, data, isInbound); this._handlePublicKeyRing(senderId, data, isInbound);
break; break;
@ -112,16 +121,15 @@ Wallet.prototype._handleData = function(senderId, data, isInbound) {
} }
}; };
Wallet.prototype._handleNetworkChange = function(newPeer) { Wallet.prototype._handleNetworkChange = function(newPeerId) {
if (newPeer) { if (newPeerId) {
this.log('#### Setting new PEER:', newPeer); this.log('#### Setting new PEER:', newPeerId);
this.sendWalletId(newPeer); this.sendWalletId(newPeerId);
this.sendPublicKeyRing(newPeer);
this.sendTxProposals(newPeer);
} }
this.emit('refresh'); this.emit('refresh');
}; };
Wallet.prototype._optsToObj = function () { Wallet.prototype._optsToObj = function () {
var obj = { var obj = {
id: this.id, id: this.id,
@ -133,7 +141,28 @@ Wallet.prototype._optsToObj = function () {
return obj; return obj;
}; };
Wallet.prototype.getPeerId = function(index) {
// if (typeof index === 'undefined') {
// // return my own peerId
// var gen = this.privateKey.getId(idBuf);
// return gen;
// }
// return peer number 'index' peerId
//
var idBuf;
// TODO idBuf DISABLED FOR NOW
//idBuf = new Buffer(this.id);
return this.publicKeyRing.getCopayerId(index || 0, idBuf);
};
Wallet.prototype.getMyPeerId = function() {
return this.getPeerId(0);
};
Wallet.prototype.netStart = function() { Wallet.prototype.netStart = function() {
console.log('[Wallet.js.159:netStart:]'); //TODO
var self = this; var self = this;
var net = this.network; var net = this.network;
net.removeAllListeners(); net.removeAllListeners();
@ -141,15 +170,27 @@ Wallet.prototype.netStart = function() {
net.on('data', self._handleData.bind(self) ); net.on('data', self._handleData.bind(self) );
net.on('open', function() {}); // TODO net.on('open', function() {}); // TODO
net.on('openError', function() { net.on('openError', function() {
this.log('[Wallet.js.132:openError:] GOT openError'); //TODO self.log('[Wallet.js.132:openError:] GOT openError'); //TODO
self.emit('openError'); self.emit('openError');
}); });
net.on('close', function() { net.on('close', function() {
self.emit('close'); self.emit('close');
}); });
net.start(function(peerId) {
var myPeerId = self.getMyPeerId();
var startOpts = {
peerId: myPeerId
};
net.start(function() {
console.log('[Wallet.js.177] NET START: emit CREATED'); //TODO
self.emit('created'); self.emit('created');
}); for (var i=0; i<self.publicKeyRing.registeredCopayers(); i++) {
var otherPeerId = self.getPeerId(i);
if (otherPeerId !== myPeerId) {
net.connectTo(otherPeerId);
}
}
}, startOpts);
}; };
Wallet.prototype.store = function(isSync) { Wallet.prototype.store = function(isSync) {
@ -200,6 +241,15 @@ Wallet.prototype.sendTxProposals = function(recipients) {
this.emit('txProposalsUpdated', this.txProposals); this.emit('txProposalsUpdated', this.txProposals);
}; };
Wallet.prototype.sendWalletReady = function(recipients) {
this.log('### SENDING WalletReady TO:', recipients);
this.network.send( recipients, {
type: 'walletReady',
walletId: this.id,
});
this.emit('walletReady');
};
Wallet.prototype.sendWalletId = function(recipients) { Wallet.prototype.sendWalletId = function(recipients) {
this.log('### SENDING walletId TO:', recipients||'All', this.walletId); this.log('### SENDING walletId TO:', recipients||'All', this.walletId);
@ -207,6 +257,7 @@ Wallet.prototype.sendWalletId = function(recipients) {
this.network.send(recipients, { this.network.send(recipients, {
type: 'walletId', type: 'walletId',
walletId: this.id, walletId: this.id,
opts: this._optsToObj()
}); });
}; };
@ -230,75 +281,82 @@ Wallet.prototype.generateAddress = function() {
return addr; return addr;
}; };
// TODO : sort by time... / signed.
Wallet.prototype.getTxProposals = function() { Wallet.prototype.getTxProposals = function() {
var ret = []; var ret = [];
var self= this; for(var k in this.txProposals.txps) {
self.txProposals.txps.forEach(function(txp) { var txp = this.txProposals.txps[k];
var i = {txp:txp}; var i = {txp:txp};
i.ntxid = txp.builder.build().getNormalizedHash(); i.ntxid = k;
i.signedByUs = txp.signedBy[self.privateKey.id]?true:false; i.signedByUs = txp.signedBy[this.privateKey.getId()]?true:false;
ret.push(i); ret.push(i);
});
return ret;
};
// TODO: this can be precalculated.
Wallet.prototype._findTxByNtxid = function(ntxid) {
var ret;
var l = this.txProposals.txps.length;
var id = ntxid.toString('hex');
for(var i=0; i<l; i++) {
var txp = this.txProposals.txps[i];
var id2 = txp.builder.build().getNormalizedHash().toString('hex');
if (id === id2 ) {
ret = txp;
}
} }
return ret; return ret;
}; };
Wallet.prototype.getTxProposal = function(ntxid) {
var txp = this.txProposals.txps[ntxid];
var i = {txp:txp};
i.ntxid = ntxid;
i.signedByUs = txp.signedBy[this.privateKey.getId()]?true:false;
return i;
};
Wallet.prototype.sign = function(ntxid) { Wallet.prototype.sign = function(ntxid) {
var txp = this._findTxByNtxid(ntxid); var self = this;
var txp = self.txProposals.txps[ntxid];
if (!txp) return; if (!txp) return;
var pkr = this.publicKeyRing; var pkr = self.publicKeyRing;
var keys = this.privateKey.getAll(pkr.addressIndex, pkr.changeAddressIndex); var keys = self.privateKey.getAll(pkr.addressIndex, pkr.changeAddressIndex);
var ret = txp.builder.sign(keys);
if (ret.signaturesAdded) { var b = txp.builder;
txp.signedBy[this.privateKey.id] = Date.now(); var before = b.signaturesAdded;
this.log('[Wallet.js.230:ret:]',ret); //TODO b.sign(keys);
if (ret.isFullySigned) {
this.log('[Wallet.js.231] BROADCASTING TX!!!'); //TODO var ret = false;
var tx = txp.builder.build(); if (b.signaturesAdded > before) {
var txHex = tx.serialize().toString('hex'); txp.signedBy[self.privateKey.getId()] = Date.now();
this.blockchain.sendRawTransaction(txHex, function(txid) { this.sendTxProposals();
this.log('[Wallet.js.235:txid:]',txid); //TODO this.store(true);
if (txid) { ret = true;
this.store(true);
}
});
}
else {
this.sendTxProposals();
this.store(true);
}
} }
return ret; return ret;
}; };
Wallet.prototype.sendTx = function(ntxid) {
var txp = this.txProposals.txps[ntxid];
if (!txp) return;
var tx = txp.builder.build();
if (!tx.isComplete()) return;
this.log('[Wallet.js.231] BROADCASTING TX!!!'); //TODO
var txHex = tx.serialize().toString('hex');
this.log('[Wallet.js.261:txHex:]',txHex); //TODO
var self = this;
this.blockchain.sendRawTransaction(txHex, function(txid) {
self.log('BITCOND txid:',txid); //TODO
if (txid) {
self.txProposals.remove(ntxid);
self.store(true);
}
return (txid);
});
};
Wallet.prototype.addSeenToTxProposals = function() { Wallet.prototype.addSeenToTxProposals = function() {
var ret=false; var ret=false;
var self=this; var self=this;
this.txProposals.txps.forEach(function(txp) { for(var k in this.txProposals.txps) {
if (!txp.seenBy[self.privateKey.id]) { var txp = this.txProposals.txps[k];
txp.seenBy[self.privateKey.id] = Date.now(); if (!txp.seenBy[self.privateKey.getId()]) {
txp.seenBy[self.privateKey.getId()] = Date.now();
ret = true; ret = true;
} }
}); }
return ret; return ret;
}; };
@ -333,9 +391,12 @@ Wallet.prototype.getBalance = function(cb) {
var balance = 0; var balance = 0;
var balanceByAddr = {}; var balanceByAddr = {};
var COIN = bitcore.util.COIN; var COIN = bitcore.util.COIN;
var addresses = this.getAddressesStr(true);
if (!addresses.length) return cb(0,[]);
// Prefill balanceByAddr with main address // Prefill balanceByAddr with main address
this.getAddressesStr(true).forEach(function(a){ addresses.forEach(function(a){
balanceByAddr[a]=0; balanceByAddr[a]=0;
}); });
this.getUnspent(function(utxos) { this.getUnspent(function(utxos) {
@ -345,9 +406,9 @@ Wallet.prototype.getBalance = function(cb) {
balance = balance + amt; balance = balance + amt;
balanceByAddr[u.address] = (balanceByAddr[u.address]||0) + amt; balanceByAddr[u.address] = (balanceByAddr[u.address]||0) + amt;
} }
Object.keys(balanceByAddr).forEach(function(a) { for(var a in balanceByAddr){
balanceByAddr[a] = balanceByAddr[a]/COIN; balanceByAddr[a] = balanceByAddr[a]/COIN;
}); };
return cb(balance / COIN, balanceByAddr); return cb(balance / COIN, balanceByAddr);
}); });
}; };
@ -369,14 +430,10 @@ Wallet.prototype.createTx = function(toAddress, amountSatStr, opts, cb) {
if (typeof opts.spendUnconfirmed === 'undefined') { if (typeof opts.spendUnconfirmed === 'undefined') {
opts.spendUnconfirmed = this.spendUnconfirmed; opts.spendUnconfirmed = this.spendUnconfirmed;
} }
if (!opts.remainderOut) {
opts.remainderOut={ address: this.publicKeyRing.generateAddress(true).toString()};
}
self.getUnspent(function(unspentList) { self.getUnspent(function(unspentList) {
// TODO check enough funds, etc. // TODO check enough funds, etc.
self.createTxSync(toAddress, amountSatStr, unspentList, opts); self.createTxSync(toAddress, amountSatStr, unspentList, opts);
self.sendPublicKeyRing(); // Change Address
self.sendTxProposals(); self.sendTxProposals();
self.store(); self.store();
return cb(); return cb();
@ -409,11 +466,13 @@ Wallet.prototype.createTxSync = function(toAddress, amountSatStr, utxos, opts) {
b.sign( priv.getAll(pkr.addressIndex, pkr.changeAddressIndex) ); b.sign( priv.getAll(pkr.addressIndex, pkr.changeAddressIndex) );
} }
var me = {}; var me = {};
if (priv) me[priv.id] = Date.now(); if (priv) me[priv.getId()] = Date.now();
this.txProposals.add({ this.txProposals.add({
signedBy: priv && b.signaturesAdded ? me : {}, signedBy: priv && b.signaturesAdded ? me : {},
seenBy: priv ? me : {}, seenBy: priv ? me : {},
creator: priv.getId(),
createdTs: Date.now(),
builder: b, builder: b,
}); });
}; };

View File

@ -39,10 +39,13 @@ WalletFactory.prototype.log = function(){
WalletFactory.prototype._checkRead = function(walletId) { WalletFactory.prototype._checkRead = function(walletId) {
var s = this.storage; var s = this.storage;
var ret = s.get(walletId, 'publicKeyRing') && var ret =
s.get(walletId, 'txProposals') && (
s.get(walletId, 'opts') && s.get(walletId, 'publicKeyRing') &&
s.get(walletId, 'privateKey') s.get(walletId, 'txProposals') &&
s.get(walletId, 'opts') &&
s.get(walletId, 'privateKey')
)?true:false;
; ;
return ret?true:false; return ret?true:false;
}; };
@ -53,17 +56,14 @@ WalletFactory.prototype.read = function(walletId) {
var s = this.storage; var s = this.storage;
var opts = s.get(walletId, 'opts'); var opts = s.get(walletId, 'opts');
opts.id = walletId; opts.id = walletId;
opts.publicKeyRing = new PublicKeyRing.fromObj(s.get(walletId, 'publicKeyRing')); opts.publicKeyRing = new PublicKeyRing.fromObj(s.get(walletId, 'publicKeyRing'));
opts.txProposals = new TxProposals.fromObj(s.get(walletId, 'txProposals')); opts.txProposals = new TxProposals.fromObj(s.get(walletId, 'txProposals'));
opts.privateKey = new PrivateKey.fromObj(s.get(walletId, 'privateKey')); opts.privateKey = new PrivateKey.fromObj(s.get(walletId, 'privateKey'));
opts.storage = this.storage; opts.storage = this.storage;
opts.network = this.network; opts.network = this.network;
opts.blockchain = this.blockchain; opts.blockchain = this.blockchain;
opts.verbose = this.verbose; opts.verbose = this.verbose;
var w = new Wallet(opts); var w = new Wallet(opts);
// JIC: Add our key // JIC: Add our key
@ -81,10 +81,13 @@ WalletFactory.prototype.read = function(walletId) {
WalletFactory.prototype.create = function(opts) { WalletFactory.prototype.create = function(opts) {
var s = WalletFactory.storage; var s = WalletFactory.storage;
opts = opts || {}; opts = opts || {};
this.log('### CREATING NEW WALLET.' + (opts.id ? ' USING ID: ' + opts.id : ' NEW ID')); this.log('### CREATING NEW WALLET.' +
(opts.id ? ' USING ID: ' + opts.id : ' NEW ID') +
(opts.privateKey ? ' USING PrivateKey: ' + opts.privateKey.getId() : ' NEW PrivateKey')
);
opts.privateKey = opts.privateKey || new PrivateKey({ networkName: this.networkName }); opts.privateKey = opts.privateKey || new PrivateKey({ networkName: this.networkName });
this.log('\t### PrivateKey Initialized');
var requiredCopayers = opts.requiredCopayers || this.walletDefaults.requiredCopayers; var requiredCopayers = opts.requiredCopayers || this.walletDefaults.requiredCopayers;
var totalCopayers = opts.totalCopayers || this.walletDefaults.totalCopayers; var totalCopayers = opts.totalCopayers || this.walletDefaults.totalCopayers;
@ -115,48 +118,12 @@ WalletFactory.prototype.create = function(opts) {
return w; return w;
}; };
WalletFactory.prototype.open = function(walletId) { WalletFactory.prototype.open = function(walletId, opts) {
var w = this.read(walletId) || this.create({ this.log('Opening walletId:' + walletId);
id: walletId, opts = opts || {};
verbose: this.verbose, opts.id = walletId;
}); opts.verbose = this.verbose;
return w; var w = this.read(walletId) || this.create(opts);
};
WalletFactory.prototype.openRemote = function(peedId) {
var s = WalletFactory.storage;
opts = opts || {};
this.log('### CREATING NEW WALLET.' + (opts.id ? ' USING ID: ' + opts.id : ' NEW ID'));
opts.privateKey = opts.privateKey || new PrivateKey({ networkName: this.networkName });
this.log('\t### PrivateKey Initialized');
var requiredCopayers = opts.requiredCopayers || this.walletDefaults.requiredCopayers;
var totalCopayers = opts.totalCopayers || this.walletDefaults.totalCopayers;
opts.publicKeyRing = opts.publicKeyRing || new PublicKeyRing({
networkName: this.networkName,
requiredCopayers: requiredCopayers,
totalCopayers: totalCopayers,
});
opts.publicKeyRing.addCopayer(opts.privateKey.getExtendedPublicKeyString());
this.log('\t### PublicKeyRing Initialized');
opts.txProposals = opts.txProposals || new TxProposals({
networkName: this.networkName,
});
this.log('\t### TxProposals Initialized');
opts.storage = this.storage;
opts.network = this.network;
opts.blockchain = this.blockchain;
opts.spendUnconfirmed = typeof opts.spendUnconfirmed === undefined
?this.walletDefaults.spendUnconfirmed : opts.spendUnconfirmed;
opts.requiredCopayers = requiredCopayers;
opts.totalCopayers = totalCopayers;
var w = new Wallet(opts);
w.store(); w.store();
return w; return w;
}; };
@ -167,16 +134,27 @@ WalletFactory.prototype.getWalletIds = function() {
WalletFactory.prototype.remove = function(walletId) { WalletFactory.prototype.remove = function(walletId) {
// TODO remove wallet contents // TODO remove wallet contents
console.log('TODO: remove wallet contents');
}; };
WalletFactory.prototype.connectTo = function(peerId, cb) { WalletFactory.prototype.joinCreateSession = function(peerId, cb) {
var self=this; var self = this;
//Create our PrivateK
var privateKey = new PrivateKey({ networkName: this.networkName });
this.log('\t### PrivateKey Initialized');
self.network.setPeerId(privateKey.getId());
self.network.start(function() { self.network.start(function() {
self.network.connectTo(peerId) self.network.connectTo(peerId);
self.network.on('walletId', function(walletId) { self.network.on('data', function(sender, data) {
self.log('Opening walletId:' + walletId); if (data.type ==='walletId') {
return cb(self.open(walletId)); data.opts.privateKey = privateKey;
var w = self.open(data.walletId, data.opts);
w.sendWalletReady(peerId);
return cb(w);
}
}); });
}); });
}; };

View File

@ -1,8 +0,0 @@
function Peer(id) {
this.id = id;
};
module.exports = require('soop')(Peer);

View File

@ -21,7 +21,7 @@ function Network(opts) {
this.peerId = opts.peerId; this.peerId = opts.peerId;
this.apiKey = opts.apiKey || 'lwjd5qra8257b9'; this.apiKey = opts.apiKey || 'lwjd5qra8257b9';
this.debug = opts.debug || 3; this.debug = opts.debug || 3;
this.maxPeers = opts.maxPeers || 5; this.maxPeers = opts.maxPeers || 10;
this.opts = { key: opts.key }; this.opts = { key: opts.key };
// For using your own peerJs server // For using your own peerJs server
@ -29,6 +29,7 @@ function Network(opts) {
if (opts[k]) self.opts[k]=opts[k]; if (opts[k]) self.opts[k]=opts[k];
}); });
this.connectedPeers = []; this.connectedPeers = [];
this.started = false;
} }
Network.parent=EventEmitter; Network.parent=EventEmitter;
@ -64,7 +65,6 @@ Network._arrayPushOnce = function(el, array) {
Network._arrayRemove = function(el, array) { Network._arrayRemove = function(el, array) {
var pos = array.indexOf(el); var pos = array.indexOf(el);
if (pos >= 0) array.splice(pos, 1); if (pos >= 0) array.splice(pos, 1);
return array; return array;
}; };
@ -104,9 +104,6 @@ Network.prototype._onData = function(data, isInbound) {
case 'disconnect': case 'disconnect':
this._onClose(obj.sender); this._onClose(obj.sender);
break; break;
case 'walletId':
this.emit('walletId', obj.data.walletId);
break;
default: default:
this.emit('data', obj.sender, obj.data, isInbound); this.emit('data', obj.sender, obj.data, isInbound);
} }
@ -123,8 +120,6 @@ Network.prototype._sendPeers = function(peerIds) {
Network.prototype._addPeer = function(peerId, isInbound) { Network.prototype._addPeer = function(peerId, isInbound) {
var hasChanged = Network._arrayPushOnce(peerId, this.connectedPeers); var hasChanged = Network._arrayPushOnce(peerId, this.connectedPeers);
if (isInbound && hasChanged) { if (isInbound && hasChanged) {
this._sendPeers(); //broadcast peer list this._sendPeers(); //broadcast peer list
} }
@ -184,18 +179,16 @@ Network.prototype._setupPeerHandlers = function(openCallback) {
var self=this; var self=this;
var p = this.peer; var p = this.peer;
p.on('open', function(peerId) { p.on('open', function() {
self.peerId = peerId; self.connectedPeers = [self.peerId];
self.connectedPeers = [peerId];
self._notifyNetworkChange(); console.log('[WebRTC.js.187] LENGTH', self.connectedPeers.length); //TODO
return openCallback(peerId); return openCallback();
}); });
p.on('error', function(err) { p.on('error', function(err) {
console.log('### PEER ERROR:', err); console.log('### PEER ERROR:', err);
self.peer.disconnect(); //self.disconnect(null, true); // force disconnect
self.peer.destroy();
self.peer = null;
self._checkAnyPeer(); self._checkAnyPeer();
}); });
@ -215,12 +208,33 @@ Network.prototype._setupPeerHandlers = function(openCallback) {
}); });
}; };
Network.prototype.start = function(openCallback) { Network.prototype.setPeerId = function(peerId) {
if (this.started) {
throw new Error ('network already started: can not change peerId')
}
this.peerId = peerId;
};
Network.prototype.start = function(openCallback, opts) {
opts = opts || {};
// Start PeerJS Peer // Start PeerJS Peer
if (this.peer) return openCallback(); // This is for connectTo-> peer is started before var self = this;
if (this.started) return openCallback();
opts.connectedPeers = opts.connectedPeers || [];
this.peerId = this.peerId || opts.peerId;
this.peer = new Peer(this.peerId, this.opts); this.peer = new Peer(this.peerId, this.opts);
this._setupPeerHandlers(openCallback); this._setupPeerHandlers(openCallback);
for (var i = 0; i<opts.connectedPeers.length; i++) {
var otherPeerId = opts.connectedPeers[i];
this.connectTo(otherPeerId);
}
this.started = true;
console.log('[WebRTC.js.237] started TRUE'); //TODO
}; };
Network.prototype._sendToOne = function(peerId, data, cb) { Network.prototype._sendToOne = function(peerId, data, cb) {
@ -267,7 +281,7 @@ console.log('[WebRTC.js.258:peerId:]',peerId); //TODO
Network.prototype.connectTo = function(peerId) { Network.prototype.connectTo = function(peerId) {
var self = this; var self = this;
console.log('### STARTING TO CONNECT TO:' + peerId ); console.log('### STARTING CONNECTION TO:' + peerId );
var dataConn = this.peer.connect(peerId, { var dataConn = this.peer.connect(peerId, {
serialization: 'none', serialization: 'none',
@ -279,11 +293,12 @@ Network.prototype.connectTo = function(peerId) {
}; };
Network.prototype.disconnect = function(cb) { Network.prototype.disconnect = function(cb, forced) {
var self = this; var self = this;
self.closing = 1; self.closing = 1;
this.send(null, { type: 'disconnect' }, function() { var cleanUp = function() {
self.connectedPeers = []; self.connectedPeers = [];
self.started = false;
self.peerId = null; self.peerId = null;
if (self.peer) { if (self.peer) {
self.peer.disconnect(); self.peer.disconnect();
@ -292,7 +307,12 @@ Network.prototype.disconnect = function(cb) {
} }
self.closing = 0; self.closing = 0;
if (typeof cb === 'function') cb(); if (typeof cb === 'function') cb();
}); };
if (!forced) {
this.send(null, { type: 'disconnect' }, cleanUp);
} else {
cleanUp();
}
}; };
module.exports = require('soop')(Network); module.exports = require('soop')(Network);

View File

@ -2,7 +2,6 @@
var imports = require('soop').imports(); var imports = require('soop').imports();
var fs = imports.fs || require('fs'); var fs = imports.fs || require('fs');
var parent = imports.parent || require('./Base'); var parent = imports.parent || require('./Base');
var crypto = imports.crypto || require('crypto');
var CryptoJS = require('node-cryptojs-aes').CryptoJS; var CryptoJS = require('node-cryptojs-aes').CryptoJS;
var passwords = []; var passwords = [];
@ -15,8 +14,33 @@ function Storage(opts) {
} }
Storage.parent = parent; Storage.parent = parent;
Storage.prototype._encrypt = function(string) {
var encrypted = CryptoJS.AES.encrypt(string, passwords[0]);
var encryptedBase64 = encrypted.toString();
return encryptedBase64;
};
Storage.prototype._encryptObj = function(obj) {
var string = JSON.stringify(obj);
return this._encrypt(string);
};
Storage.prototype._decrypt = function(base64) {
var decrypted = CryptoJS.AES.decrypt(base64, passwords[0]);
var decryptedStr = decrypted.toString(CryptoJS.enc.Utf8);
return decryptedStr;
};
Storage.prototype._decryptObj = function(base64) {
var decryptedStr = this._decrypt(base64);
return JSON.parse(decryptedStr);
};
Storage.prototype.load = function(walletId, callback) { Storage.prototype.load = function(walletId, callback) {
fs.readFile(walletId, function(err, data) { var self = this;
fs.readFile(walletId, function(err, base64) {
var data = self._decryptObj(base64);
if (err) return callback(err); if (err) return callback(err);
try { try {
@ -32,10 +56,11 @@ Storage.prototype.load = function(walletId, callback) {
}; };
Storage.prototype.save = function(walletId, callback) { Storage.prototype.save = function(walletId, callback) {
var data = JSON.stringify(this.data[walletId]); var obj = this.data[walletId];
var encryptedBase64 = this._encryptObj(obj);
//TODO: update to use a queue to ensure that saves are made sequentially //TODO: update to use a queue to ensure that saves are made sequentially
fs.writeFile(walletId, data, function(err) { fs.writeFile(walletId, encryptedBase64, function(err) {
if (callback) if (callback)
return callback(err); return callback(err);
}); });
@ -105,16 +130,15 @@ Storage.prototype.setFromObj = function(walletId, obj, callback) {
this.save(walletId, callback); this.save(walletId, callback);
}; };
Storage.prototype.setFromEncryptedObj = function(walletId) { Storage.prototype.setFromEncryptedObj = function(walletId, base64, callback) {
//TODO: implement var obj = this._decryptObj(base64);
this.setFromObj(walletId, obj, callback);
}; };
Storage.prototype.getEncryptedObj = function(walletId) { Storage.prototype.getEncryptedObj = function(walletId) {
var data = JSON.stringify(this.data[walletId]); var encryptedBase64 = this._encryptObj(this.data[walletId]);
var encrypted = CryptoJS.AES.encrypt(data, passwords[0]);
var hex = CryptoJS.enc.Hex.stringify(CryptoJS.enc.Base64.parse(encrypted.toString()));
return hex; return encryptedBase64;
}; };
// remove all values // remove all values

View File

@ -25,12 +25,26 @@ Storage.prototype._setPassphrase = function(password) {
pps[this.__uniqueid] = password; pps[this.__uniqueid] = password;
} }
Storage.prototype._encrypt = function(data) { Storage.prototype._encrypt = function(string) {
return CryptoJS.AES.encrypt(data, this._getPassphrase()); var encrypted = CryptoJS.AES.encrypt(string, this._getPassphrase());
var encryptedBase64 = encrypted.toString();
return encryptedBase64;
}; };
Storage.prototype._decrypt = function(encrypted) { Storage.prototype._encryptObj = function(obj) {
return CryptoJS.AES.decrypt(encrypted, this._getPassphrase()); var string = JSON.stringify(obj);
return this._encrypt(string);
};
Storage.prototype._decrypt = function(base64) {
var decrypted = CryptoJS.AES.decrypt(base64, this._getPassphrase());
var decryptedStr = decrypted.toString(CryptoJS.enc.Utf8);
return decryptedStr;
};
Storage.prototype._decryptObj = function(base64) {
var decryptedStr = this._decrypt(base64);
return JSON.parse(decryptedStr);
}; };
Storage.prototype._read = function(k) { Storage.prototype._read = function(k) {
@ -53,6 +67,17 @@ Storage.prototype._write = function(k,v) {
localStorage.setItem(k, v); localStorage.setItem(k, v);
}; };
Storage.prototype.setFromObj = function(walletId, obj) {
for (var i in keys) {
var key = keys[0];
obj[key] = this.get(walletId, key);
}
};
Storage.prototype.setFromEncryptedObj = function(walletId, base64) {
};
Storage.prototype.getEncryptedObj = function(walletId) { Storage.prototype.getEncryptedObj = function(walletId) {
var keys = this._getWalletKeys(); var keys = this._getWalletKeys();
var obj = {}; var obj = {};
@ -62,9 +87,9 @@ Storage.prototype.getEncryptedObj = function(walletId) {
} }
var str = JSON.stringify(obj); var str = JSON.stringify(obj);
var hex = CryptoJS.enc.Hex.stringify(CryptoJS.enc.Base64.parse(this._encrypt(str).toString())); var base64 = this._encrypt(str).toString();
return hex; return base64;
}; };
module.exports = require('soop')(Storage); module.exports = require('soop')(Storage);

View File

@ -27,6 +27,7 @@ angular.module('copay.controllerUtils').factory('controllerUtils', function ($ro
}); });
w.on('created', function() { w.on('created', function() {
console.log('[controllerUtils.js.30:created:] RECV '); //TODO
$location.path('peer'); $location.path('peer');
$rootScope.wallet = w; $rootScope.wallet = w;
@ -41,6 +42,8 @@ angular.module('copay.controllerUtils').factory('controllerUtils', function ($ro
}); });
w.on('openError', root.onErrorDigest); w.on('openError', root.onErrorDigest);
w.on('close', root.onErrorDigest); w.on('close', root.onErrorDigest);
w.netStart();
console.log('[controllerUtils.js.45] setupUxHandlers END'); //TODO
}; };
root.setSocketHandlers = function(cb) { root.setSocketHandlers = function(cb) {

File diff suppressed because one or more lines are too long

1
lib/bitcore.js Symbolic link
View File

@ -0,0 +1 @@
../../bitcore/browser/bundle.js

27
test/mocks/FakeNetwork.js Normal file
View File

@ -0,0 +1,27 @@
var imports = require('soop').imports();
var EventEmitter= imports.EventEmitter || require('events').EventEmitter;
function Network(opts) {
}
Network.parent=EventEmitter;
Network.prototype.start = function(openCallback, opts) {
// start! :D
};
Network.prototype.send = function(peerIds, data, cb) {
// send! c:
};
Network.prototype.connectTo = function(peerId) {
// connect C:
};
Network.prototype.disconnect = function(cb) {
// disconect :c
};
module.exports = require('soop')(Network);

View File

@ -69,16 +69,16 @@ describe('PrivateKey model', function() {
it('should calculate .id', function () { it('should calculate .id', function () {
var w1 = new PrivateKey(config); var w1 = new PrivateKey(config);
should.exist(w1.id); should.exist(w1.getId());
w1.id.length.should.equal(40); w1.getId().length.should.equal(40);
}); });
it('fromObj toObj roundtrip', function () { it('fromObj toObj roundtrip', function () {
var w1 = new PrivateKey(config); var w1 = new PrivateKey(config);
var w2 = PrivateKey.fromObj(w1.toObj()); var o = JSON.parse(JSON.stringify(w1.toObj()))
var w2 = PrivateKey.fromObj(o);
w2.toObj().extendedPrivateKeyString.should.equal(w1.toObj().extendedPrivateKeyString); w2.toObj().extendedPrivateKeyString.should.equal(w1.toObj().extendedPrivateKeyString);
w2.id.should.equal(w1.id); w2.getId().should.equal(w1.getId());
JSON.stringify(w2.get(1,1).storeObj()).should JSON.stringify(w2.get(1,1).storeObj()).should
.equal(JSON.stringify(w1.get(1,1).storeObj())); .equal(JSON.stringify(w1.get(1,1).storeObj()));

View File

@ -125,21 +125,22 @@ describe('TxProposals model', function() {
priv, priv,
pkr pkr
)); ));
var tx = w.txps[0].builder.build(); var k = Object.keys(w.txps)[0];
var tx = w.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(2); tx.countInputMissingSignatures(0).should.equal(2);
(w.txps[0].signedBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].signedBy[priv.id] - ts > 0).should.equal(true);
(w.txps[0].seenBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].seenBy[priv.id] - ts > 0).should.equal(true);
w.merge(w); w.merge(w);
w.txps.length.should.equal(1); Object.keys(w.txps).length.should.equal(1);
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(2); tx.countInputMissingSignatures(0).should.equal(2);
(w.txps[0].signedBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].signedBy[priv.id] - ts > 0).should.equal(true);
(w.txps[0].seenBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].seenBy[priv.id] - ts > 0).should.equal(true);
}); });
@ -168,12 +169,13 @@ describe('TxProposals model', function() {
pkr pkr
)); ));
var tx = w.txps[0].builder.build(); var k = Object.keys(w.txps)[0];
var tx = w.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(1); tx.countInputMissingSignatures(0).should.equal(1);
Object.keys(w.txps[0].signedBy).length.should.equal(0); Object.keys(w.txps[k].signedBy).length.should.equal(0);
Object.keys(w.txps[0].seenBy).length.should.equal(1); Object.keys(w.txps[k].seenBy).length.should.equal(1);
var w2 = new TxProposals({ var w2 = new TxProposals({
@ -191,21 +193,22 @@ describe('TxProposals model', function() {
pkr pkr
)); ));
var tx = w2.txps[0].builder.build(); var k = Object.keys(w.txps)[0];
var tx = w2.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(2); tx.countInputMissingSignatures(0).should.equal(2);
(w2.txps[0].signedBy[priv.id] - ts > 0).should.equal(true); (w2.txps[k].signedBy[priv.id] - ts > 0).should.equal(true);
(w2.txps[0].seenBy[priv.id] - ts > 0).should.equal(true); (w2.txps[k].seenBy[priv.id] - ts > 0).should.equal(true);
w.merge(w2); w.merge(w2);
w.txps.length.should.equal(1); Object.keys(w.txps).length.should.equal(1);
var tx = w.txps[0].builder.build(); var tx = w.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(2); tx.countInputMissingSignatures(0).should.equal(2);
(w.txps[0].signedBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].signedBy[priv.id] - ts > 0).should.equal(true);
(w.txps[0].seenBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].seenBy[priv.id] - ts > 0).should.equal(true);
}); });
@ -243,12 +246,13 @@ var _dumpChunks = function (scriptSig, label) {
pkr pkr
)); ));
var tx = w.txps[0].builder.build(); var k = Object.keys(w.txps)[0];
var tx = w.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(1); tx.countInputMissingSignatures(0).should.equal(1);
Object.keys(w.txps[0].signedBy).length.should.equal(0); Object.keys(w.txps[k].signedBy).length.should.equal(0);
Object.keys(w.txps[0].seenBy).length.should.equal(1); Object.keys(w.txps[k].seenBy).length.should.equal(1);
var w2 = new TxProposals({ var w2 = new TxProposals({
@ -265,21 +269,22 @@ var _dumpChunks = function (scriptSig, label) {
priv, priv,
pkr pkr
)); ));
tx = w2.txps[0].builder.build(); var k = Object.keys(w2.txps)[0];
tx = w2.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(2); tx.countInputMissingSignatures(0).should.equal(2);
(w2.txps[0].signedBy[priv.id] - ts > 0).should.equal(true); (w2.txps[k].signedBy[priv.id] - ts > 0).should.equal(true);
(w2.txps[0].seenBy[priv.id] - ts > 0).should.equal(true); (w2.txps[k].seenBy[priv.id] - ts > 0).should.equal(true);
w.merge(w2); w.merge(w2);
w.txps.length.should.equal(1); Object.keys(w.txps).length.should.equal(1);
tx = w.txps[0].builder.build(); tx = w.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(2); tx.countInputMissingSignatures(0).should.equal(2);
(w.txps[0].signedBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].signedBy[priv.id] - ts > 0).should.equal(true);
(w.txps[0].seenBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].seenBy[priv.id] - ts > 0).should.equal(true);
var w3 = new TxProposals({ var w3 = new TxProposals({
@ -296,22 +301,22 @@ var _dumpChunks = function (scriptSig, label) {
priv2, priv2,
pkr pkr
)); ));
tx = w3.txps[0].builder.build(); tx = w3.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(2); tx.countInputMissingSignatures(0).should.equal(2);
(w3.txps[0].signedBy[priv2.id] - ts > 0).should.equal(true); (w3.txps[k].signedBy[priv2.id] - ts > 0).should.equal(true);
(w3.txps[0].seenBy[priv2.id] - ts > 0).should.equal(true); (w3.txps[k].seenBy[priv2.id] - ts > 0).should.equal(true);
w.merge(w3); w.merge(w3);
w.txps.length.should.equal(1); Object.keys(w.txps).length.should.equal(1);
(w.txps[0].signedBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].signedBy[priv.id] - ts > 0).should.equal(true);
(w.txps[0].seenBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].seenBy[priv.id] - ts > 0).should.equal(true);
(w.txps[0].signedBy[priv2.id] - ts > 0).should.equal(true); (w.txps[k].signedBy[priv2.id] - ts > 0).should.equal(true);
(w.txps[0].seenBy[priv2.id] - ts > 0).should.equal(true); (w.txps[k].seenBy[priv2.id] - ts > 0).should.equal(true);
tx = w.txps[0].builder.build(); tx = w.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(1); tx.countInputMissingSignatures(0).should.equal(1);
}); });
@ -341,11 +346,12 @@ var _dumpChunks = function (scriptSig, label) {
priv, priv,
pkr pkr
)); ));
var tx = w.txps[0].builder.build(); var k = Object.keys(w.txps)[0];
var tx = w.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(2); tx.countInputMissingSignatures(0).should.equal(2);
(w.txps[0].signedBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].signedBy[priv.id] - ts > 0).should.equal(true);
(w.txps[0].seenBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].seenBy[priv.id] - ts > 0).should.equal(true);
var w2 = new TxProposals({ var w2 = new TxProposals({
@ -361,11 +367,11 @@ var _dumpChunks = function (scriptSig, label) {
priv2, priv2,
pkr pkr
)); ));
var tx = w2.txps[0].builder.build(); var tx = w2.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(2); tx.countInputMissingSignatures(0).should.equal(2);
(w2.txps[0].signedBy[priv2.id] - ts > 0).should.equal(true); (w2.txps[k].signedBy[priv2.id] - ts > 0).should.equal(true);
(w2.txps[0].seenBy[priv2.id] - ts > 0).should.equal(true); (w2.txps[k].seenBy[priv2.id] - ts > 0).should.equal(true);
var w3 = new TxProposals({ var w3 = new TxProposals({
@ -381,34 +387,34 @@ var _dumpChunks = function (scriptSig, label) {
priv3, priv3,
pkr pkr
)); ));
var tx = w3.txps[0].builder.build(); var tx = w3.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(2); tx.countInputMissingSignatures(0).should.equal(2);
(w3.txps[0].signedBy[priv3.id] - ts > 0).should.equal(true); (w3.txps[k].signedBy[priv3.id] - ts > 0).should.equal(true);
(w3.txps[0].seenBy[priv3.id] - ts > 0).should.equal(true); (w3.txps[k].seenBy[priv3.id] - ts > 0).should.equal(true);
w.merge(w2); w.merge(w2);
w.txps.length.should.equal(1); Object.keys(w.txps).length.should.equal(1);
var tx = w.txps[0].builder.build(); var tx = w.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(1); tx.countInputMissingSignatures(0).should.equal(1);
(w.txps[0].seenBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].seenBy[priv.id] - ts > 0).should.equal(true);
(w.txps[0].seenBy[priv2.id] - ts > 0).should.equal(true); (w.txps[k].seenBy[priv2.id] - ts > 0).should.equal(true);
(w.txps[0].signedBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].signedBy[priv.id] - ts > 0).should.equal(true);
(w.txps[0].signedBy[priv2.id] - ts > 0).should.equal(true); (w.txps[k].signedBy[priv2.id] - ts > 0).should.equal(true);
w.merge(w3); w.merge(w3);
var tx = w.txps[0].builder.build(); var tx = w.txps[k].builder.build();
tx.isComplete().should.equal(true); tx.isComplete().should.equal(true);
tx.countInputMissingSignatures(0).should.equal(0); tx.countInputMissingSignatures(0).should.equal(0);
w.txps.length.should.equal(1); Object.keys(w.txps).length.should.equal(1);
(w.txps[0].seenBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].seenBy[priv.id] - ts > 0).should.equal(true);
(w.txps[0].seenBy[priv2.id] - ts > 0).should.equal(true); (w.txps[k].seenBy[priv2.id] - ts > 0).should.equal(true);
(w.txps[0].seenBy[priv3.id] - ts > 0).should.equal(true); (w.txps[k].seenBy[priv3.id] - ts > 0).should.equal(true);
(w.txps[0].signedBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].signedBy[priv.id] - ts > 0).should.equal(true);
(w.txps[0].signedBy[priv2.id] - ts > 0).should.equal(true); (w.txps[k].signedBy[priv2.id] - ts > 0).should.equal(true);
(w.txps[0].signedBy[priv3.id] - ts > 0).should.equal(true); (w.txps[k].signedBy[priv3.id] - ts > 0).should.equal(true);
}); });
@ -435,11 +441,12 @@ var _dumpChunks = function (scriptSig, label) {
priv, priv,
pkr pkr
)); ));
var tx = w.txps[0].builder.build(); var k = Object.keys(w.txps)[0];
var tx = w.txps[k].builder.build();
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(2); tx.countInputMissingSignatures(0).should.equal(2);
(w.txps[0].signedBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].signedBy[priv.id] - ts > 0).should.equal(true);
(w.txps[0].seenBy[priv.id] - ts > 0).should.equal(true); (w.txps[k].seenBy[priv.id] - ts > 0).should.equal(true);
var o = w.toObj(); var o = w.toObj();
should.exist(o); should.exist(o);
@ -451,18 +458,22 @@ var _dumpChunks = function (scriptSig, label) {
should.exist(o.txps[0].builderObj.valueInSat); should.exist(o.txps[0].builderObj.valueInSat);
should.exist(o.txps[0].signedBy[priv.id]); should.exist(o.txps[0].signedBy[priv.id]);
var w2 = TxProposals.fromObj(o); var o2 = JSON.parse(JSON.stringify(o));
var w2 = TxProposals.fromObj(o2);
w2.walletId.should.equal(w.walletId); w2.walletId.should.equal(w.walletId);
var tx2 = w2.txps[0].builder.build(); var tx2 = w2.txps[k].builder.build();
tx2.isComplete().should.equal(false); tx2.isComplete().should.equal(false);
tx2.countInputMissingSignatures(0).should.equal(2); tx2.countInputMissingSignatures(0).should.equal(2);
(w2.txps[0].signedBy[priv.id] - ts > 0).should.equal(true); (w2.txps[k].signedBy[priv.id] - ts > 0).should.equal(true);
(w2.txps[0].seenBy[priv.id] - ts > 0).should.equal(true); (w2.txps[k].seenBy[priv.id] - ts > 0).should.equal(true);
should.exist(w2.txps[0].builder); should.exist(w2.txps[k].builder);
should.exist(w2.txps[0].builder.valueInSat); should.exist(w2.txps[k].builder.valueInSat);
w2.merge(w); w2.merge(w);
Object.keys(w2.txps).length.should.equal(1);
}); });
}); });

View File

@ -126,11 +126,12 @@ describe('Wallet model', function() {
); );
var t = w.txProposals; var t = w.txProposals;
var tx = t.txps[0].builder.build(); var k = Object.keys(t.txps)[0];
var tx = t.txps[k].builder.build();
should.exist(tx); should.exist(tx);
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
Object.keys(t.txps[0].signedBy).length.should.equal(1); Object.keys(t.txps[k].signedBy).length.should.equal(1);
Object.keys(t.txps[0].seenBy).length.should.equal(1); Object.keys(t.txps[k].seenBy).length.should.equal(1);
}); });
it('#addressIsOwn', function () { it('#addressIsOwn', function () {
@ -157,13 +158,14 @@ describe('Wallet model', function() {
unspentTest unspentTest
); );
var t = w.txProposals; var t = w.txProposals;
var tx = t.txps[0].builder.build(); var k = Object.keys(t.txps)[0];
var tx = t.txps[k].builder.build();
should.exist(tx); should.exist(tx);
tx.isComplete().should.equal(false); tx.isComplete().should.equal(false);
tx.countInputMissingSignatures(0).should.equal(2); tx.countInputMissingSignatures(0).should.equal(2);
( t.txps[0].signedBy[w.privateKey.id] - ts > 0).should.equal(true); ( t.txps[k].signedBy[w.privateKey.getId()] - ts > 0).should.equal(true);
( t.txps[0].seenBy[w.privateKey.id] - ts > 0).should.equal(true); ( t.txps[k].seenBy[w.privateKey.getId()] - ts > 0).should.equal(true);
} }
} }
}); });

View File

@ -3,12 +3,12 @@
var chai = chai || require('chai'); var chai = chai || require('chai');
var should = chai.should(); var should = chai.should();
var WebRTC = require('../js/models/network/WebRTC'); var FakeNetwork = require('./mocks/FakeNetwork');
var Insight = require('../js/models/blockchain/Insight'); var Insight = require('../js/models/blockchain/Insight');
var FakeStorage = require('./mocks/FakeStorage'); var FakeStorage = require('./mocks/FakeStorage');
var WalletFactory = typeof copay === 'undefined' ? require('soop').load('../js/models/core/WalletFactory',{ var WalletFactory = typeof copay === 'undefined' ? require('soop').load('../js/models/core/WalletFactory',{
Network: WebRTC, Network: FakeNetwork,
Blockchain: Insight, Blockchain: Insight,
Storage: FakeStorage, Storage: FakeStorage,
}) : copay.WalletFactory; }) : copay.WalletFactory;

View File

@ -17,7 +17,9 @@ describe('Storage/File', function() {
var fs = {} var fs = {}
fs.readFile = function(filename, callback) { fs.readFile = function(filename, callback) {
filename.should.equal('myfilename'); filename.should.equal('myfilename');
callback(); var obj = {"test":"test"};
var encryptedStr = CryptoJS.AES.encrypt(JSON.stringify(obj), "password").toString();
callback(null, encryptedStr);
}; };
var Storage = require('soop').load('../js/models/storage/File.js', {fs: fs}); var Storage = require('soop').load('../js/models/storage/File.js', {fs: fs});
var storage = new Storage({password: 'password'}); var storage = new Storage({password: 'password'});
@ -156,15 +158,16 @@ describe('Storage/File', function() {
var obj = {test:'testval'}; var obj = {test:'testval'};
var data = JSON.stringify(obj); var data = JSON.stringify(obj);
var encrypted = CryptoJS.AES.encrypt(data, 'password'); var encrypted = CryptoJS.AES.encrypt(data, 'password');
var hex = CryptoJS.enc.Hex.stringify(CryptoJS.enc.Base64.parse(encrypted.toString())); var base64 = encrypted.toString();
var storage = new Storage({password: 'password'}); var storage = new Storage({password: 'password'});
storage.data['walletId'] = obj; storage.data['walletId'] = obj;
var enc = storage.getEncryptedObj('walletId'); var enc = storage.getEncryptedObj('walletId');
enc.length.should.equal(96); //enc.length.should.equal(96);
enc.slice(0,10).should.equal(hex.slice(0,10)); enc.length.should.be.greaterThan(10);
enc.slice(0,6).should.equal("53616c"); enc.slice(0,10).should.equal(base64.slice(0,10));
//enc.slice(0,6).should.equal("53616c");
}); });
}); });

View File

@ -53,8 +53,8 @@ if (typeof process === 'undefined' || !process.version) {
storage.set('walletId', 'test', 'testval'); storage.set('walletId', 'test', 'testval');
var obj = {test:'testval'}; var obj = {test:'testval'};
var encrypted = storage.getEncryptedObj('walletId'); var encrypted = storage.getEncryptedObj('walletId');
encrypted.length.should.equal(96); encrypted.length.should.be.greaterThan(10);
encrypted.slice(0,6).should.equal("53616c"); //encrypted.slice(0,6).should.equal("53616c");
}); });
}); });
}); });