FEATURE: Added mechanism for importing keypair.

FEATURE: Added mechanism for importing keypair.

Follow-up to 8361691.

diff --git a/assets/javascripts/discourse/connectors/user-preferences-account/encrypt.hbs b/assets/javascripts/discourse/connectors/user-preferences-account/encrypt.hbs
index c90d46c..f884490 100644
--- a/assets/javascripts/discourse/connectors/user-preferences-account/encrypt.hbs
+++ b/assets/javascripts/discourse/connectors/user-preferences-account/encrypt.hbs
@@ -60,6 +60,16 @@
                 <p class="text-danger">{{i18n passphraseStatus}}</p>
               {{/if}}
               <p>
+                <label>
+                {{input type="checkbox" checked=importKey}}
+                {{i18n "encrypt.preferences.import_key"}}
+                </label>
+              </p>
+              {{#if importKey}}
+                {{{i18n 'encrypt.preferences.notice_import'}}}
+                {{textarea class="imported-keypair" value=key}}
+              {{/if}}
+              <p>
                 {{d-button class="btn-primary" icon="lock" action=(action "enableEncrypt") disabled=(or passphraseStatus inProgress) label="encrypt.preferences.enable"}}
                 {{d-button action=(action "hidePassphraseInput") disabled=inProgress label="cancel"}}
               </p>
diff --git a/assets/javascripts/discourse/connectors/user-preferences-account/encrypt.js.es6 b/assets/javascripts/discourse/connectors/user-preferences-account/encrypt.js.es6
index c161c7a..bcdd9a0 100644
--- a/assets/javascripts/discourse/connectors/user-preferences-account/encrypt.js.es6
+++ b/assets/javascripts/discourse/connectors/user-preferences-account/encrypt.js.es6
@@ -16,6 +16,11 @@ import {
   deleteIndexedDb
 } from "discourse/plugins/discourse-encrypt/lib/keys_db";
 import { hideComponentIfDisabled } from "discourse/plugins/discourse-encrypt/lib/discourse";
+import {
+  PACKED_KEY_HEADER,
+  PACKED_KEY_SEPARATOR,
+  PACKED_KEY_FOOTER
+} from "discourse/plugins/discourse-encrypt/lib/discourse";
 
 // TODO: I believe this should get into core.
 // Handlebars offers `if` but no other helpers for conditions, which eventually
@@ -47,6 +52,10 @@ export default {
         isEncryptEnabled: false,
         /** @var Whether the encryption is active on this device. */
         isEncryptActive: false,
+        /** @var Whether it is an import operation. */
+        importKey: false,
+        /** @var Key to be imported .*/
+        key: "",
         // TOOD: Check out if there is a way to define functions like this in
         //       the `export default` scope.
         willDestroyElement() {
@@ -104,10 +113,29 @@ export default {
     enableEncrypt() {
       this.set("inProgress", true);
 
-      // 1. Generate key pair.
-      generateKeyPair()
-        // 2. a. Export public key to string.
-        // 2. b. Export private key to a string (using passphrase).
+      // 1. Generate new key pair or import existing one.
+      let keyPairPromise;
+      if (this.get("importKey")) {
+        const str = (this.get("key") || PACKED_KEY_SEPARATOR)
+          .replace(PACKED_KEY_HEADER, "")
+          .replace(PACKED_KEY_FOOTER, "")
+          .split(PACKED_KEY_SEPARATOR);
+
+        const publicStr = str[0].split(/\s+/).map(x => x.trim()).join("");
+        const privateStr = str[1].split(/\s+/).map(x => x.trim()).join("");
+        console.log("importing key", publicStr, privateStr);
+
+        keyPairPromise = Promise.all([
+          importPublicKey(publicStr),
+          importPublicKey(privateStr, ["decrypt", "unwrapKey"])
+        ]);
+      } else {
+        keyPairPromise = generateKeyPair();
+      }
+
+      // 2. a. Export public key to string.
+      // 2. b. Export private key to a string (using passphrase).
+      keyPairPromise
         .then(keyPair => {
           const [publicKey, privateKey] = keyPair;
 
@@ -162,7 +190,9 @@ export default {
           this.setProperties({
             inProgress: false,
             isEncryptEnabled: true,
-            isEncryptActive: true
+            isEncryptActive: true,
+            importKey: false,
+            key: ""
           });
         })
 
@@ -274,4 +304,4 @@ export default {
       showModal("export-keypair");
     }
   }
-};
+};
\ No newline at end of file
diff --git a/assets/javascripts/lib/keys.js.es6 b/assets/javascripts/lib/keys.js.es6
index cc50a89..519981b 100644
--- a/assets/javascripts/lib/keys.js.es6
+++ b/assets/javascripts/lib/keys.js.es6
@@ -59,10 +59,11 @@ export function exportPublicKey(publicKey) {
  * Imports a public key.
  *
  * @param publicKey
+ * @param usages
  *
  * @return Ember.RSVP.Promise<CryptoKey>
  */
-export function importPublicKey(publicKey) {
+export function importPublicKey(publicKey, usages) {
   return new Ember.RSVP.Promise((resolve, reject) => {
     window.crypto.subtle
       .importKey(
@@ -70,7 +71,7 @@ export function importPublicKey(publicKey) {
         JSON.parse(bufferToString(base64ToBuffer(publicKey))),
         { name: "RSA-OAEP", hash: { name: "SHA-256" } },
         true,
-        ["encrypt", "wrapKey"]
+        usages ? usages : ["encrypt", "wrapKey"]
       )
       .then(resolve, reject);
   });
diff --git a/assets/stylesheets/common/encrypt.scss b/assets/stylesheets/common/encrypt.scss
index a73643c..d2698e2 100644
--- a/assets/stylesheets/common/encrypt.scss
+++ b/assets/stylesheets/common/encrypt.scss
@@ -1,4 +1,5 @@
-pre.exported-keypair {
+pre.exported-keypair, textarea.imported-keypair {
+  font-family: Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace, serif;
   font-size: 0.75rem;
   max-height: 300px;
 }
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index dce9930..132dfa0 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -32,12 +32,16 @@ en:
         passphrase_mismatch: "The two passphrases you entered do not match."
         passphrase_invalid: "The passphrase you entered is incorrect."
 
+        import_key: "I already have an encryption key."
+
         notice_enable: |
           <p>In order to enable encryption, you must choose a passphrase.</p>
           <p>Forgetting this passphrase will lead to the loss of all encrypted messages.</p>
           <p>After you enabled encryption, you must activate encryption on all other devices entering the same passphrase.</p>
         notice_active: |
           <p>Please enter the encryption passphrase you used on other devices.<p>
+        notice_import: |
+          <p>Please paste the encryption key you previously you previously exported.</p>
 
         activate: "Activate Encrypted Messages"
         deactivate: "Deactive Encryption on this Device"

GitHub sha: 3d40fb5c

1 Like