darkwallet/darkwallet

View on GitHub
src/js/model/pockets.js

Summary

Maintainability
C
7 hrs
Test Coverage
'use strict';

define(['bitcoinjs-lib', 'model/pocket/hd', 'model/pocket/multisig', 'model/pocket/readonly'], function(Bitcoin, HdPocket, MultisigPocket, ReadOnlyPocket) {

/**
 * Pocket functionality.
 * @param {Object} store Store for the object.
 * @param {Object} identity Identity for the object.
 * @param {Object} wallet Wallet for the object.
 * @constructor
 */
function Pockets(store, identity, wallet) {
    this.store = store;
    this.wallet = wallet;
    this.registerTypes();
    this.initPockets(store);
}

/**
 * Register all pocket types
 * @private
 */

Pockets.prototype.registerTypes = function() {
    this.pocketTypes = {};
    this.addressTypes = {};
    this.pocketFactories= {};
    this.registerType(HdPocket);
    this.registerType(MultisigPocket);
    this.registerType(ReadOnlyPocket);
}

/**
 * Register a pocket type
 * @private
 */
Pockets.prototype.registerType = function(pocketType) {
    var self = this;
    var name = pocketType.prototype.type;
    this.pocketTypes[name] = pocketType.prototype;
    this.pocketFactories[name] = pocketType;
    pocketType.prototype.types.forEach(function(type) {
        self.addressTypes[type] = pocketType.prototype;
    });
}

/**
 * Initialize store and internal caches for pockets
 * @param {String} store Identity store
 * @return {Object[]} List of pockets
 * @private
 */
Pockets.prototype.initPockets = function(store) {
    var mpks = store.get('mpks') || ((store.get('version') < 5) ? [] : null);
    var pcodes = store.get('pcodes') || ((store.get('version') < 6) ? [] : null);
    this.hdPockets = store.init('pockets', [{ name:'spending', mpk: mpks[0], pcode: pcodes[0] },
                                            { name: 'business', mpk: mpks[1], pcode: pcodes[1] },
                                            { name: 'savings', mpk: mpks[2], pcode: pcodes[2] }]);

    // Init pocket wallets (temporary cache for pockets)
    this.pockets = { 'hd': {}, 'multisig': {}, 'readonly': {} };
    for(var i=0; i< this.hdPockets.length; i++) {
        if (this.hdPockets[i]) {
            this.initPocketWallet(i, 'hd', this.hdPockets[i]);
        }
    }
    return this.hdPockets;
};

/**
 * Create pocket with the given name
 * @param {String} name Name for the new pocket
 */
Pockets.prototype.createPocket = function(name, password) {
    // Raise exception if name exists
    if (this.search('hd', {'name': name})) {
        throw new Error('Pocket with that name already exists!');
    }
    var pocketStore = {'name': name};

    // initialize mpk
    if (this.wallet.store.get('version') > 4) {
        var mpks = this.wallet.store.get('mpks');
        var pcodes = this.wallet.store.get('pcodes');
        if (!mpks[this.hdPockets.length]) {
            var keyStore = this.wallet.store.getPrivateData(password);
            var rootKey = Bitcoin.HDNode.fromBase58(keyStore.privKey);
            mpks[this.hdPockets.length] = rootKey.deriveHardened(this.hdPockets.length).toBase58(false);
        }
        pocketStore.mpk = mpks[this.hdPockets.length];
        if (!pcodes[this.hdPockets.length]) {
            var keyStore = this.wallet.store.getPrivateData(password);
            var pCodeKey = Bitcoin.HDNode.fromBase58(keyStore.pCodeKey);
            pcodes[this.hdPockets.length] = pCodeKey.deriveHardened(this.hdPockets.length).toBase58(false);
        }
        pocketStore.pcode = pcodes[this.hdPockets.length];
 
    }

    // add the pocket
    this.hdPockets.push(pocketStore);
    this.initPocketWallet(this.hdPockets.length-1, 'hd', pocketStore);
    this.store.save();
};

/**
 * Initialize a pockets wallet
 * @param {Object} id Pocket id (can be branch number, multisig address...)
 * @param {String} type The pocket type
 * @param {Object} pocketStore The store for the pocket
 * @private
 */
Pockets.prototype.initPocketWallet = function(id, type, pocketStore) {
    if (this.pockets[type] && this.pocketFactories[type]) {
        pocketStore = pocketStore ? pocketStore : {id: id};
        var PocketFactory = this.pocketFactories[type];
        this.pockets[type][id] = new PocketFactory(pocketStore, this);
    } else {
        console.log("could not create pocket!", type);
    }
    return this.pockets[type][id];
};

/**
 * Search for a pocket
 * @param {String} type The pocket type
 * @param {Object} search Search query, has to be one key: value for now.
 */

Pockets.prototype.search = function(type, search) {
    var label = Object.keys(search)[0];
    var value = search[label];
    var keys = Object.keys(this.pockets[type]);
    for(var i=0; i<keys.length; i++) {
        if (this.pockets[type][keys[i]][label] === value) {
            return this.pockets[type][keys[i]];
        }
    }
}


/**
 * Get an hd pocket by id and type
 * @param {Object} id Pocket id (can be branch number, multisig address...)
 * @param {String} type The pocket type
 * @return {Object} The pocket instance
 */
Pockets.prototype.getPocket = function(id, type) {
    type = type ? type : 'hd';
    return this.pockets[type][id];
};

/**
 * Get the type for a certain address type
 * @return {String} addressType The address type
 */
Pockets.prototype.getPocketType = function(addressType) {
    return this.addressTypes[addressType].type;
};

/**
 * Delete a pocket
 * @param {Object} id Pocket id (can be branch number, multisig address...)
 * @param {String} type The pocket type
 * @throws {Error} When the pocket doesn't exist
 */
Pockets.prototype.deletePocket = function(id, type) {
    type = type ? type : 'hd';
    var pocket = this.pockets[type][id];
    if (pocket) {
        pocket.destroy();
    }
};

/**
 * Get the pocket index for a wallet address
 * @param {Object} walletAddress Address we're looking for. See {@link Wallet#getWalletAddress}.
 * @return {Number|String} The pocket index
 */
Pockets.prototype.getAddressPocketId = function(walletAddress) {
    return this.addressTypes[walletAddress.type].getIndex(walletAddress, this.wallet.store.get('version'));
};

/**
 * Get the pocket for a wallet address
 * @param {Object} walletAddress Address we're looking for. See {@link Wallet#getWalletAddress}.
 * @return {Number|String} The pocket index
 */
Pockets.prototype.getAddressPocket = function(walletAddress) {
    var type = this.getPocketType(walletAddress.type);
    var id = this.addressTypes[walletAddress.type].getIndex(walletAddress, this.wallet.store.get('version'));
    return this.getPocket(id, type);
};


/**
 * Get all pockets of a certain type
 * @param {String} type The pocket type
 */

Pockets.prototype.getPockets = function(type) {
    type = type ? type : 'hd';
    var pockets = this.pockets[type];
    if (!pockets) {
        throw new Error('Unknown address type! {0}|'+ type);
    }
    return pockets;
}

/**
 * Add an address to its pocket
 * @param {Object} walletAddress Address we're adding. See {@link Wallet#getWalletAddress}.
 */
Pockets.prototype.addToPocket = function(walletAddress) {
    var id = this.getAddressPocketId(walletAddress);
    var addressType = this.addressTypes[walletAddress.type];
    if (addressType && addressType.autoCreate && !(this.pockets[addressType.type][id])) {
        this.initPocketWallet(id, addressType.type);
    }
    var pocketBase = this.getPockets(addressType.type);
    pocketBase[id].addToPocket(walletAddress);
};

/**
 * Gets all public addresses for this pocket.
 * @param {Object} id Pocket id (can be branch number, multisig address...)
 * @param {String} type The pocket type
 * @return {Array} An array of strings with the addresses.
 */
Pockets.prototype.getAddresses = function(id, type) {
    type = type ? type : 'hd';
    return this.pockets[type][id].getAddresses();
};

/**
 * Gets the pocket wallet for a pocket
 * @param {Object} id Pocket id (can be pocket index, multisig address...)
 * @param {String} type The pocket type
 * @return {Object} The pocket wallet
 */
Pockets.prototype.getPocketWallet = function(id, type) {
    // Default to multisig or hd for backwards compatibility.
    type = type ? type : (typeof id === 'string') ? 'multisig' : 'hd';
    return this.pockets[type][id].getWallet();
};

return Pockets;
});