'use strict';

var openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../../dist/openpgp');

var sinon = require('sinon'),
  chai = require('chai'),
  expect = chai.expect;

var pub_key =
    ['-----BEGIN PGP PUBLIC KEY BLOCK-----',
    'Version: GnuPG v2.0.19 (GNU/Linux)',
    '',
    'mI0EUmEvTgEEANyWtQQMOybQ9JltDqmaX0WnNPJeLILIM36sw6zL0nfTQ5zXSS3+',
    'fIF6P29lJFxpblWk02PSID5zX/DYU9/zjM2xPO8Oa4xo0cVTOTLj++Ri5mtr//f5',
    'GLsIXxFrBJhD/ghFsL3Op0GXOeLJ9A5bsOn8th7x6JucNKuaRB6bQbSPABEBAAG0',
    'JFRlc3QgTWNUZXN0aW5ndG9uIDx0ZXN0QGV4YW1wbGUuY29tPoi5BBMBAgAjBQJS',
    'YS9OAhsvBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQSmNhOk1uQJQwDAP6',
    'AgrTyqkRlJVqz2pb46TfbDM2TDF7o9CBnBzIGoxBhlRwpqALz7z2kxBDmwpQa+ki',
    'Bq3jZN/UosY9y8bhwMAlnrDY9jP1gdCo+H0sD48CdXybblNwaYpwqC8VSpDdTndf',
    '9j2wE/weihGp/DAdy/2kyBCaiOY1sjhUfJ1GogF49rC4jQRSYS9OAQQA6R/PtBFa',
    'JaT4jq10yqASk4sqwVMsc6HcifM5lSdxzExFP74naUMMyEsKHP53QxTF0Grqusag',
    'Qg/ZtgT0CN1HUM152y7ACOdp1giKjpMzOTQClqCoclyvWOFB+L/SwGEIJf7LSCEr',
    'woBuJifJc8xAVr0XX0JthoW+uP91eTQ3XpsAEQEAAYkBPQQYAQIACQUCUmEvTgIb',
    'LgCoCRBKY2E6TW5AlJ0gBBkBAgAGBQJSYS9OAAoJEOCE90RsICyXuqIEANmmiRCA',
    'SF7YK7PvFkieJNwzeK0V3F2lGX+uu6Y3Q/Zxdtwc4xR+me/CSBmsURyXTO29OWhP',
    'GLszPH9zSJU9BdDi6v0yNprmFPX/1Ng0Abn/sCkwetvjxC1YIvTLFwtUL/7v6NS2',
    'bZpsUxRTg9+cSrMWWSNjiY9qUKajm1tuzPDZXAUEAMNmAN3xXN/Kjyvj2OK2ck0X',
    'W748sl/tc3qiKPMJ+0AkMF7Pjhmh9nxqE9+QCEl7qinFqqBLjuzgUhBU4QlwX1GD',
    'AtNTq6ihLMD5v1d82ZC7tNatdlDMGWnIdvEMCv2GZcuIqDQ9rXWs49e7tq1NncLY',
    'hz3tYjKhoFTKEIq3y3Pp',
    '=h/aX',
    '-----END PGP PUBLIC KEY BLOCK-----'].join('\n');

var priv_key =
    ['-----BEGIN PGP PRIVATE KEY BLOCK-----',
    'Version: GnuPG v2.0.19 (GNU/Linux)',
    '',
    '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',
    '=lw5e',
    '-----END PGP PRIVATE KEY BLOCK-----'].join('\n');

var passphrase = 'hello world';
var plaintext = 'short message\nnext line\n한국어/조선말';
var password1 = 'I am a password';
var password2 = 'I am another password';

describe('OpenPGP.js public api tests', function() {

  describe('initWorker, getWorker, destroyWorker - unit tests', function() {
    afterEach(function() {
      openpgp.destroyWorker(); // cleanup worker in case of failure
    });

    it('should work', function() {
      var workerStub = {
        postMessage: function() {}
      };
      openpgp.initWorker({
        worker: workerStub
      });
      expect(openpgp.getWorker()).to.exist;
      openpgp.destroyWorker();
      expect(openpgp.getWorker()).to.not.exist;
    });
  });

  describe('generateKey - unit tests', function() {
    var keyGenStub, keyObjStub, getWebCryptoStub;

    beforeEach(function() {
      keyObjStub = {
        armor: function() {
          return 'priv_key';
        },
        toPublic: function() {
          return {
            armor: function() {
              return 'pub_key';
            }
          };
        }
      };
      keyGenStub = sinon.stub(openpgp.key, 'generate');
      keyGenStub.returns(resolves(keyObjStub));
      getWebCryptoStub = sinon.stub(openpgp.util, 'getWebCrypto');
    });

    afterEach(function() {
      keyGenStub.restore();
      openpgp.destroyWorker();
      getWebCryptoStub.restore();
    });

    it('should fail for invalid user name', function() {
      var opt = {
        userIds: [{ name: {}, email: 'text@example.com' }]
      };
      var test = openpgp.generateKey.bind(null, opt);
      expect(test).to.throw(/Invalid user id format/);
    });

    it('should fail for invalid user email address', function() {
      var opt = {
        userIds: [{ name: 'Test User', email: 'textexample.com' }]
      };
      var test = openpgp.generateKey.bind(null, opt);
      expect(test).to.throw(/Invalid user id format/);
    });

    it('should fail for invalid user email address', function() {
      var opt = {
        userIds: [{ name: 'Test User', email: 'text@examplecom' }]
      };
      var test = openpgp.generateKey.bind(null, opt);
      expect(test).to.throw(/Invalid user id format/);
    });

    it('should fail for invalid string user id', function() {
      var opt = {
        userIds: ['Test User text@example.com>']
      };
      var test = openpgp.generateKey.bind(null, opt);
      expect(test).to.throw(/Invalid user id format/);
    });

    it('should fail for invalid single string user id', function() {
      var opt = {
        userIds: 'Test User text@example.com>'
      };
      var test = openpgp.generateKey.bind(null, opt);
      expect(test).to.throw(/Invalid user id format/);
    });

    it('should work for valid single string user id', function(done) {
      var opt = {
        userIds: 'Test User <text@example.com>'
      };
      openpgp.generateKey(opt).then(function() { done(); });
    });

    it('should work for valid string user id', function(done) {
      var opt = {
        userIds: ['Test User <text@example.com>']
      };
      openpgp.generateKey(opt).then(function() { done(); });
    });

    it('should work for valid single user id hash', function(done) {
      var opt = {
        userIds: { name: 'Test User', email: 'text@example.com' }
      };
      openpgp.generateKey(opt).then(function() { done(); });
    });

    it('should work for valid single user id hash', function(done) {
      var opt = {
        userIds: [{ name: 'Test User', email: 'text@example.com' }]
      };
      openpgp.generateKey(opt).then(function() { done(); });
    });

    it('should work for an empty name', function(done) {
      var opt = {
        userIds: { email: 'text@example.com' }
      };
      openpgp.generateKey(opt).then(function() { done(); });
    });

    it('should work for an empty email address', function(done) {
      var opt = {
        userIds: { name: 'Test User' }
      };
      openpgp.generateKey(opt).then(function() { done(); });
    });

    it('should have default params set', function(done) {
      var opt = {
        userIds: { name: 'Test User', email: 'text@example.com' },
        passphrase: 'secret',
        unlocked: true
      };
      openpgp.generateKey(opt).then(function(newKey) {
        expect(keyGenStub.withArgs({
          userIds: ['Test User <text@example.com>'],
          passphrase: 'secret',
          numBits: 2048,
          unlocked: true
        }).calledOnce).to.be.true;
        expect(newKey.key).to.exist;
        expect(newKey.privateKeyArmored).to.exist;
        expect(newKey.publicKeyArmored).to.exist;
        done();
      });
    });

    it('should work for no params', function(done) {
      openpgp.generateKey().then(function(newKey) {
        expect(keyGenStub.withArgs({
          userIds: [],
          passphrase: undefined,
          numBits: 2048,
          unlocked: false
        }).calledOnce).to.be.true;
        expect(newKey.key).to.exist;
        done();
      });
    });

    it('should delegate to async proxy', function() {
      var workerStub = {
        postMessage: function() {}
      };
      openpgp.initWorker({
        worker: workerStub
      });
      var proxyGenStub = sinon.stub(openpgp.getWorker(), 'delegate');
      getWebCryptoStub.returns();

      openpgp.generateKey();
      expect(proxyGenStub.calledOnce).to.be.true;
      expect(keyGenStub.calledOnce).to.be.false;
    });

    it('should delegate to async proxy after web crypto failure', function(done) {
      var workerStub = {
        postMessage: function() {}
      };
      openpgp.initWorker({
        worker: workerStub
      });
      var proxyGenStub = sinon.stub(openpgp.getWorker(), 'delegate').returns(resolves('proxy_key'));
      getWebCryptoStub.returns({});
      keyGenStub.returns(rejects(new Error('Native webcrypto keygen failed on purpose :)')));

      openpgp.generateKey().then(function(newKey) {
        expect(keyGenStub.calledOnce).to.be.true;
        expect(proxyGenStub.calledOnce).to.be.true;
        expect(newKey).to.equal('proxy_key');
        done();
      });
    });
  });

  describe('generateKey - integration tests', function() {
    var useNativeVal;

    beforeEach(function() {
      useNativeVal = openpgp.config.useNative;
    });

    afterEach(function() {
      openpgp.config.useNative = useNativeVal;
      openpgp.destroyWorker();
    });

    it('should work in JS (without worker)', function(done) {
      openpgp.config.useNative = false;
      openpgp.destroyWorker();
      var opt = {
        userIds: [{ name: 'Test User', email: 'text@example.com' }],
        numBits: 512
      };

      openpgp.generateKey(opt).then(function(newKey) {
        expect(newKey.key.getUserIds()[0]).to.equal('Test User <text@example.com>');
        expect(newKey.privateKeyArmored).to.exist;
        expect(newKey.publicKeyArmored).to.exist;
        done();
      });
    });

    it('should work in JS (with worker)', function(done) {
      openpgp.config.useNative = false;
      openpgp.initWorker({ path:'../dist/openpgp.worker.js' });
      var opt = {
        userIds: [{ name: 'Test User', email: 'text@example.com' }],
        numBits: 512
      };

      openpgp.generateKey(opt).then(function(newKey) {
        expect(newKey.key.getUserIds()[0]).to.equal('Test User <text@example.com>');
        expect(newKey.privateKeyArmored).to.exist;
        expect(newKey.publicKeyArmored).to.exist;
        done();
      });
    });

    it('should work in with native crypto', function(done) {
      openpgp.config.useNative = true;
      var opt = {
        userIds: [{ name: 'Test User', email: 'text@example.com' }],
        numBits: 512
      };
      if (openpgp.util.getWebCrypto()) { opt.numBits = 2048; } // webkit webcrypto accepts minimum 2048 bit keys

      openpgp.generateKey(opt).then(function(newKey) {
        expect(newKey.key.getUserIds()[0]).to.equal('Test User <text@example.com>');
        expect(newKey.privateKeyArmored).to.exist;
        expect(newKey.publicKeyArmored).to.exist;
        done();
      });
    });
  });

  describe('encrypt, decrypt, sign, verify - integration tests', function() {
    var privateKey, publicKey, zeroCopyVal;

    beforeEach(function() {
      publicKey = openpgp.key.readArmored(pub_key);
      expect(publicKey.keys).to.have.length(1);
      expect(publicKey.err).to.not.exist;
      privateKey = openpgp.key.readArmored(priv_key);
      expect(privateKey.keys).to.have.length(1);
      expect(privateKey.err).to.not.exist;
      zeroCopyVal = openpgp.config.zeroCopy;
    });

    afterEach(function() {
      openpgp.config.zeroCopy = zeroCopyVal;
    });

    it('Decrypting key with wrong passphrase returns false', function () {
      expect(privateKey.keys[0].decrypt('wrong passphrase')).to.be.false;
    });

    it('Decrypting key with correct passphrase returns true', function () {
      expect(privateKey.keys[0].decrypt(passphrase)).to.be.true;
    });

    describe('without Worker', tests);
    describe('with Worker', function() {
      before(function() {
        openpgp.initWorker({ path:'../dist/openpgp.worker.js' });
      });

      tests();

      after(function() {
        openpgp.destroyWorker(); // cleanup worker in case of failure
      });
    });

    function tests() {
      it('Calling decrypt with not decrypted key leads to exception', function (done) {
        var encOpt = {
          data: plaintext,
          publicKeys: publicKey.keys,
        };
        var decOpt = {
          privateKey: privateKey.keys[0]
        };
        openpgp.encrypt(encOpt).then(function(encrypted) {
          decOpt.message = openpgp.message.readArmored(encrypted.data);
          return openpgp.decrypt(decOpt);
        }).catch(function(error) {
          expect(error.message).to.match(/not decrypted/);
          done();
        });
      });

      describe('decryptKey', function() {
        it('should work for correct passphrase', function(done) {
          openpgp.decryptKey({
            privateKey: privateKey.keys[0],
            passphrase: passphrase
          }).then(function(unlocked){
            expect(unlocked.key.primaryKey.getKeyId().toHex()).to.equal(privateKey.keys[0].primaryKey.getKeyId().toHex());
            expect(unlocked.key.primaryKey.isDecrypted).to.be.true;
            done();
          });
        });

        it('should fail for incorrect passphrase', function(done) {
          openpgp.decryptKey({
            privateKey: privateKey.keys[0],
            passphrase: 'incorrect'
          }).catch(function(error){
            expect(error.message).to.match(/Invalid passphrase/);
            done();
          });
        });
      });

      describe('with pgp key pair', function() {
        var wrong_pubkey = '-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n' +
          'Version: OpenPGP.js v0.9.0\r\n' +
          'Comment: Hoodiecrow - https://hoodiecrow.com\r\n' +
          '\r\n' +
          'xk0EUlhMvAEB/2MZtCUOAYvyLFjDp3OBMGn3Ev8FwjzyPbIF0JUw+L7y2XR5\r\n' +
          'RVGvbK88unV3cU/1tOYdNsXI6pSp/Ztjyv7vbBUAEQEAAc0pV2hpdGVvdXQg\r\n' +
          'VXNlciA8d2hpdGVvdXQudGVzdEB0LW9ubGluZS5kZT7CXAQQAQgAEAUCUlhM\r\n' +
          'vQkQ9vYOm0LN/0wAAAW4Af9C+kYW1AvNWmivdtr0M0iYCUjM9DNOQH1fcvXq\r\n' +
          'IiN602mWrkd8jcEzLsW5IUNzVPLhrFIuKyBDTpLnC07Loce1\r\n' +
          '=6XMW\r\n' +
          '-----END PGP PUBLIC KEY BLOCK-----\r\n\r\n';

        beforeEach(function() {
          expect(privateKey.keys[0].decrypt(passphrase)).to.be.true;
        });

        it('should encrypt then decrypt', function(done) {
          var encOpt = {
            data: plaintext,
            publicKeys: publicKey.keys,
          };
          var decOpt = {
            privateKey: privateKey.keys[0]
          };
          openpgp.encrypt(encOpt).then(function(encrypted) {
            decOpt.message = openpgp.message.readArmored(encrypted.data);
            return openpgp.decrypt(decOpt);
          }).then(function(decrypted) {
            expect(decrypted.data).to.equal(plaintext);
            expect(decrypted.signatures).to.not.exist;
            done();
          });
        });

        it('should encrypt/sign and decrypt/verify', function(done) {
          var encOpt = {
            data: plaintext,
            publicKeys: publicKey.keys,
            privateKeys: privateKey.keys
          };
          var decOpt = {
            privateKey: privateKey.keys[0],
            publicKeys: publicKey.keys
          };
          openpgp.encrypt(encOpt).then(function(encrypted) {
            decOpt.message = openpgp.message.readArmored(encrypted.data);
            return openpgp.decrypt(decOpt);
          }).then(function(decrypted) {
            expect(decrypted.data).to.equal(plaintext);
            expect(decrypted.signatures[0].valid).to.be.true;
            expect(decrypted.signatures[0].keyid.toHex()).to.equal(privateKey.keys[0].primaryKey.getKeyId().toHex());
            done();
          });
        });

        it('should fail to verify decrypted data with wrong public pgp key', function(done) {
          var encOpt = {
            data: plaintext,
            publicKeys: publicKey.keys,
            privateKeys: privateKey.keys
          };
          var decOpt = {
            privateKey: privateKey.keys[0],
            publicKeys: openpgp.key.readArmored(wrong_pubkey).keys
          };
          openpgp.encrypt(encOpt).then(function(encrypted) {
            decOpt.message = openpgp.message.readArmored(encrypted.data);
            return openpgp.decrypt(decOpt);
          }).then(function(decrypted) {
            expect(decrypted.data).to.equal(plaintext);
            expect(decrypted.signatures[0].valid).to.be.null;
            expect(decrypted.signatures[0].keyid.toHex()).to.equal(privateKey.keys[0].primaryKey.getKeyId().toHex());
            done();
          });
        });

        it('should sign and verify cleartext data', function(done) {
          var signOpt = {
            data: plaintext,
            privateKeys: privateKey.keys
          };
          var verifyOpt = {
            publicKeys: publicKey.keys
          };
          openpgp.sign(signOpt).then(function(signed) {
            verifyOpt.message = openpgp.cleartext.readArmored(signed.data);
            return openpgp.verify(verifyOpt);
          }).then(function(verified) {
            expect(verified.data).to.equal(plaintext);
            expect(verified.signatures[0].valid).to.be.true;
            expect(verified.signatures[0].keyid.toHex()).to.equal(privateKey.keys[0].primaryKey.getKeyId().toHex());
            done();
          });
        });

        it('should sign and fail to verify cleartext data with wrong public pgp key', function(done) {
          var signOpt = {
            data: plaintext,
            privateKeys: privateKey.keys
          };
          var verifyOpt = {
            publicKeys: openpgp.key.readArmored(wrong_pubkey).keys
          };
          openpgp.sign(signOpt).then(function(signed) {
            verifyOpt.message = openpgp.cleartext.readArmored(signed.data);
            return openpgp.verify(verifyOpt);
          }).then(function(verified) {
            expect(verified.data).to.equal(plaintext);
            expect(verified.signatures[0].valid).to.be.null;
            expect(verified.signatures[0].keyid.toHex()).to.equal(privateKey.keys[0].primaryKey.getKeyId().toHex());
            done();
          });
        });

        it('should sign and verify cleartext data and not armor', function(done) {
          var signOpt = {
            data: plaintext,
            privateKeys: privateKey.keys,
            armor: false
          };
          var verifyOpt = {
            publicKeys: publicKey.keys
          };
          openpgp.sign(signOpt).then(function(signed) {
            verifyOpt.message = signed.message;
            return openpgp.verify(verifyOpt);
          }).then(function(verified) {
            expect(verified.data).to.equal(plaintext);
            expect(verified.signatures[0].valid).to.be.true;
            expect(verified.signatures[0].keyid.toHex()).to.equal(privateKey.keys[0].primaryKey.getKeyId().toHex());
            done();
          });
        });
      });

      describe('with symmetric entryption', function() {
        it('should encrypt and decrypt with one password', function(done) {
          var encOpt = {
            data: plaintext,
            passwords: password1
          };
          var decOpt = {
            password: password1
          };
          openpgp.encrypt(encOpt).then(function(encrypted) {
            decOpt.message = openpgp.message.readArmored(encrypted.data);
            return openpgp.decrypt(decOpt);
          }).then(function(decrypted) {
            expect(decrypted.data).to.equal(plaintext);
            done();
          });
        });

        it('should encrypt and decrypt with two passwords', function(done) {
          var encOpt = {
            data: plaintext,
            passwords: [password1, password2]
          };
          var decOpt = {
            password: password2
          };
          openpgp.encrypt(encOpt).then(function(encrypted) {
            decOpt.message = openpgp.message.readArmored(encrypted.data);
            return openpgp.decrypt(decOpt);
          }).then(function(decrypted) {
            expect(decrypted.data).to.equal(plaintext);
            done();
          });
        });

        it('should encrypt and decrypt with password and not ascii armor', function(done) {
          var encOpt = {
            data: plaintext,
            passwords: password1,
            armor: false
          };
          var decOpt = {
            password: password1
          };
          openpgp.encrypt(encOpt).then(function(encrypted) {
            decOpt.message = encrypted.message;
            return openpgp.decrypt(decOpt);
          }).then(function(decrypted) {
            expect(decrypted.data).to.equal(plaintext);
            done();
          });
        });

        it('should encrypt and decrypt with one session key', function(done) {
          var encOpt = {
            data: plaintext,
            passwords: password1
          };
          var decOpt = {
            sessionKey: password1
          };
          openpgp.encrypt(encOpt).then(function(encrypted) {
            decOpt.message = openpgp.message.readArmored(encrypted.data);
            return openpgp.decrypt(decOpt);
          }).then(function(decrypted) {
            expect(decrypted.data).to.equal(plaintext);
            done();
          });
        });

        it('should encrypt and decrypt with two session keys and not ascii armor', function(done) {
          var encOpt = {
            data: plaintext,
            passwords: [password1, password2],
            armor: false
          };
          var decOpt = {
            sessionKey: password2
          };
          openpgp.encrypt(encOpt).then(function(encrypted) {
            decOpt.message = encrypted.message;
            return openpgp.decrypt(decOpt);
          }).then(function(decrypted) {
            expect(decrypted.data).to.equal(plaintext);
            done();
          });
        });

        it('should encrypt and decrypt with binary data and transferable objects', function(done) {
          openpgp.config.zeroCopy = true; // activate transferable objects
          var encOpt = {
            data: new Uint8Array([0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01]),
            passwords: [password1, password2],
            armor: false
          };
          var decOpt = {
            sessionKey: password2,
            format: 'binary'
          };
          openpgp.encrypt(encOpt).then(function(encrypted) {
            decOpt.message = encrypted.message;
            return openpgp.decrypt(decOpt);
          }).then(function(decrypted) {
            if (openpgp.getWorker()) {
              expect(encOpt.data.byteLength).to.equal(0); // transfered buffer should be empty
            }
            expect(decrypted.data).to.deep.equal(new Uint8Array([0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01]));
            done();
          });
        });
      });
    }

  });

});