2014-04-16 13:50:10 -07:00
'use strict' ;
2014-07-31 21:09:46 -07:00
var TxProposals = require ( './TxProposals' ) ;
2014-04-16 13:50:10 -07:00
var PublicKeyRing = require ( './PublicKeyRing' ) ;
var PrivateKey = require ( './PrivateKey' ) ;
var Wallet = require ( './Wallet' ) ;
2014-06-15 20:55:23 -07:00
var WebRTC = module . exports . WebRTC = require ( '../network/WebRTC' ) ;
var Insight = module . exports . Insight = require ( '../blockchain/Insight' ) ;
var StorageLocalEncrypted = module . exports . StorageLocalEncrypted = require ( '../storage/LocalEncrypted' ) ;
2014-04-16 13:50:10 -07:00
/ *
* WalletFactory
*
* /
2014-05-14 17:02:01 -07:00
function WalletFactory ( config , version ) {
2014-04-16 13:50:10 -07:00
var self = this ;
2014-05-21 07:10:19 -07:00
config = config || { } ;
2014-06-15 20:55:23 -07:00
this . Storage = config . Storage || StorageLocalEncrypted ;
this . Network = config . Network || WebRTC ;
this . Blockchain = config . Blockchain || Insight ;
this . storage = new this . Storage ( config . storage ) ;
this . network = new this . Network ( config . network ) ;
this . blockchain = new this . Blockchain ( config . blockchain ) ;
2014-04-16 13:50:10 -07:00
2014-06-16 11:51:19 -07:00
this . networkName = config . networkName ;
this . verbose = config . verbose ;
2014-04-16 13:50:10 -07:00
this . walletDefaults = config . wallet ;
2014-06-16 11:51:19 -07:00
this . version = version ;
2014-04-16 13:50:10 -07:00
}
2014-06-16 11:51:19 -07:00
WalletFactory . prototype . log = function ( ) {
2014-04-16 13:50:10 -07:00
if ( ! this . verbose ) return ;
2014-06-03 14:38:56 -07:00
if ( console ) {
console . log . apply ( console , arguments ) ;
}
2014-04-16 13:50:10 -07:00
} ;
WalletFactory . prototype . _checkRead = function ( walletId ) {
var s = this . storage ;
2014-06-16 11:51:19 -07:00
var ret =
s . get ( walletId , 'publicKeyRing' ) &&
s . get ( walletId , 'txProposals' ) &&
s . get ( walletId , 'opts' ) &&
s . get ( walletId , 'privateKey' ) ;
2014-06-02 14:59:38 -07:00
return ! ! ret ;
2014-04-16 13:50:10 -07:00
} ;
2014-04-25 15:12:13 -07:00
WalletFactory . prototype . fromObj = function ( obj ) {
2014-06-09 16:08:12 -07:00
// not stored options
2014-06-16 11:51:19 -07:00
obj . opts . reconnectDelay = this . walletDefaults . reconnectDelay ;
2014-06-09 16:08:12 -07:00
2014-04-28 08:02:43 -07:00
var w = Wallet . fromObj ( obj , this . storage , this . network , this . blockchain ) ;
2014-06-13 07:47:22 -07:00
if ( ! w ) return false ;
2014-04-28 08:02:43 -07:00
w . verbose = this . verbose ;
2014-06-13 07:47:22 -07:00
this . _checkVersion ( w . version ) ;
this . _checkNetwork ( w . getNetworkName ( ) ) ;
2014-04-25 15:12:13 -07:00
return w ;
} ;
2014-05-01 14:32:22 -07:00
WalletFactory . prototype . fromEncryptedObj = function ( base64 , password ) {
this . storage . _setPassphrase ( password ) ;
var walletObj = this . storage . import ( base64 ) ;
2014-06-02 14:59:38 -07:00
if ( ! walletObj ) return false ;
2014-06-02 12:41:57 -07:00
var w = this . fromObj ( walletObj ) ;
2014-05-16 21:19:52 -07:00
return w ;
2014-05-01 14:32:22 -07:00
} ;
2014-07-02 06:43:00 -07:00
WalletFactory . prototype . import = function ( base64 , password ) {
2014-06-18 06:58:34 -07:00
var self = this ;
2014-06-19 07:35:38 -07:00
var w = self . fromEncryptedObj ( base64 , password ) ;
2014-06-19 12:07:51 -07:00
2014-07-02 06:43:00 -07:00
if ( ! w ) throw new Error ( 'Wrong password' ) ;
2014-06-25 11:49:02 -07:00
return w ;
2014-06-19 07:35:38 -07:00
}
2014-05-01 14:32:22 -07:00
2014-05-01 12:21:53 -07:00
WalletFactory . prototype . read = function ( walletId ) {
2014-06-16 11:51:19 -07:00
if ( ! this . _checkRead ( walletId ) )
2014-06-02 14:59:38 -07:00
return false ;
2014-04-25 15:12:13 -07:00
2014-04-28 07:22:41 -07:00
var obj = { } ;
2014-04-25 15:12:13 -07:00
var s = this . storage ;
2014-04-28 07:22:41 -07:00
obj . id = walletId ;
2014-06-16 11:51:19 -07:00
obj . opts = s . get ( walletId , 'opts' ) ;
obj . publicKeyRing = s . get ( walletId , 'publicKeyRing' ) ;
obj . txProposals = s . get ( walletId , 'txProposals' ) ;
obj . privateKey = s . get ( walletId , 'privateKey' ) ;
2014-06-18 06:03:22 -07:00
obj . addressBook = s . get ( walletId , 'addressBook' ) ;
2014-06-25 13:14:12 -07:00
obj . backupOffered = s . get ( walletId , 'backupOffered' ) ;
2014-04-28 07:22:41 -07:00
var w = this . fromObj ( obj ) ;
2014-04-16 13:50:10 -07:00
return w ;
} ;
WalletFactory . prototype . create = function ( opts ) {
2014-06-16 11:51:19 -07:00
opts = opts || { } ;
2014-08-01 07:24:16 -07:00
this . log ( '### CREATING NEW WALLET.' + ( opts . id ? ' USING ID: ' + opts . id : ' NEW ID' ) + ( opts . privateKey ? ' USING PrivateKey: ' + opts . privateKey . getId ( ) : ' NEW PrivateKey' ) ) ;
2014-04-16 13:50:10 -07:00
2014-06-16 11:51:19 -07:00
opts . privateKey = opts . privateKey || new PrivateKey ( {
networkName : this . networkName
} ) ;
2014-04-20 08:41:28 -07:00
2014-04-16 13:50:10 -07:00
var requiredCopayers = opts . requiredCopayers || this . walletDefaults . requiredCopayers ;
2014-06-16 11:51:19 -07:00
var totalCopayers = opts . totalCopayers || this . walletDefaults . totalCopayers ;
2014-08-14 15:46:42 -07:00
opts . lockTimeoutMin = this . walletDefaults . idleDurationMin ;
2014-04-16 13:50:10 -07:00
opts . publicKeyRing = opts . publicKeyRing || new PublicKeyRing ( {
networkName : this . networkName ,
requiredCopayers : requiredCopayers ,
totalCopayers : totalCopayers ,
} ) ;
2014-05-28 12:10:05 -07:00
opts . publicKeyRing . addCopayer (
opts . privateKey . deriveBIP45Branch ( ) . extendedPublicKeyString ( ) ,
2014-08-01 07:24:16 -07:00
opts . nickname
) ;
2014-04-16 13:50:10 -07:00
this . log ( '\t### PublicKeyRing Initialized' ) ;
2014-08-05 12:42:51 -07:00
opts . txProposals = opts . txProposals || new TxProposals ( {
2014-04-16 13:50:10 -07:00
networkName : this . networkName ,
} ) ;
2014-08-05 12:42:51 -07:00
this . log ( '\t### TxProposals Initialized' ) ;
2014-04-16 13:50:10 -07:00
2014-05-01 06:03:58 -07:00
this . storage . _setPassphrase ( opts . passphrase ) ;
2014-04-16 13:50:10 -07:00
opts . storage = this . storage ;
opts . network = this . network ;
opts . blockchain = this . blockchain ;
2014-04-16 16:58:57 -07:00
opts . verbose = this . verbose ;
2014-04-16 13:50:10 -07:00
opts . spendUnconfirmed = opts . spendUnconfirmed || this . walletDefaults . spendUnconfirmed ;
2014-06-16 11:51:19 -07:00
opts . reconnectDelay = opts . reconnectDelay || this . walletDefaults . reconnectDelay ;
2014-04-16 13:50:10 -07:00
opts . requiredCopayers = requiredCopayers ;
2014-06-16 11:51:19 -07:00
opts . totalCopayers = totalCopayers ;
opts . version = opts . version || this . version ;
2014-08-14 15:46:42 -07:00
2014-04-17 13:01:31 -07:00
var w = new Wallet ( opts ) ;
2014-04-16 13:50:10 -07:00
w . store ( ) ;
2014-08-04 11:10:01 -07:00
this . storage . setLastOpened ( w . id ) ;
2014-04-16 13:50:10 -07:00
return w ;
} ;
2014-05-14 17:02:01 -07:00
WalletFactory . prototype . _checkVersion = function ( inVersion ) {
var thisV = this . version . split ( '.' ) ;
var thisV0 = parseInt ( thisV [ 0 ] ) ;
2014-06-16 11:51:19 -07:00
var inV = inVersion . split ( '.' ) ;
var inV0 = parseInt ( inV [ 0 ] ) ;
2014-05-14 17:02:01 -07:00
//We only check for major version differences
2014-06-16 11:51:19 -07:00
if ( thisV0 < inV0 ) {
2014-05-14 17:02:01 -07:00
throw new Error ( 'Major difference in software versions' +
2014-08-05 12:42:51 -07:00
'. Received:' + inVersion +
'. Current version:' + this . version +
'. Aborting.' ) ;
2014-05-14 17:02:01 -07:00
}
} ;
2014-06-09 13:09:06 -07:00
WalletFactory . prototype . _checkNetwork = function ( inNetworkName ) {
2014-06-16 11:51:19 -07:00
if ( this . networkName !== inNetworkName ) {
throw new Error ( 'This Wallet is configured for ' + inNetworkName + ' while currently Copay is configured for: ' + this . networkName + '. Check your settings.' ) ;
2014-06-09 13:09:06 -07:00
}
} ;
2014-08-14 15:46:42 -07:00
WalletFactory . prototype . open = function ( walletId , passphrase ) {
this . storage . _setPassphrase ( passphrase ) ;
var w = this . read ( walletId , opts ) ;
if ( w )
2014-05-06 13:57:16 -07:00
w . store ( ) ;
2014-08-04 11:10:01 -07:00
this . storage . setLastOpened ( walletId ) ;
2014-04-16 16:58:57 -07:00
return w ;
} ;
2014-04-24 12:35:52 -07:00
WalletFactory . prototype . getWallets = function ( ) {
var ret = this . storage . getWallets ( ) ;
ret . forEach ( function ( i ) {
2014-06-16 11:51:19 -07:00
i . show = i . name ? ( ( i . name + ' <' + i . id + '>' ) ) : i . id ;
2014-04-24 12:35:52 -07:00
} ) ;
return ret ;
} ;
2014-04-16 13:50:10 -07:00
2014-06-16 13:37:33 -07:00
WalletFactory . prototype . delete = function ( walletId , cb ) {
2014-06-16 11:51:19 -07:00
var s = this . storage ;
2014-06-16 13:37:33 -07:00
this . log ( '## DELETING WALLET ID:' + walletId ) ; //TODO
s . deleteWallet ( walletId ) ;
2014-08-04 11:10:01 -07:00
s . setLastOpened ( undefined ) ;
2014-06-16 11:51:19 -07:00
return cb ( ) ;
2014-04-16 13:50:10 -07:00
} ;
2014-05-14 14:24:24 -07:00
WalletFactory . prototype . decodeSecret = function ( secret ) {
try {
return Wallet . decodeSecret ( secret ) ;
} catch ( e ) {
return false ;
}
2014-06-09 14:01:15 -07:00
} ;
2014-04-16 16:58:57 -07:00
2014-05-01 14:34:30 -07:00
WalletFactory . prototype . joinCreateSession = function ( secret , nickname , passphrase , cb ) {
2014-04-20 08:41:28 -07:00
var self = this ;
2014-05-14 14:24:24 -07:00
var s = self . decodeSecret ( secret ) ;
if ( ! s ) return cb ( 'badSecret' ) ;
2014-06-16 11:51:19 -07:00
2014-04-20 08:41:28 -07:00
//Create our PrivateK
2014-06-16 11:51:19 -07:00
var privateKey = new PrivateKey ( {
networkName : this . networkName
} ) ;
2014-04-20 08:41:28 -07:00
this . log ( '\t### PrivateKey Initialized' ) ;
2014-04-24 19:13:55 -07:00
var opts = {
copayerId : privateKey . getId ( ) ,
2014-06-26 08:49:22 -07:00
privkey : privateKey . getIdPriv ( ) ,
key : privateKey . getIdKey ( )
2014-04-24 19:13:55 -07:00
} ;
self . network . cleanUp ( ) ;
2014-07-08 11:25:12 -07:00
// This is a hack to reconize if the connection was rejected or the peer wasn't there.
var connectedOnce = false ;
self . network . on ( 'connected' , function ( sender , data ) {
connectedOnce = true ;
} ) ;
self . network . on ( 'onlyYou' , function ( sender , data ) {
return cb ( connectedOnce ? 'walletFull' : 'joinError' ) ;
} ) ;
self . network . on ( 'serverError' , function ( ) {
return cb ( 'joinError' ) ;
} ) ;
2014-04-24 19:13:55 -07:00
self . network . start ( opts , function ( ) {
2014-04-30 08:58:40 -07:00
self . network . connectTo ( s . pubKey ) ;
2014-05-19 16:47:28 -07:00
2014-04-20 12:16:09 -07:00
self . network . on ( 'data' , function ( sender , data ) {
2014-06-16 11:51:19 -07:00
if ( data . type === 'walletId' ) {
if ( data . networkName !== self . networkName ) {
2014-06-09 17:00:28 -07:00
return cb ( 'badNetwork' ) ;
}
2014-04-20 12:16:09 -07:00
data . opts . privateKey = privateKey ;
2014-06-16 11:51:19 -07:00
data . opts . nickname = nickname ;
2014-05-01 14:34:30 -07:00
data . opts . passphrase = passphrase ;
2014-05-06 13:57:16 -07:00
data . opts . id = data . walletId ;
var w = self . create ( data . opts ) ;
2014-05-09 10:35:57 -07:00
w . seedCopayer ( s . pubKey ) ;
2014-04-30 08:58:40 -07:00
return cb ( null , w ) ;
2014-04-20 12:16:09 -07:00
}
2014-04-16 16:58:57 -07:00
} ) ;
} ) ;
} ;
2014-08-14 12:02:31 -07:00
module . exports = WalletFactory ;