{"size": 11618, "ext": "js", "max_stars_repo_path": "test/Identity.js", "max_stars_repo_name": "tomtt/copay", "max_stars_repo_stars_event_min_datetime": "2018-02-18T20:48:01.000Z", "max_stars_repo_stars_event_max_datetime": "2018-02-18T20:48:01.000Z", "max_issues_repo_path": "test/Identity.js", "max_issues_repo_name": "tomtt/copay", "max_issues_repo_issues_event_min_datetime": null, "max_issues_repo_issues_event_max_datetime": null, "max_forks_repo_path": "test/Identity.js", "max_forks_repo_name": "tomtt/copay", "max_forks_repo_forks_event_min_datetime": null, "max_forks_repo_forks_event_max_datetime": null}
{"max_stars_count": 1, "max_issues_count": null, "max_forks_count": null, "avg_line_length": 28.0628019324, "max_line_length": 135, "alphanum_fraction": 0.5964021346}
'use strict';


var _ = require('lodash');
var chai = chai || require('chai');
var sinon = sinon || require('sinon');
var should = chai.should();
var PluginManager = require('../js/models/PluginManager');
var Insight = require('../js/models/Insight');

var Identity = copay.Identity;
var Wallet = copay.Wallet;
var Passphrase = copay.Passphrase;

var FakeBlockchain = require('./mocks/FakeBlockchain');

var PERSISTED_PROPERTIES = (copay.Wallet || require('../js/models/Wallet')).PERSISTED_PROPERTIES;

function assertObjectEqual(a, b) {
  PERSISTED_PROPERTIES.forEach(function(k) {
    if (a[k] && b[k]) {
      _.omit(a[k], 'name').should.be.deep.equal(b[k], k + ' differs');
    }
  })
}


describe('Identity model', function() {
  var wallet;
  var email = 'hola@hola.com';
  var password = 'password';
  var blockchain;

  var config = {
    walletDefaults: {
      requiredCopayers: 3,
      totalCopayers: 5,
      spendUnconfirmed: 1,
      reconnectDelay: 100,

    },
    blockchain: {
      host: 'test.insight.is',
      port: 80,
      schema: 'https'
    },
    networkName: 'testnet',
    passphrase: {
      iterations: 100,
      storageSalt: 'mjuBtGybi/4=',
    },

    // network layer config
    network: {
      testnet: {
        url: 'https://test-insight.bitpay.com:443'
      },
      livenet: {
        url: 'https://insight.bitpay.com:443'
      },
    },
    version: '0.0.1'
  };

  function getDefaultParams() {
    var params = _.cloneDeep(config);
    _.extend(params, {
      email: email,
      password: password
    });
    params.storage = sinon.stub();
    params.storage.setCredentials = sinon.stub();
    params.storage.getItem = sinon.stub();
    params.storage.setItem = sinon.stub();
    params.storage.setItem.onFirstCall().callsArgWith(2, null);
    params.storage.setItem.onSecondCall().callsArgWith(2, null);
    return params;
  }

  function getNewWallet(args) {
    var w = sinon.stub();
    w.getId = sinon.stub().returns('wid');
    w.getStorageKey = sinon.stub().returns('wkey');
    w.toObj = sinon.stub().returns({
      obj: 1
    });
    w.getName = sinon.stub().returns('name');
    w.on = sinon.stub();
    w.netStart = sinon.stub();
    w.args = args;
    return w;
  }


  var walletClass = function(args) {
    return getNewWallet(args);
  };

  function createIdentity(done) {

    // TODO (eordano): Change this to proper dependency injection
    var blockchain = new FakeBlockchain(config.blockchain);
    var params = getDefaultParams();
    blockchain.on = sinon.stub();
    Wallet._newInsight = sinon.stub().returns(blockchain);

    return {
      blockchain: blockchain,
      storage: params.storage,
      wallet: wallet,
      params: params
    };
  };

  describe('new Identity()', function() {
    it('returns an identity', function() {
      var iden = new Identity(getDefaultParams());
      should.exist(iden);
      iden.walletDefaults.should.deep.equal(config.walletDefaults);
    });
  });

  describe('Identity.create()', function() {
    it('should create and store identity', function() {
      var args = createIdentity();
      args.blockchain.on = sinon.stub();
      sinon.stub(Identity.prototype, 'store').yields(null);
      Identity.create(args.params, function(err, iden) {
        should.not.exist(err);
        should.exist(iden);
        should.exist(iden.wallets);
        Identity.prototype.store.calledOnce.should.be.true;
      });
    });
  });

  describe('#open', function(done) {
    it.skip('should return last focused wallet', function(done) {
      var wallets = [{
        id: 'wallet1',
        store: sinon.stub().yields(null),
        netStart: sinon.stub(),
      }, {
        id: 'wallet2',
        store: sinon.stub().yields(null),
        netStart: sinon.stub(),
      }, {
        id: 'wallet3',
        store: sinon.stub().yields(null),
        netStart: sinon.stub(),
      }];
      var args = createIdentity();
      Identity.create(args.params, function(err, identity) {
        // TODO: Add checks for what is this testing
        done();
      });
    });
  });

  describe.skip('#storeWallet', function() {
    // TODO test storeWallet
  });


  describe('#createWallet', function() {
    var iden = null;
    var args = null;
    beforeEach(function() {
      args = createIdentity();
      args.params.noWallets = true;
      var old = Identity.prototype.createWallet;
      Identity.create(args.params, function(err, res) {
        iden = res;
      });
    });
    it('should be able to create wallets with given pk', function(done) {
      var priv = 'tprv8ZgxMBicQKsPdEqHcA7RjJTayxA3gSSqeRTttS1JjVbgmNDZdSk9EHZK5pc52GY5xFmwcakmUeKWUDzGoMLGAhrfr5b3MovMUZUTPqisL2m';
      args.storage.setItem = sinon.stub();
      args.storage.setItem.onFirstCall().callsArg(2);
      args.storage.setItem.onSecondCall().callsArg(2);
      should.exist(walletClass, 'check walletClass stub');
      iden.createWallet({
        privateKeyHex: priv,
        walletClass: walletClass,
      }, function(err, w) {
        should.not.exist(err);
        w.args.privateKey.toObj().extendedPrivateKeyString.should.equal(priv);
        done();
      });
    });

    it('should be able to create wallets with random pk', function(done) {
      args.storage.setItem = sinon.stub();
      args.storage.setItem.onCall(0).callsArg(2);
      args.storage.setItem.onCall(1).callsArg(2);
      args.storage.setItem.onCall(2).callsArg(2);
      args.storage.setItem.onCall(3).callsArg(2);
      iden.createWallet({
        walletClass: walletClass,
      }, function(err, w1) {
        should.exist(w1);

        iden.createWallet({
          walletClass: walletClass,
        }, function(err, w2) {
          should.exist(w2);
          w2.args.privateKey.toObj().extendedPrivateKeyString.should.not.equal(
            w1.args.privateKey.toObj().extendedPrivateKeyString
          ); + done();
        });
      });
    });
  });

  describe('#retrieveWalletFromStorage', function() {


    it('should return wallet', function(done) {
      var args = createIdentity();
      args.storage.getItem.onFirstCall().callsArgWith(1, null, '{"wallet": "fakeData"}');
      var backup = Wallet.fromUntrustedObj;
      args.params.noWallets = true;

      sinon.stub().returns(args.wallet);

      var opts = {
        importWallet: sinon.stub().returns(getNewWallet()),
      };

      Identity.create(args.params, function(err, iden) {
        iden.retrieveWalletFromStorage('dummy', opts, function(err, wallet) {
          should.not.exist(err);
          opts.importWallet.calledOnce.should.equal(true);
          should.exist(wallet);
          done();
        });
      });
    });
  });

  describe('#importWallet', function() {
    it('should import a wallet, call the right encryption functions', function(done) {
      var args = createIdentity();
      args.storage.getItem.onFirstCall().callsArgWith(1, null, '{"wallet": "fakeData"}');
      var backup = Wallet.fromUntrustedObj;
      args.params.noWallets = true;
      sinon.stub().returns(args.wallet);

      var fakeCrypto = {
        kdf: sinon.stub().returns('passphrase'),
        decrypt: sinon.stub().returns('{"walletId":123}'),
      };

      var opts = {
        importWallet: sinon.stub().returns(getNewWallet()),
        cryptoUtil: fakeCrypto,
      };

      Identity.create(args.params, function(err, iden) {
        sinon.stub(iden, 'importWalletFromObj').yields(null);
        iden.importEncryptedWallet(123, 'password', opts, function(err) {
          should.not.exist(err);
          fakeCrypto.kdf.getCall(0).args[0].should.equal('password');
          fakeCrypto.decrypt.getCall(0).args[0].should.equal('passphrase');
          fakeCrypto.decrypt.getCall(0).args[1].should.equal(123);
          done();
        });
      });
    });
  });



  describe('#export', function() {

  });

  describe('#import', function() {

  });

  /**
   * TODO (eordano): Move this to a different test file
   *
  describe('#pluginManager', function() {
    it('should create a new PluginManager object', function() {
      var pm = new PluginManager({plugins: { FakeLocalStorage: true }, pluginsPath: '../../test/mocks/'});
      should.exist(pm);
    });
  });

  describe('#Insight', function() {
    it('should parse a uri', function() {
      var uri = Insight.setCompleteUrl('http://someurl.bitpay.com:443');
      should.exist(uri);
    });
  });
   */

  describe('#joinWallet', function() {
    var opts = {
      secret: '8WtTuiFTkhP5ao7AF2QErSwV39Cbur6pdMebKzQXFqL59RscXM',
      nickname: 'test',
      password: 'pass'
    };
    var iden = null;
    var args = null;
    var net = null;

    beforeEach(function() {
      args = createIdentity();
      args.params.Async = net = sinon.stub();

      net.cleanUp = sinon.spy();
      net.on = sinon.stub();
      net.start = sinon.spy();
      var old = Identity.prototype.createWallet;
      Identity.create(args.params, function(err, res) {
        iden = res;
      });
    });

    it('should yield bad network error', function(done) {
      var net = sinon.stub();

      net.greet = sinon.stub();
      net.cleanUp = sinon.stub();
      net.start = sinon.stub().yields(null);
      net.on = sinon.stub();
      net.on.withArgs('data').yields('senderId', {
        type: 'walletId',
        networkName: 'aWeirdNetworkName',
        opts: {},
      });

      opts.privHex = undefined;
      opts.Async = net;
      iden.joinWallet(opts, function(err, w) {
        err.should.equal('badNetwork');
        done();
      });
    });


    it('should callback with a join error in case of a problem', function(done) {
      opts.privHex = undefined;
      var net = sinon.stub();
      net.greet = sinon.stub();
      net.cleanUp = sinon.stub();
      net.start = sinon.stub().yields(null);

      net.on = sinon.stub();
      net.on.withArgs('serverError').yields(null);
      net.on.withArgs('data').yields('senderId', {
        type: 'walletId',
        networkName: iden.networkName,
      });
      opts.Async = net;

      iden.joinWallet(opts, function(err, w) {
        err.should.equal('joinError');
        done();
      });
    });

    it('should return walletFull', function(done) {
      net = sinon.stub();
      net.on = sinon.stub();
      net.start = sinon.stub();
      net.start.onFirstCall().callsArg(1);
      net.greet = sinon.stub();
      iden.createWallet = sinon.stub();
      iden.createWallet.onFirstCall().yields(null, null);
      net.on.withArgs('data').yields('senderId', {
        type: 'walletId',
        networkName: 'testnet',
        opts: {},
      });
      opts.privHex = undefined;
      opts.Async = net;

      iden.joinWallet(opts, function(err, w) {
        err.should.equal('walletFull');
        done();
      });
    });

    it('should accept a priv key as an input', function(done) {
      net = sinon.stub();
      net.on = sinon.stub();
      net.start = sinon.stub();
      net.start.onFirstCall().callsArg(1);
      net.greet = sinon.stub();
      iden.createWallet = sinon.stub();
      var fakeWallet = {
        sendWalletReady: _.noop
      };
      iden.createWallet.onFirstCall().yields(null, fakeWallet);
      net.on.withArgs('data').yields('senderId', {
        type: 'walletId',
        networkName: 'testnet',
        opts: {},
      });

      opts.privHex = 'tprv8ZgxMBicQKsPf7MCvCjnhnr4uiR2Z2gyNC27vgd9KUu98F9mM1tbaRrWMyddVju36GxLbeyntuSadBAttriwGGMWUkRgVmUUCg5nFioGZsd';
      opts.Async = net;
      iden.joinWallet(opts, function(err, w) {
        w.should.equal(fakeWallet);
        done();
      });
    });
  });
});
