From bde27d94811b223657d1d7f381c634028d9eae70 Mon Sep 17 00:00:00 2001
From: Mikunj <mikunj@live.com.au>
Date: Fri, 5 Jun 2020 12:06:18 +1000
Subject: [PATCH 1/6] Fix create closed group overflow on small screen

---
 stylesheets/_session.scss | 1 +
 1 file changed, 1 insertion(+)

diff --git a/stylesheets/_session.scss b/stylesheets/_session.scss
index 150ffb7ee..49e979638 100644
--- a/stylesheets/_session.scss
+++ b/stylesheets/_session.scss
@@ -1589,6 +1589,7 @@ input {
   @media (max-height: 804px) {
     &__container {
       overflow-y: visible;
+      max-height: none;
     }
   }
 }

From 1076c5545fb3bb8b7e216faec7c4f8375e311886 Mon Sep 17 00:00:00 2001
From: Mikunj <mikunj@live.com.au>
Date: Thu, 16 Jul 2020 16:14:21 +1000
Subject: [PATCH 2/6] Change version to 1.1.0

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 5d40d6722..06f52c276 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
   "name": "session-messenger-desktop",
   "productName": "Session",
   "description": "Private messaging from your desktop",
-  "version": "2.0.0",
+  "version": "1.1.0",
   "license": "GPL-3.0",
   "author": {
     "name": "Loki Project",

From 0c7cc7d24f0c19cd2229328406618d0697c99266 Mon Sep 17 00:00:00 2001
From: Audric Ackermann <audric@loki.network>
Date: Thu, 29 Oct 2020 13:33:26 +1100
Subject: [PATCH 3/6] cleanup account_manager unused code

---
 js/background.js                           |   4 -
 libtextsecure/account_manager.js           | 114 ---------------------
 libtextsecure/test/account_manager_test.js |  16 ---
 test/crypto_test.js                        |  37 -------
 4 files changed, 171 deletions(-)

diff --git a/js/background.js b/js/background.js
index b89561c0e..1fc6005ac 100644
--- a/js/background.js
+++ b/js/background.js
@@ -221,10 +221,6 @@
   // start a background worker for ecc
   textsecure.startWorker('js/libsignal-protocol-worker.js');
   Whisper.KeyChangeListener.init(textsecure.storage.protocol);
-  textsecure.storage.protocol.on('removePreKey', () => {
-    getAccountManager().refreshPreKeys();
-  });
-
   let messageReceiver;
   window.getSocketStatus = () => {
     if (messageReceiver) {
diff --git a/libtextsecure/account_manager.js b/libtextsecure/account_manager.js
index b30778621..c0e081087 100644
--- a/libtextsecure/account_manager.js
+++ b/libtextsecure/account_manager.js
@@ -7,7 +7,6 @@
   lokiFileServerAPI,
   mnemonic,
   btoa,
-  Signal,
   getString,
   Event,
   dcodeIO,
@@ -48,60 +47,6 @@
   AccountManager.prototype = new textsecure.EventTarget();
   AccountManager.prototype.extend({
     constructor: AccountManager,
-    requestVoiceVerification(number) {},
-    requestSMSVerification(number) {},
-    async encryptDeviceName(name, providedIdentityKey) {
-      if (!name) {
-        return null;
-      }
-      const identityKey =
-        providedIdentityKey ||
-        (await textsecure.storage.protocol.getIdentityKeyPair());
-      if (!identityKey) {
-        throw new Error(
-          'Identity key was not provided and is not in database!'
-        );
-      }
-      const encrypted = await Signal.Crypto.encryptDeviceName(
-        name,
-        identityKey.pubKey
-      );
-
-      const proto = new textsecure.protobuf.DeviceName();
-      proto.ephemeralPublic = encrypted.ephemeralPublic;
-      proto.syntheticIv = encrypted.syntheticIv;
-      proto.ciphertext = encrypted.ciphertext;
-
-      const arrayBuffer = proto.encode().toArrayBuffer();
-      return Signal.Crypto.arrayBufferToBase64(arrayBuffer);
-    },
-    async decryptDeviceName(base64) {
-      const identityKey = await textsecure.storage.protocol.getIdentityKeyPair();
-
-      const arrayBuffer = Signal.Crypto.base64ToArrayBuffer(base64);
-      const proto = textsecure.protobuf.DeviceName.decode(arrayBuffer);
-      const encrypted = {
-        ephemeralPublic: proto.ephemeralPublic.toArrayBuffer(),
-        syntheticIv: proto.syntheticIv.toArrayBuffer(),
-        ciphertext: proto.ciphertext.toArrayBuffer(),
-      };
-
-      const name = await Signal.Crypto.decryptDeviceName(
-        encrypted,
-        identityKey.privKey
-      );
-
-      return name;
-    },
-    async maybeUpdateDeviceName() {
-      throw new Error('Signal method called: maybeUpdateDeviceName');
-    },
-    async deviceNameIsEncrypted() {
-      await textsecure.storage.user.setDeviceNameEncrypted();
-    },
-    async maybeDeleteSignalingKey() {
-      throw new Error('Signal method called: maybeDeleteSignalingKey');
-    },
     registerSingleDevice(mnemonic, mnemonicLanguage, profileName) {
       const createAccount = this.createAccount.bind(this);
       const clearSessionsAndPreKeys = this.clearSessionsAndPreKeys.bind(this);
@@ -140,65 +85,6 @@
         )
       );
     },
-    async addMockContact(doSave) {
-      if (doSave === undefined) {
-        // eslint-disable-next-line no-param-reassign
-        doSave = true;
-      }
-      const keyPair = await libsignal.KeyHelper.generateIdentityKeyPair();
-      const pubKey = StringView.arrayBufferToHex(keyPair.pubKey);
-      const privKey = StringView.arrayBufferToHex(keyPair.privKey);
-      log.info(`contact pubkey ${pubKey}`);
-      log.info(`contact privkey ${privKey}`);
-      const signedKeyId = Math.floor(Math.random() * 1000 + 1);
-
-      const signedPreKey = await libsignal.KeyHelper.generateSignedPreKey(
-        keyPair,
-        signedKeyId
-      );
-      const contactSignedPreKey = {
-        publicKey: signedPreKey.keyPair.pubKey,
-        signature: signedPreKey.signature,
-        keyId: signedPreKey.keyId,
-      };
-      if (doSave) {
-        await textsecure.storage.protocol.storeContactSignedPreKey(
-          pubKey,
-          contactSignedPreKey
-        );
-      } else {
-        log.info(
-          `signed prekey:
-          ${StringView.arrayBufferToHex(contactSignedPreKey.publicKey)}`
-        );
-        log.info(
-          `signature:
-          ${StringView.arrayBufferToHex(contactSignedPreKey.signature)}`
-        );
-      }
-
-      for (let keyId = 0; keyId < 10; keyId += 1) {
-        const preKey = await libsignal.KeyHelper.generatePreKey(keyId);
-        if (doSave) {
-          await textsecure.storage.protocol.storeContactPreKey(pubKey, {
-            publicKey: preKey.keyPair.pubKey,
-            keyId,
-          });
-        } else {
-          log.info(
-            `signed prekey:
-            ${StringView.arrayBufferToHex(preKey.keyPair.pubKey)}`
-          );
-        }
-      }
-      log.info('Added mock contact');
-    },
-    registerSecondDevice(setProvisioningUrl, confirmNumber, progressCallback) {
-      throw new Error(
-        'account_manager: registerSecondDevice has not been implemented!'
-      );
-    },
-    refreshPreKeys() {},
     rotateSignedPreKey() {
       return this.queueTask(() => {
         const signedKeyId = textsecure.storage.get('signedKeyId', 1);
diff --git a/libtextsecure/test/account_manager_test.js b/libtextsecure/test/account_manager_test.js
index 7f70ea08d..f73425db6 100644
--- a/libtextsecure/test/account_manager_test.js
+++ b/libtextsecure/test/account_manager_test.js
@@ -29,22 +29,6 @@ describe('AccountManager', () => {
       window.textsecure.storage.protocol = originalProtocolStorage;
     });
 
-    describe('encrypted device name', () => {
-      it('roundtrips', async () => {
-        const deviceName = 'v2.5.0 on Ubunto 20.04';
-        const encrypted = await accountManager.encryptDeviceName(deviceName);
-        assert.strictEqual(typeof encrypted, 'string');
-        const decrypted = await accountManager.decryptDeviceName(encrypted);
-
-        assert.strictEqual(decrypted, deviceName);
-      });
-
-      it('handles null deviceName', async () => {
-        const encrypted = await accountManager.encryptDeviceName(null);
-        assert.strictEqual(encrypted, null);
-      });
-    });
-
     it('keeps three confirmed keys even if over a week old', () => {
       const now = Date.now();
       signedPreKeys = [
diff --git a/test/crypto_test.js b/test/crypto_test.js
index 44eb42877..a5a6b0ac1 100644
--- a/test/crypto_test.js
+++ b/test/crypto_test.js
@@ -110,43 +110,6 @@ describe('Crypto', () => {
     });
   });
 
-  describe('encrypted device name', () => {
-    it('roundtrips', async () => {
-      const deviceName = 'v1.19.0 on Windows 10';
-      const identityKey = await libsignal.KeyHelper.generateIdentityKeyPair();
-
-      const encrypted = await Signal.Crypto.encryptDeviceName(
-        deviceName,
-        identityKey.pubKey
-      );
-      const decrypted = await Signal.Crypto.decryptDeviceName(
-        encrypted,
-        identityKey.privKey
-      );
-
-      assert.strictEqual(decrypted, deviceName);
-    });
-
-    it('fails if iv is changed', async () => {
-      const deviceName = 'v1.19.0 on Windows 10';
-      const identityKey = await libsignal.KeyHelper.generateIdentityKeyPair();
-
-      const encrypted = await Signal.Crypto.encryptDeviceName(
-        deviceName,
-        identityKey.pubKey
-      );
-      encrypted.syntheticIv = Signal.Crypto.getRandomBytes(16);
-      try {
-        await Signal.Crypto.decryptDeviceName(encrypted, identityKey.privKey);
-      } catch (error) {
-        assert.strictEqual(
-          error.message,
-          'decryptDeviceName: synthetic IV did not match'
-        );
-      }
-    });
-  });
-
   describe('attachment encryption', () => {
     it('roundtrips', async () => {
       const staticKeyPair = await libsignal.KeyHelper.generateIdentityKeyPair();

From 6dc3582a1d60b147eeac88ddd01b0056dbe578ba Mon Sep 17 00:00:00 2001
From: Audric Ackermann <audric@loki.network>
Date: Thu, 29 Oct 2020 13:33:51 +1100
Subject: [PATCH 4/6] move to new identity key mechanism
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

now we do as followed:
• Generate 16 bytes of random data
• Add 16 bytes of zeros
• Use the 16 bytes of random + 16 bytes of zeros to generate an ED25519 key pair
• Convert the ED25519 key pair to an X25519 key pair

All of this is happening with libsodiumm called over IPC
---
 libtextsecure/account_manager.js           |  4 +--
 main.js                                    | 36 ++++++++++++++++++++++
 preload.js                                 | 14 +++++++--
 ts/components/session/RegistrationTabs.tsx |  8 ++---
 ts/window.d.ts                             |  1 +
 5 files changed, 54 insertions(+), 9 deletions(-)

diff --git a/libtextsecure/account_manager.js b/libtextsecure/account_manager.js
index c0e081087..80c53c824 100644
--- a/libtextsecure/account_manager.js
+++ b/libtextsecure/account_manager.js
@@ -60,11 +60,11 @@
           // handle shorter than 32 bytes seeds
           const privKeyHexLength = 32 * 2;
           if (seedHex.length !== privKeyHexLength) {
-            seedHex = seedHex.concat(seedHex);
+            seedHex = seedHex.concat('0'.repeat(32));
             seedHex = seedHex.substring(0, privKeyHexLength);
           }
           const seed = dcodeIO.ByteBuffer.wrap(seedHex, 'hex').toArrayBuffer();
-          return libsignal.Curve.async.createKeyPair(seed);
+          return window.sessionGenerateKeyPair(seed);
         };
       } else {
         generateKeypair = libsignal.KeyHelper.generateIdentityKeyPair;
diff --git a/main.js b/main.js
index 4bebeafc9..6ee2f53fb 100644
--- a/main.js
+++ b/main.js
@@ -1178,6 +1178,42 @@ ipc.on('decrypt-lns-entry', (event, lnsName, ciphertext) => {
   decryptLns(event, lnsName, ciphertext);
 });
 
+async function sessionGenerateKeyPair(event, seed) {
+  const sodium = await getSodium();
+
+  try {
+    const ed25519KeyPair = sodium.crypto_sign_seed_keypair(
+      new Uint8Array(seed)
+    );
+    const x25519PublicKey = sodium.crypto_sign_ed25519_pk_to_curve25519(
+      ed25519KeyPair.publicKey
+    );
+    // prepend version byte (coming from `processKeys(raw_keys)`)
+    const origPub = new Uint8Array(x25519PublicKey);
+    const prependedX25519PublicKey = new Uint8Array(33);
+    prependedX25519PublicKey.set(origPub, 1);
+    prependedX25519PublicKey[0] = 5;
+    const x25519SecretKey = sodium.crypto_sign_ed25519_sk_to_curve25519(
+      ed25519KeyPair.privateKey
+    );
+
+    // prepend with 05 the public key
+    const x25519KeyPair = {
+      pubKey: prependedX25519PublicKey.buffer,
+      privKey: x25519SecretKey.buffer,
+    };
+
+    // null as first parameter to indivate no error
+    event.reply('generate-keypair-seed-response', null, x25519KeyPair);
+  } catch (err) {
+    event.reply('generate-keypair-seed-response', err);
+  }
+}
+
+ipc.on('generate-keypair-seed', (event, seed) => {
+  sessionGenerateKeyPair(event, seed);
+});
+
 ipc.on('set-auto-update-setting', (event, enabled) => {
   userConfig.set('autoUpdate', !!enabled);
 
diff --git a/preload.js b/preload.js
index 86eca4ccc..e2e5d2e3c 100644
--- a/preload.js
+++ b/preload.js
@@ -118,7 +118,7 @@ const localeMessages = ipc.sendSync('locale-data');
 
 window.blake2b = input =>
   new Promise((resolve, reject) => {
-    ipc.once('blake2b-digest-response', (event, error, res) => {
+    ipc.once('blake2b-digest-response', (_, error, res) => {
       // eslint-disable-next-line no-unused-expressions
       error ? reject(error) : resolve(res);
     });
@@ -128,7 +128,7 @@ window.blake2b = input =>
 
 window.decryptLnsEntry = (key, value) =>
   new Promise((resolve, reject) => {
-    ipc.once('decrypt-lns-response', (event, error, res) => {
+    ipc.once('decrypt-lns-response', (_, error, res) => {
       // eslint-disable-next-line no-unused-expressions
       error ? reject(error) : resolve(res);
     });
@@ -136,6 +136,16 @@ window.decryptLnsEntry = (key, value) =>
     ipc.send('decrypt-lns-entry', key, value);
   });
 
+window.sessionGenerateKeyPair = seed =>
+  new Promise((resolve, reject) => {
+    ipc.once('generate-keypair-seed-response', (_, error, res) => {
+      // eslint-disable-next-line no-unused-expressions
+      error ? reject(error) : resolve(res);
+    });
+
+    ipc.send('generate-keypair-seed', seed);
+  });
+
 window.updateZoomFactor = () => {
   const zoomFactor = window.getSettingValue('zoom-factor-setting') || 100;
   window.setZoomFactor(zoomFactor / 100);
diff --git a/ts/components/session/RegistrationTabs.tsx b/ts/components/session/RegistrationTabs.tsx
index ec81b6605..e688f2bde 100644
--- a/ts/components/session/RegistrationTabs.tsx
+++ b/ts/components/session/RegistrationTabs.tsx
@@ -174,14 +174,14 @@ export class RegistrationTabs extends React.Component<{}, State> {
       // handle shorter than 32 bytes seeds
       const privKeyHexLength = 32 * 2;
       if (seedHex.length !== privKeyHexLength) {
-        seedHex = seedHex.concat(seedHex);
+        seedHex = seedHex.concat('0'.repeat(32));
         seedHex = seedHex.substring(0, privKeyHexLength);
       }
       const seed = window.dcodeIO.ByteBuffer.wrap(
         seedHex,
         'hex'
       ).toArrayBuffer();
-      const keyPair = await window.libsignal.Curve.async.createKeyPair(seed);
+      const keyPair = await window.sessionGenerateKeyPair(seed);
       const hexGeneratedPubKey = StringUtils.decode(keyPair.pubKey, 'hex');
 
       this.setState({
@@ -297,9 +297,7 @@ export class RegistrationTabs extends React.Component<{}, State> {
 
             {this.renderRegistrationContent()}
             <SessionButton
-              onClick={() => {
-                this.onCompleteSignUpClick();
-              }}
+              onClick={this.onCompleteSignUpClick}
               buttonType={SessionButtonType.Brand}
               buttonColor={SessionButtonColor.Green}
               text={window.i18n('getStarted')}
diff --git a/ts/window.d.ts b/ts/window.d.ts
index 51387b0d3..9e9429512 100644
--- a/ts/window.d.ts
+++ b/ts/window.d.ts
@@ -99,5 +99,6 @@ declare global {
     GroupBuffer: any;
     SwarmPolling: SwarmPolling;
     owsDesktopApp: any;
+    sessionGenerateKeyPair: (seed: ArrayBuffer) => Promise<{ pubKey: ArrayBufferLike;  privKey: ArrayBufferLike; }>;
   }
 }

From 43b335406f77a06c3fe42820d460470a4a97c607 Mon Sep 17 00:00:00 2001
From: Audric Ackermann <audric@loki.network>
Date: Fri, 30 Oct 2020 09:38:27 +1100
Subject: [PATCH 5/6] store the ed25519KeyPair temp key too on storage under
 'identityKey'

---
 main.js        | 1 +
 ts/window.d.ts | 4 +++-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/main.js b/main.js
index 6ee2f53fb..2c94986f5 100644
--- a/main.js
+++ b/main.js
@@ -1201,6 +1201,7 @@ async function sessionGenerateKeyPair(event, seed) {
     const x25519KeyPair = {
       pubKey: prependedX25519PublicKey.buffer,
       privKey: x25519SecretKey.buffer,
+      ed25519KeyPair,
     };
 
     // null as first parameter to indivate no error
diff --git a/ts/window.d.ts b/ts/window.d.ts
index 9e9429512..b0e549396 100644
--- a/ts/window.d.ts
+++ b/ts/window.d.ts
@@ -99,6 +99,8 @@ declare global {
     GroupBuffer: any;
     SwarmPolling: SwarmPolling;
     owsDesktopApp: any;
-    sessionGenerateKeyPair: (seed: ArrayBuffer) => Promise<{ pubKey: ArrayBufferLike;  privKey: ArrayBufferLike; }>;
+    sessionGenerateKeyPair: (
+      seed: ArrayBuffer
+    ) => Promise<{ pubKey: ArrayBufferLike; privKey: ArrayBufferLike }>;
   }
 }

From e5ef8dc2547e75ab0d38a32091351874cf1110c6 Mon Sep 17 00:00:00 2001
From: Audric Ackermann <audric@loki.network>
Date: Tue, 10 Nov 2020 15:17:03 +1100
Subject: [PATCH 6/6] Bump to v1.4.1

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 4626af6d0..0f19dade5 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
   "name": "session-messenger-desktop",
   "productName": "Session",
   "description": "Private messaging from your desktop",
-  "version": "1.4.0",
+  "version": "1.4.1",
   "license": "GPL-3.0",
   "author": {
     "name": "Loki Project",