2014-04-16 17:50:10 -03:00
'use strict' ;
2014-09-03 01:25:08 -03:00
var preconditions = require ( 'preconditions' ) . singleton ( ) ;
2014-04-16 17:50:10 -03:00
2014-10-10 12:02:46 -03:00
var _ = require ( 'underscore' ) ;
var log = require ( '../log' ) ;
var version = require ( '../../version' ) . version ;
2014-08-01 01:09:46 -03:00
var TxProposals = require ( './TxProposals' ) ;
2014-04-16 17:50:10 -03:00
var PublicKeyRing = require ( './PublicKeyRing' ) ;
var PrivateKey = require ( './PrivateKey' ) ;
var Wallet = require ( './Wallet' ) ;
2014-09-03 01:25:08 -03:00
var PluginManager = require ( './PluginManager' ) ;
2014-09-27 18:00:27 -03:00
var Profile = require ( './Profile' ) ;
2014-09-23 15:24:57 -03:00
var Insight = module . exports . Insight = require ( './Insight' ) ;
2014-09-30 20:12:02 -03:00
var Async = module . exports . Async = require ( './Async' ) ;
2014-09-23 15:24:57 -03:00
var Storage = module . exports . Storage = require ( './Storage' ) ;
2014-06-15 20:55:23 -07:00
2014-09-04 01:33:12 -03:00
/ * *
* @ desc
2014-09-26 05:00:43 -03:00
* Identity - stores the state for a wallet in creation
2014-09-04 01:33:12 -03:00
*
* @ param { Object } config - configuration for this wallet
* @ param { Object } config . wallet - default configuration for the wallet
2014-09-08 15:42:55 -03:00
* @ constructor
2014-04-16 17:50:10 -03:00
* /
2014-09-03 01:25:08 -03:00
2014-10-21 09:57:54 -03:00
function Identity ( password , opts ) {
2014-09-28 18:38:06 -03:00
preconditions . checkArgument ( opts ) ;
2014-06-15 20:55:23 -07:00
2014-10-22 00:14:48 -03:00
opts = _ . extend ( { } , opts ) ;
2014-10-11 08:43:51 -03:00
this . storage = Identity . _getStorage ( opts , password ) ;
2014-10-07 18:33:55 -03:00
this . networkOpts = {
'livenet' : opts . network . livenet ,
'testnet' : opts . network . testnet ,
2014-09-10 11:12:28 -07:00
} ;
2014-10-07 18:33:55 -03:00
this . blockchainOpts = {
'livenet' : opts . network . livenet ,
'testnet' : opts . network . testnet ,
2014-09-10 11:12:28 -07:00
} ;
2014-04-16 17:50:10 -03:00
2014-10-23 15:47:24 -03:00
this . pluginManager = opts . pluginManager || { } ;
2014-10-22 00:14:48 -03:00
this . insightSaveOpts = opts . insightSave || { } ;
2014-10-05 13:01:43 -03:00
this . walletDefaults = opts . walletDefaults || { } ;
2014-09-28 18:38:06 -03:00
this . version = opts . version || version ;
2014-10-24 08:37:40 -03:00
this . wallets = { } ;
2014-09-28 18:38:06 -03:00
} ;
/* for stubbing */
2014-09-30 15:28:02 -03:00
Identity . _createProfile = function ( email , password , storage , cb ) {
Profile . create ( email , password , storage , cb ) ;
2014-09-28 18:38:06 -03:00
} ;
Identity . _newStorage = function ( opts ) {
2014-09-27 18:53:34 -03:00
return new Storage ( opts ) ;
} ;
2014-09-29 19:58:00 -03:00
Identity . _newWallet = function ( opts ) {
2014-09-29 12:11:10 -03:00
return new Wallet ( opts ) ;
} ;
2014-10-16 17:39:22 -03:00
Identity . _walletFromObj = function ( o , readOpts ) {
return Wallet . fromObj ( o , readOpts ) ;
2014-09-29 12:11:10 -03:00
} ;
2014-10-05 15:59:41 -03:00
Identity . _walletDelete = function ( id , s , cb ) {
return Wallet . delete ( id , s , cb ) ;
2014-09-29 19:58:00 -03:00
} ;
2014-10-01 08:35:17 -03:00
/* for stubbing */
Identity . _openProfile = function ( email , password , storage , cb ) {
Profile . open ( email , password , storage , cb ) ;
} ;
2014-10-07 18:33:55 -03:00
/* for stubbing */
Identity . _newAsync = function ( opts ) {
return new Async ( opts ) ;
} ;
2014-10-11 08:43:51 -03:00
Identity . _getStorage = function ( opts , password ) {
var storageOpts = { } ;
if ( opts . pluginManager ) {
storageOpts = _ . clone ( {
db : opts . pluginManager . get ( 'DB' ) ,
passphraseConfig : opts . passphraseConfig ,
} ) ;
}
if ( password )
storageOpts . password = password ;
return Identity . _newStorage ( storageOpts ) ;
} ;
/ * *
* check if any profile exists on storage
*
* @ param opts . storageOpts
* @ param cb
* /
Identity . anyProfile = function ( opts , cb ) {
var storage = Identity . _getStorage ( opts ) ;
2014-10-24 09:36:28 -03:00
storage . getFirst ( Profile . key ( '' ) , {
onlyKey : true
} , function ( err , v , k ) {
return cb ( k ? true : false ) ;
} ) ;
2014-10-11 08:43:51 -03:00
} ;
2014-10-01 08:35:17 -03:00
2014-10-11 14:33:45 -03:00
/ * *
* check if any wallet exists on storage
*
* @ param opts . storageOpts
* @ param cb
* /
Identity . anyWallet = function ( opts , cb ) {
var storage = Identity . _getStorage ( opts ) ;
2014-10-24 09:36:28 -03:00
storage . getFirst ( Wallet . getStorageKey ( '' ) , {
onlyKey : true
} , function ( err , v , k ) {
return cb ( k ? true : false ) ;
} ) ;
2014-10-11 14:33:45 -03:00
} ;
2014-09-28 18:38:06 -03:00
/ * *
* creates and Identity
*
* @ param email
* @ param password
* @ param opts
* @ param cb
* @ return { undefined }
* /
Identity . create = function ( email , password , opts , cb ) {
2014-09-30 16:04:17 -03:00
opts = opts || { } ;
2014-09-30 15:28:02 -03:00
2014-10-21 09:57:54 -03:00
var iden = new Identity ( password , opts ) ;
2014-09-30 16:04:17 -03:00
2014-09-30 15:28:02 -03:00
Identity . _createProfile ( email , password , iden . storage , function ( err , profile ) {
if ( err ) return cb ( err ) ;
iden . profile = profile ;
2014-09-30 16:04:17 -03:00
if ( opts . noWallets )
cb ( null , iden ) ;
// default wallet
2014-10-06 16:13:21 -03:00
var dflt = _ . clone ( opts . walletDefaults ) ;
var wopts = _ . extend ( dflt , {
2014-09-30 16:04:17 -03:00
nickname : email ,
networkName : opts . networkName ,
requiredCopayers : 1 ,
totalCopayers : 1 ,
2014-09-30 21:16:46 -03:00
password : password ,
2014-10-22 00:14:48 -03:00
name : 'general'
2014-09-30 20:12:02 -03:00
} ) ;
2014-09-30 16:04:17 -03:00
iden . createWallet ( wopts , function ( err , w ) {
2014-10-22 00:14:48 -03:00
if ( err ) {
return cb ( err ) ;
}
2014-10-23 17:26:32 -03:00
if ( iden . pluginManager . get && iden . pluginManager . get ( 'remote-backup' ) ) {
iden . pluginManager . get ( 'remote-backup' ) . store (
iden ,
iden . insightSaveOpts ,
function ( error ) {
// FIXME: Ignoring this error may not be the best thing to do. But remote storage
// is not required for the user to use the wallet.
return cb ( null , iden , w ) ;
}
) ;
} else {
return cb ( null , iden , w ) ;
}
2014-09-30 16:04:17 -03:00
} ) ;
2014-09-28 18:38:06 -03:00
} ) ;
} ;
/ * *
* validates Profile ' s email
*
* @ param authcode
* @ param cb
* @ return { undefined }
* /
Identity . prototype . validate = function ( authcode , cb ) {
// TODO
console . log ( '[Identity.js.99] TODO: Should validate email thru authcode' ) ; //TODO
return cb ( ) ;
} ;
/ * *
* open ' s an Identity from storage
*
* @ param email
* @ param password
* @ param opts
* @ param cb
* @ return { undefined }
* /
Identity . open = function ( email , password , opts , cb ) {
2014-10-21 09:57:54 -03:00
var iden = new Identity ( password , opts ) ;
2014-09-30 08:09:39 -03:00
2014-10-01 08:35:17 -03:00
Identity . _openProfile ( email , password , iden . storage , function ( err , profile ) {
2014-10-22 00:14:48 -03:00
if ( err ) {
if ( err . message && err . message . indexOf ( 'PNOTFOUND' ) !== - 1 ) {
2014-10-23 17:26:32 -03:00
if ( opts . pluginManager && opts . pluginManager . get ( 'remote-backup' ) ) {
return opts . pluginManager . get ( 'remote-backup' ) . retrieve ( email , password , opts , cb ) ;
} else {
return cb ( err ) ;
}
2014-10-22 00:14:48 -03:00
}
return cb ( err ) ;
}
2014-09-30 08:09:39 -03:00
iden . profile = profile ;
2014-10-05 15:59:41 -03:00
var wids = _ . pluck ( iden . listWallets ( ) , 'id' ) ;
2014-10-08 10:54:26 -03:00
if ( ! wids || ! wids . length )
2014-10-15 17:18:30 -03:00
return cb ( new Error ( 'Could not open any wallet from profile' ) , iden ) ;
2014-10-08 10:54:26 -03:00
// Open All wallets from profile
//This could be optional, or opts.onlyOpen = wid
2014-10-15 10:59:09 -03:00
var wallets = [ ] ;
var remaining = wids . length ;
2014-10-08 10:54:26 -03:00
_ . each ( wids , function ( wid ) {
iden . openWallet ( wid , function ( err , w ) {
2014-10-15 12:09:10 -03:00
if ( err ) {
2014-10-08 10:54:26 -03:00
log . error ( 'Cound not open wallet id:' + wid + '. Skipping' )
2014-10-15 12:09:10 -03:00
iden . profile . deleteWallet ( wid , function ( ) { } ) ;
} else {
2014-10-08 10:54:26 -03:00
log . info ( 'Open wallet id:' + wid + ' opened' ) ;
2014-10-15 10:59:09 -03:00
wallets . push ( w ) ;
}
if ( -- remaining == 0 ) {
2014-10-20 18:33:21 -03:00
var lastFocused = iden . profile . getLastFocusedWallet ( ) ;
return cb ( err , iden , lastFocused ) ;
2014-10-08 10:54:26 -03:00
}
2014-10-05 15:59:41 -03:00
} )
2014-10-08 10:54:26 -03:00
} ) ;
2014-09-28 18:38:06 -03:00
} ) ;
} ;
/ * *
* isAvailable
*
* @ param email
* @ param opts
* @ param cb
* @ return { undefined }
* /
Identity . isAvailable = function ( email , opts , cb ) {
console . log ( '[Identity.js.127:isAvailable:] TODO' ) ; //TODO
return cb ( ) ;
} ;
2014-10-24 09:36:28 -03:00
Identity . prototype . readWallet = function ( walletId , readOpts , cb ) {
preconditions . checkArgument ( cb ) ;
var self = this ,
err ;
var obj = { } ;
this . storage . getFirst ( Wallet . getStorageKey ( walletId ) , { } , function ( err , obj ) {
if ( err ) return cb ( err ) ;
if ( ! obj )
return cb ( new Error ( 'WNOTFOUND: Wallet not found' ) ) ;
var w , err ;
obj . id = walletId ;
try {
log . debug ( '## OPENING Wallet: ' + walletId ) ;
w = Wallet . fromUntrustedObj ( obj , readOpts ) ;
} catch ( e ) {
log . debug ( "ERROR: " , e . message ) ;
if ( e && e . message && e . message . indexOf ( 'MISSOPTS' ) ) {
err = new Error ( 'WERROR: Could not read: ' + walletId + ': ' + e . message ) ;
} else {
err = e ;
}
w = null ;
}
return cb ( err , w ) ;
} ) ;
} ;
2014-09-28 18:38:06 -03:00
2014-10-24 08:37:40 -03:00
Identity . prototype . storeWallet = function ( w , cb ) {
preconditions . checkArgument ( w && _ . isObject ( w ) ) ;
var id = w . getId ( ) ;
var val = w . toObj ( ) ;
var key = Wallet . getStorageKey ( id + '_' + w . getName ( ) ) ;
this . storage . set ( key , val , function ( err ) {
log . debug ( 'Wallet:' + w . getName ( ) + ' stored' ) ;
if ( cb )
cb ( err ) ;
} ) ;
} ;
2014-09-29 10:18:47 -03:00
/ * *
* store
*
* @ param opts
* @ param cb
* @ return { undefined }
* /
2014-09-28 18:38:06 -03:00
Identity . prototype . store = function ( opts , cb ) {
2014-09-30 15:28:02 -03:00
preconditions . checkState ( this . profile ) ;
2014-09-28 20:50:37 -03:00
var self = this ;
2014-09-28 21:22:53 -03:00
self . profile . store ( opts , function ( err ) {
if ( err ) return cb ( err ) ;
2014-10-24 08:37:40 -03:00
var l = Object . keys ( self . wallets ) ,
2014-09-28 20:50:37 -03:00
i = 0 ;
if ( ! l ) return cb ( ) ;
2014-10-24 08:37:40 -03:00
_ . each ( self . wallets , function ( w ) {
self . storeWallet ( w , function ( err ) {
2014-09-28 20:50:37 -03:00
if ( err ) return cb ( err ) ;
if ( ++ i == l )
return cb ( ) ;
} )
} ) ;
} ) ;
2014-09-28 18:38:06 -03:00
} ;
2014-09-30 21:16:46 -03:00
2014-10-05 15:59:41 -03:00
Identity . prototype . _cleanUp = function ( ) {
2014-10-07 18:33:55 -03:00
// NOP
2014-10-05 15:59:41 -03:00
} ;
2014-09-30 21:16:46 -03:00
/ * *
* @ desc Closes the wallet and disconnects all services
* /
Identity . prototype . close = function ( cb ) {
preconditions . checkState ( this . profile ) ;
2014-10-24 08:37:40 -03:00
var l = Object . keys ( this . wallets ) ,
2014-09-30 21:16:46 -03:00
i = 0 ;
2014-10-01 08:35:17 -03:00
if ( ! l ) {
return cb ? cb ( ) : null ;
}
2014-09-30 21:16:46 -03:00
2014-10-05 15:59:41 -03:00
var self = this ;
2014-10-24 08:37:40 -03:00
_ . each ( this . wallets , function ( w ) {
2014-09-30 21:16:46 -03:00
w . close ( function ( err ) {
if ( err ) return cb ( err ) ;
2014-10-05 15:59:41 -03:00
if ( ++ i == l ) {
self . _cleanUp ( ) ;
if ( cb ) return cb ( ) ;
}
2014-09-30 21:16:46 -03:00
} )
} ) ;
} ;
2014-09-04 01:33:12 -03:00
/ * *
* @ desc Imports a wallet from an encrypted base64 object
* @ param { string } base64 - the base64 encoded object
2014-09-18 18:29:00 -03:00
* @ param { string } passphrase - passphrase to decrypt it
2014-09-04 01:33:12 -03:00
* @ param { string [ ] } skipFields - fields to ignore when importing
* @ return { Wallet }
* /
2014-09-30 21:16:46 -03:00
Identity . prototype . importWallet = function ( base64 , password , skipFields , cb ) {
2014-10-16 17:39:22 -03:00
var self = this ;
2014-10-14 09:58:12 -03:00
preconditions . checkArgument ( password ) ;
2014-09-29 16:55:45 -03:00
preconditions . checkArgument ( cb ) ;
2014-10-21 09:57:54 -03:00
var obj = this . storage . decrypt ( base64 , password ) ;
2014-09-29 11:35:04 -03:00
2014-10-16 17:39:22 -03:00
var readOpts = {
networkOpts : this . networkOpts ,
blockchainOpts : this . blockchainOpts ,
skipFields : skipFields
} ;
if ( ! obj ) return cb ( null ) ;
var w = Identity . _walletFromObj ( obj , readOpts ) ;
2014-09-29 11:35:04 -03:00
this . _checkVersion ( w . version ) ;
2014-09-29 16:55:45 -03:00
this . addWallet ( w , function ( err ) {
2014-10-16 17:39:22 -03:00
if ( err ) return cb ( err , null ) ;
2014-10-24 08:37:40 -03:00
self . wallets [ w . getId ( ) ] = w ;
2014-10-16 17:39:22 -03:00
self . store ( null , function ( err ) {
return cb ( err , w ) ;
} ) ;
2014-09-29 11:35:04 -03:00
} ) ;
2014-05-01 18:32:22 -03:00
} ;
2014-10-05 15:59:41 -03:00
Identity . prototype . closeWallet = function ( wid , cb ) {
2014-10-08 10:54:26 -03:00
var w = this . getOpenWallet ( wid ) ;
preconditions . checkState ( w , 'Wallet not found' ) ;
2014-10-05 15:59:41 -03:00
var self = this ;
w . close ( function ( err ) {
2014-10-24 08:37:40 -03:00
delete self . wallets [ wid ] ;
2014-10-05 15:59:41 -03:00
return cb ( err ) ;
} ) ;
} ;
2014-10-22 00:14:48 -03:00
Identity . importFromJson = function ( str , password , opts , cb ) {
2014-10-21 09:57:54 -03:00
preconditions . checkArgument ( str ) ;
2014-10-22 00:14:48 -03:00
var json ;
try {
json = JSON . parse ( str ) ;
} catch ( e ) {
return cb ( 'Unable to retrieve json from string' , str ) ;
}
2014-10-21 09:57:54 -03:00
2014-10-21 12:03:09 -03:00
if ( ! _ . isNumber ( json . iterations ) )
2014-10-24 08:37:40 -03:00
return cb ( 'BADSTR: Missing iterations' ) ;
2014-10-21 09:57:54 -03:00
2014-10-21 12:03:09 -03:00
if ( ! json . profile )
return cb ( 'BADSTR: Missing profile' ) ;
2014-10-21 09:57:54 -03:00
var iden = new Identity ( password , opts ) ;
iden . profile = Profile . import ( json . profile , password , iden . storage ) ;
json . wallets = json . wallets || { } ;
2014-10-22 00:14:48 -03:00
var walletInfoBackup = iden . profile . walletInfos ;
iden . profile . walletInfos = { } ;
2014-10-21 09:57:54 -03:00
2014-10-22 00:14:48 -03:00
var l = _ . size ( json . wallets ) ,
2014-10-21 09:57:54 -03:00
i = 0 ;
if ( ! l )
return cb ( null , iden ) ;
2014-10-22 00:14:48 -03:00
_ . each ( json . wallets , function ( wstr ) {
iden . importWallet ( wstr , password , opts . skipFields , function ( err , w ) {
2014-10-21 09:57:54 -03:00
if ( err ) return cb ( err ) ;
log . debug ( 'Wallet ' + w . getId ( ) + ' imported' ) ;
2014-10-22 00:14:48 -03:00
if ( ++ i == l ) {
iden . profile . walletInfos = walletInfoBackup ;
iden . store ( opts , function ( err ) {
if ( err ) {
return cb ( err ) ;
} else {
return cb ( null , iden , iden . openWallets [ 0 ] ) ;
}
} ) ;
}
2014-10-21 09:57:54 -03:00
} )
} ) ;
} ;
/ * *
* @ desc Return JSON with base64 encoded strings for wallets and profile , and iteration count
* @ return { string } Stringify JSON
* /
2014-10-22 00:14:48 -03:00
Identity . prototype . exportAsJson = function ( ) {
2014-10-15 16:24:21 -03:00
var ret = { } ;
ret . iterations = this . storage . iterations ;
2014-10-21 09:57:54 -03:00
ret . profile = this . profile . export ( ) ;
2014-10-15 16:24:21 -03:00
ret . wallets = { } ;
2014-10-24 08:37:40 -03:00
_ . each ( this . wallets , function ( w ) {
2014-10-21 12:03:09 -03:00
ret . wallets [ w . getId ( ) ] = w . export ( ) ;
2014-10-15 16:24:21 -03:00
} ) ;
2014-10-21 09:57:54 -03:00
var r = JSON . stringify ( ret ) ;
return r ;
2014-10-15 15:02:14 -03:00
} ;
2014-10-24 08:37:40 -03:00
Identity . prototype . bindWallet = function ( w ) {
var self = this ;
self . wallets [ w . getId ( ) ] = w ;
log . debug ( 'Binding wallet ' + w . getName ( ) ) ;
w . on ( 'hasChange' , function ( ) {
log . debug ( '<hasChange> Wallet' + w . getName ( ) ) ;
self . storeWallet ( w ) ;
} ) ;
} ;
2014-09-04 01:33:12 -03:00
/ * *
2014-09-14 13:52:43 -03:00
* @ desc This method prepares options for a new Wallet
2014-09-04 01:33:12 -03:00
*
* @ param { Object } opts
* @ param { string } opts . id
* @ param { PrivateKey = } opts . privateKey
* @ param { string = } opts . privateKeyHex
* @ param { number } opts . requiredCopayers
* @ param { number } opts . totalCopayers
* @ param { PublicKeyRing = } opts . publicKeyRing
* @ param { string } opts . nickname
2014-09-30 21:16:46 -03:00
* @ param { string } opts . password
2014-09-04 01:33:12 -03:00
* @ TODO : Figure out what is this parameter
* @ param { ? } opts . spendUnconfirmed this . walletDefaults . spendUnconfirmed ? ?
* @ TODO : Figure out in what unit is this reconnect delay .
* @ param { number } opts . reconnectDelay milliseconds ?
* @ param { number = } opts . version
2014-09-03 15:43:27 -03:00
* @ param { callback } opts . version
2014-09-04 01:33:12 -03:00
* @ return { Wallet }
* /
2014-09-27 18:56:25 -03:00
Identity . prototype . createWallet = function ( opts , cb ) {
2014-09-08 10:46:57 -03:00
preconditions . checkArgument ( cb ) ;
2014-09-30 20:12:02 -03:00
preconditions . checkState ( this . profile ) ;
2014-09-10 13:56:49 -07:00
opts = opts || { } ;
opts . networkName = opts . networkName || 'testnet' ;
2014-09-10 11:12:28 -07:00
2014-09-01 12:35:40 -03:00
log . debug ( '### CREATING NEW WALLET.' + ( opts . id ? ' USING ID: ' + opts . id : ' NEW ID' ) + ( opts . privateKey ? ' USING PrivateKey: ' + opts . privateKey . getId ( ) : ' NEW PrivateKey' ) ) ;
2014-04-16 17:50:10 -03:00
2014-08-21 14:54:36 -04:00
var privOpts = {
2014-09-09 15:30:49 -07:00
networkName : opts . networkName ,
2014-08-21 14:54:36 -04:00
} ;
2014-09-04 16:13:30 -03:00
if ( opts . privateKeyHex && opts . privateKeyHex . length > 1 ) {
2014-08-21 14:54:36 -04:00
privOpts . extendedPrivateKeyString = opts . privateKeyHex ;
}
opts . privateKey = opts . privateKey || new PrivateKey ( privOpts ) ;
2014-04-20 12:41:28 -03:00
2014-04-16 17:50:10 -03:00
var requiredCopayers = opts . requiredCopayers || this . walletDefaults . requiredCopayers ;
2014-06-16 15:51:19 -03:00
var totalCopayers = opts . totalCopayers || this . walletDefaults . totalCopayers ;
2014-08-14 18:46:42 -04:00
opts . lockTimeoutMin = this . walletDefaults . idleDurationMin ;
2014-04-16 17:50:10 -03:00
opts . publicKeyRing = opts . publicKeyRing || new PublicKeyRing ( {
2014-09-09 15:30:49 -07:00
networkName : opts . networkName ,
2014-04-16 17:50:10 -03:00
requiredCopayers : requiredCopayers ,
totalCopayers : totalCopayers ,
} ) ;
2014-05-28 16:10:05 -03:00
opts . publicKeyRing . addCopayer (
opts . privateKey . deriveBIP45Branch ( ) . extendedPublicKeyString ( ) ,
2014-10-16 10:18:37 -03:00
opts . nickname || this . profile . getName ( )
2014-08-01 11:24:16 -03:00
) ;
2014-09-01 12:35:40 -03:00
log . debug ( '\t### PublicKeyRing Initialized' ) ;
2014-04-16 17:50:10 -03:00
2014-08-05 16:42:51 -03:00
opts . txProposals = opts . txProposals || new TxProposals ( {
2014-09-09 15:30:49 -07:00
networkName : opts . networkName ,
2014-04-16 17:50:10 -03:00
} ) ;
2014-09-01 12:35:40 -03:00
log . debug ( '\t### TxProposals Initialized' ) ;
2014-04-16 17:50:10 -03:00
2014-05-01 10:03:58 -03:00
2014-10-07 18:33:55 -03:00
opts . networkOpts = this . networkOpts ;
opts . blockchainOpts = this . blockchainOpts ;
2014-04-16 20:58:57 -03:00
2014-04-16 17:50:10 -03:00
opts . spendUnconfirmed = opts . spendUnconfirmed || this . walletDefaults . spendUnconfirmed ;
2014-06-16 15:51:19 -03:00
opts . reconnectDelay = opts . reconnectDelay || this . walletDefaults . reconnectDelay ;
2014-04-16 17:50:10 -03:00
opts . requiredCopayers = requiredCopayers ;
2014-06-16 15:51:19 -03:00
opts . totalCopayers = totalCopayers ;
opts . version = opts . version || this . version ;
2014-08-14 18:46:42 -04:00
2014-09-29 06:31:04 -03:00
var self = this ;
2014-09-29 19:58:00 -03:00
var w = Identity . _newWallet ( opts ) ;
2014-09-29 11:35:04 -03:00
this . addWallet ( w , function ( err ) {
2014-09-14 13:52:43 -03:00
if ( err ) return cb ( err ) ;
2014-10-24 08:37:40 -03:00
self . bindWallet ( w ) ;
2014-10-23 17:26:32 -03:00
if ( self . pluginManager . get && self . pluginManager . get ( 'remote-backup' ) ) {
self . pluginManager . get ( 'remote-backup' ) . store ( self , self . insightSaveOpts , _ . noop ) ;
}
w . netStart ( ) ;
return cb ( null , w ) ;
2014-10-22 00:14:48 -03:00
} ) ;
} ;
2014-04-16 17:50:10 -03:00
2014-10-05 15:59:41 -03:00
// add wallet (import)
2014-09-29 11:35:04 -03:00
Identity . prototype . addWallet = function ( wallet , cb ) {
2014-09-29 12:11:10 -03:00
preconditions . checkArgument ( wallet ) ;
2014-09-29 16:55:45 -03:00
preconditions . checkArgument ( wallet . getId ) ;
2014-09-29 11:35:04 -03:00
preconditions . checkArgument ( cb ) ;
2014-09-30 20:12:02 -03:00
preconditions . checkState ( this . profile ) ;
2014-09-29 11:35:04 -03:00
var self = this ;
2014-10-05 15:59:41 -03:00
self . profile . addWallet ( wallet . getId ( ) , {
name : wallet . name
} , function ( err ) {
2014-09-30 21:16:46 -03:00
if ( err ) return cb ( err ) ;
2014-10-24 08:37:40 -03:00
self . storeWallet ( wallet , function ( err ) {
return cb ( err ) ;
} ) ;
2014-09-29 11:35:04 -03:00
} ) ;
} ;
2014-09-04 01:33:12 -03:00
/ * *
* @ desc Checks if a version is compatible with the current version
* @ param { string } inVersion - a version , with major , minor , and revision , period - separated ( x . y . z )
* @ throws { Error } if there ' s a major version difference
* /
2014-09-26 05:00:43 -03:00
Identity . prototype . _checkVersion = function ( inVersion ) {
2014-09-29 12:11:10 -03:00
if ( inVersion ) {
var thisV = this . version . split ( '.' ) ;
var thisV0 = parseInt ( thisV [ 0 ] ) ;
var inV = inVersion . split ( '.' ) ;
var inV0 = parseInt ( inV [ 0 ] ) ;
}
2014-05-14 21:02:01 -03:00
//We only check for major version differences
2014-06-16 15:51:19 -03:00
if ( thisV0 < inV0 ) {
2014-05-14 21:02:01 -03:00
throw new Error ( 'Major difference in software versions' +
2014-09-04 16:13:30 -03:00
'. Received:' + inVersion +
'. Current version:' + this . version +
'. Aborting.' ) ;
2014-05-14 21:02:01 -03:00
}
} ;
2014-09-04 01:33:12 -03:00
/ * *
* @ desc Retrieve a wallet from the storage
* @ param { string } walletId - the id of the wallet
2014-09-03 01:25:08 -03:00
* @ param { function } callback ( err , { Wallet } )
* @ return
2014-09-04 01:33:12 -03:00
* /
2014-10-08 10:54:26 -03:00
Identity . prototype . openWallet = function ( walletId , cb ) {
2014-09-08 10:46:57 -03:00
preconditions . checkArgument ( cb ) ;
2014-10-08 10:54:26 -03:00
preconditions . checkState ( this . storage . hasPassphrase ( ) ) ;
2014-10-05 15:59:41 -03:00
2014-10-08 10:54:26 -03:00
var self = this ;
2014-10-01 08:35:17 -03:00
// TODO
// self.migrateWallet(walletId, password, function() {
2014-10-07 18:33:55 -03:00
//
2014-09-29 19:58:00 -03:00
2014-10-24 09:36:28 -03:00
self . readWallet ( walletId , {
2014-10-08 10:54:26 -03:00
networkOpts : this . networkOpts ,
2014-10-07 18:33:55 -03:00
blockchainOpts : this . blockchainOpts
} , function ( err , w ) {
2014-10-01 08:35:17 -03:00
if ( err ) return cb ( err ) ;
2014-10-24 08:37:40 -03:00
self . bindWallet ( w ) ;
self . storeWallet ( w , function ( err ) {
2014-10-20 18:33:21 -03:00
w . netStart ( ) ;
return cb ( err , w ) ;
2014-09-03 01:25:08 -03:00
} ) ;
} ) ;
2014-10-01 08:35:17 -03:00
// });
2014-04-16 20:58:57 -03:00
} ;
2014-09-29 06:31:04 -03:00
2014-10-08 10:54:26 -03:00
Identity . prototype . getOpenWallet = function ( id ) {
2014-10-24 08:37:40 -03:00
return this . wallets [ id ] ;
2014-10-08 10:54:26 -03:00
} ;
2014-10-14 13:22:28 -03:00
Identity . prototype . listWallets = function ( ) {
2014-10-05 15:59:41 -03:00
var ret = this . profile . listWallets ( ) ;
return ret ;
2014-04-24 16:35:52 -03:00
} ;
2014-04-16 17:50:10 -03:00
2014-09-04 01:33:12 -03:00
/ * *
* @ desc Deletes this wallet . This involves removing it from the storage instance
* @ param { string } walletId
* @ callback cb
2014-09-29 10:18:47 -03:00
* @ return { err }
2014-09-04 01:33:12 -03:00
* /
2014-09-28 18:38:06 -03:00
Identity . prototype . deleteWallet = function ( walletId , cb ) {
2014-09-23 16:01:02 -03:00
var self = this ;
2014-09-29 19:58:00 -03:00
Identity . _walletDelete ( walletId , this . storage , function ( err ) {
2014-09-13 10:25:13 -03:00
if ( err ) return cb ( err ) ;
2014-09-29 10:18:47 -03:00
self . profile . deleteWallet ( walletId , function ( err ) {
2014-09-13 10:25:13 -03:00
return cb ( err ) ;
} ) ;
2014-09-29 10:18:47 -03:00
} )
2014-04-16 17:50:10 -03:00
} ;
2014-09-04 01:33:12 -03:00
/ * *
* @ desc Pass through to { @ link Wallet # secret }
* /
2014-09-26 05:00:43 -03:00
Identity . prototype . decodeSecret = function ( secret ) {
2014-05-14 14:24:24 -07:00
try {
return Wallet . decodeSecret ( secret ) ;
} catch ( e ) {
return false ;
}
2014-06-09 18:01:15 -03:00
} ;
2014-04-16 20:58:57 -03:00
2014-09-04 01:33:12 -03:00
/ * *
* @ callback walletCreationCallback
2014-09-08 15:42:55 -03:00
* @ param { ? } err - an error , if any , that happened during the wallet creation
2014-09-04 01:33:12 -03:00
* @ param { Wallet = } wallet - the wallet created
* /
2014-04-20 12:41:28 -03:00
2014-09-04 01:33:12 -03:00
/ * *
* @ desc Start the network functionality .
*
* Start up the Network instance and try to join a wallet defined by the
* parameter < tt > secret < / t t > u s i n g t h e p a r a m e t e r < t t > n i c k n a m e < / t t > . E n c o d e
* information locally using < tt > passphrase < / t t > . < t t > p r i v a t e H e x < / t t > i s t h e
* private extended master key . < tt > cb < / t t > h a s t w o p a r a m s : e r r o r a n d w a l l e t .
*
2014-09-14 13:52:43 -03:00
* @ param { object } opts
* @ param { string } opts . secret - the wallet secret
* @ param { string } opts . nickname - a nickname for the current user
* @ param { string } opts . privateHex - the private extended master key
2014-09-04 01:33:12 -03:00
* @ param { walletCreationCallback } cb - a callback
* /
2014-09-27 18:56:25 -03:00
Identity . prototype . joinWallet = function ( opts , cb ) {
2014-09-14 13:52:43 -03:00
preconditions . checkArgument ( opts ) ;
preconditions . checkArgument ( opts . secret ) ;
2014-09-08 10:46:57 -03:00
preconditions . checkArgument ( cb ) ;
2014-08-20 18:00:33 -04:00
var self = this ;
2014-09-14 13:52:43 -03:00
var decodedSecret = this . decodeSecret ( opts . secret ) ;
2014-09-10 14:01:10 -07:00
if ( ! decodedSecret || ! decodedSecret . networkName || ! decodedSecret . pubKey ) {
2014-09-10 11:12:28 -07:00
return cb ( 'badSecret' ) ;
}
2014-06-16 15:51:19 -03:00
2014-08-20 18:00:33 -04:00
var privOpts = {
2014-09-09 15:30:49 -07:00
networkName : decodedSecret . networkName ,
2014-08-20 18:00:33 -04:00
} ;
2014-09-14 13:52:43 -03:00
if ( opts . privateHex && opts . privateHex . length > 1 ) {
2014-10-04 11:30:08 -03:00
privOpts . extendedPrivateKeyString = opts . privateHex ;
2014-08-20 18:00:33 -04:00
}
2014-04-20 12:41:28 -03:00
//Create our PrivateK
2014-08-20 18:00:33 -04:00
var privateKey = new PrivateKey ( privOpts ) ;
2014-09-01 12:35:40 -03:00
log . debug ( '\t### PrivateKey Initialized' ) ;
2014-09-18 18:29:00 -03:00
var joinOpts = {
2014-04-24 23:13:55 -03:00
copayerId : privateKey . getId ( ) ,
2014-06-26 08:49:22 -07:00
privkey : privateKey . getIdPriv ( ) ,
2014-09-03 16:51:02 -03:00
key : privateKey . getIdKey ( ) ,
2014-09-09 15:30:49 -07:00
secretNumber : decodedSecret . secretNumber ,
2014-04-24 23:13:55 -03:00
} ;
2014-09-10 11:12:28 -07:00
2014-10-07 18:33:55 -03:00
var joinNetwork = Identity . _newAsync ( this . networkOpts [ decodedSecret . networkName ] ) ;
2014-07-08 15:25:12 -03:00
// This is a hack to reconize if the connection was rejected or the peer wasn't there.
var connectedOnce = false ;
2014-09-10 11:12:28 -07:00
joinNetwork . on ( 'connected' , function ( sender , data ) {
2014-07-08 15:25:12 -03:00
connectedOnce = true ;
} ) ;
2014-09-19 11:15:45 -03:00
joinNetwork . on ( 'connect_error' , function ( ) {
return cb ( 'connectionError' ) ;
} ) ;
2014-09-10 11:12:28 -07:00
joinNetwork . on ( 'serverError' , function ( ) {
2014-07-08 15:25:12 -03:00
return cb ( 'joinError' ) ;
} ) ;
2014-09-18 18:29:00 -03:00
joinNetwork . start ( joinOpts , function ( ) {
joinNetwork . greet ( decodedSecret . pubKey , joinOpts . secretNumber ) ;
2014-09-10 11:12:28 -07:00
joinNetwork . on ( 'data' , function ( sender , data ) {
2014-09-15 14:25:09 -03:00
if ( data . type === 'walletId' && data . opts ) {
2014-10-04 19:52:43 -03:00
if ( ! data . networkName || data . networkName !== decodedSecret . networkName ) {
2014-06-09 21:00:28 -03:00
return cb ( 'badNetwork' ) ;
}
2014-10-04 19:52:43 -03:00
data . opts . networkName = data . networkName ;
2014-06-09 21:00:28 -03:00
2014-09-23 15:24:57 -03:00
var walletOpts = _ . clone ( data . opts ) ;
2014-09-18 18:29:00 -03:00
walletOpts . id = data . walletId ;
2014-10-14 19:49:29 -03:00
walletOpts . network = joinNetwork ;
2014-09-18 18:29:00 -03:00
walletOpts . privateKey = privateKey ;
2014-10-20 09:39:26 -03:00
walletOpts . nickname = opts . nickname || self . profile . getName ( ) ;
2014-10-05 15:59:41 -03:00
if ( opts . password )
walletOpts . password = opts . password ;
2014-09-18 18:29:00 -03:00
2014-09-28 18:38:06 -03:00
self . createWallet ( walletOpts , function ( err , w ) {
2014-09-18 18:29:00 -03:00
if ( w ) {
w . sendWalletReady ( decodedSecret . pubKey ) ;
2014-09-15 14:25:09 -03:00
} else {
if ( ! err ) err = 'walletFull' ;
2014-09-18 18:29:00 -03:00
log . info ( err ) ;
2014-09-15 14:25:09 -03:00
}
return cb ( err , w ) ;
} ) ;
2014-04-20 16:16:09 -03:00
}
2014-04-16 20:58:57 -03:00
} ) ;
} ) ;
} ;
2014-09-27 17:14:49 -03:00
2014-09-26 05:00:43 -03:00
module . exports = Identity ;