// Copyright 2015-2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only

/* global textsecure */

describe('encrypting and decrypting profile data', () => {
  const NAME_PADDED_LENGTH = 53;
  describe('encrypting and decrypting profile names', () => {
    it('pads, encrypts, decrypts, and unpads a short string', () => {
      const name = 'Alice';
      const buffer = dcodeIO.ByteBuffer.wrap(name).toArrayBuffer();
      const key = window.Signal.Crypto.getRandomBytes(32);

      return textsecure.crypto
        .encryptProfileName(buffer, key)
        .then(encrypted => {
          assert(encrypted.byteLength === NAME_PADDED_LENGTH + 16 + 12);
          return textsecure.crypto
            .decryptProfileName(encrypted, key)
            .then(({ given, family }) => {
              assert.strictEqual(family, null);
              assert.strictEqual(
                dcodeIO.ByteBuffer.wrap(given).toString('utf8'),
                name
              );
            });
        });
    });
    it('handles a given name of the max, 53 characters', () => {
      const name = '01234567890123456789012345678901234567890123456789123';
      const buffer = dcodeIO.ByteBuffer.wrap(name).toArrayBuffer();
      const key = window.Signal.Crypto.getRandomBytes(32);

      return textsecure.crypto
        .encryptProfileName(buffer, key)
        .then(encrypted => {
          assert(encrypted.byteLength === NAME_PADDED_LENGTH + 16 + 12);
          return textsecure.crypto
            .decryptProfileName(encrypted, key)
            .then(({ given, family }) => {
              assert.strictEqual(
                dcodeIO.ByteBuffer.wrap(given).toString('utf8'),
                name
              );
              assert.strictEqual(family, null);
            });
        });
    });
    it('handles family/given name of the max, 53 characters', () => {
      const name = '01234567890123456789\u000001234567890123456789012345678912';
      const buffer = dcodeIO.ByteBuffer.wrap(name).toArrayBuffer();
      const key = window.Signal.Crypto.getRandomBytes(32);

      return textsecure.crypto
        .encryptProfileName(buffer, key)
        .then(encrypted => {
          assert(encrypted.byteLength === NAME_PADDED_LENGTH + 16 + 12);
          return textsecure.crypto
            .decryptProfileName(encrypted, key)
            .then(({ given, family }) => {
              assert.strictEqual(
                dcodeIO.ByteBuffer.wrap(given).toString('utf8'),
                '01234567890123456789'
              );
              assert.strictEqual(
                dcodeIO.ByteBuffer.wrap(family).toString('utf8'),
                '01234567890123456789012345678912'
              );
            });
        });
    });
    it('handles a string with family/given name', () => {
      const name = 'Alice\0Jones';
      const buffer = dcodeIO.ByteBuffer.wrap(name).toArrayBuffer();
      const key = window.Signal.Crypto.getRandomBytes(32);

      return textsecure.crypto
        .encryptProfileName(buffer, key)
        .then(encrypted => {
          assert(encrypted.byteLength === NAME_PADDED_LENGTH + 16 + 12);
          return textsecure.crypto
            .decryptProfileName(encrypted, key)
            .then(({ given, family }) => {
              assert.strictEqual(
                dcodeIO.ByteBuffer.wrap(given).toString('utf8'),
                'Alice'
              );
              assert.strictEqual(
                dcodeIO.ByteBuffer.wrap(family).toString('utf8'),
                'Jones'
              );
            });
        });
    });
    it('works for empty string', async () => {
      const name = dcodeIO.ByteBuffer.wrap('').toArrayBuffer();
      const key = window.Signal.Crypto.getRandomBytes(32);

      const encrypted = await textsecure.crypto.encryptProfileName(name, key);
      assert(encrypted.byteLength === NAME_PADDED_LENGTH + 16 + 12);

      const { given, family } = await textsecure.crypto.decryptProfileName(
        encrypted,
        key
      );
      assert.strictEqual(family, null);
      assert.strictEqual(given.byteLength, 0);
      assert.strictEqual(dcodeIO.ByteBuffer.wrap(given).toString('utf8'), '');
    });
  });
  describe('encrypting and decrypting profile avatars', () => {
    it('encrypts and decrypts', () => {
      const buffer = dcodeIO.ByteBuffer.wrap(
        'This is an avatar'
      ).toArrayBuffer();
      const key = window.Signal.Crypto.getRandomBytes(32);

      return textsecure.crypto.encryptProfile(buffer, key).then(encrypted => {
        assert(encrypted.byteLength === buffer.byteLength + 16 + 12);
        return textsecure.crypto
          .decryptProfile(encrypted, key)
          .then(decrypted => {
            assertEqualArrayBuffers(buffer, decrypted);
          });
      });
    });
    it('throws when decrypting with the wrong key', () => {
      const buffer = dcodeIO.ByteBuffer.wrap(
        'This is an avatar'
      ).toArrayBuffer();
      const key = window.Signal.Crypto.getRandomBytes(32);
      const badKey = window.Signal.Crypto.getRandomBytes(32);

      return textsecure.crypto.encryptProfile(buffer, key).then(encrypted => {
        assert(encrypted.byteLength === buffer.byteLength + 16 + 12);
        return textsecure.crypto
          .decryptProfile(encrypted, badKey)
          .catch(error => {
            assert.strictEqual(error.name, 'ProfileDecryptError');
          });
      });
    });
  });
});
