FEATURE: Automatically upgrade identities to v1 when activating.

FEATURE: Automatically upgrade identities to v1 when activating.

This will destroy all passphrases and keep only the current one. This should not be a problem when migrating from v0 to v1, but might be in the future.

diff --git a/assets/javascripts/lib/discourse.js.es6 b/assets/javascripts/lib/discourse.js.es6
index 7c04e17..ecc8fe7 100644
--- a/assets/javascripts/lib/discourse.js.es6
+++ b/assets/javascripts/lib/discourse.js.es6
@@ -6,6 +6,8 @@ import {
 } from "discourse/plugins/discourse-encrypt/lib/database";
 import {
   decrypt,
+  exportIdentity,
+  generateIdentity,
   importIdentity,
   importKey
 } from "discourse/plugins/discourse-encrypt/lib/protocol";
@@ -261,7 +263,7 @@ export function activateEncrypt(currentUser, passphrase) {
   // Importing from a paper key.
   const spacePos = passphrase.indexOf(" ");
   const firstWord = spacePos && passphrase.substr(0, spacePos);
-  const label = "paper_" + firstWord;
+  const label = "paper_" + firstWord.toLowerCase();
   if (privateKeys[label]) {
     promise = promise.catch(() =>
       importIdentity(privateKeys[label], passphrase)
@@ -282,5 +284,56 @@ export function activateEncrypt(currentUser, passphrase) {
     );
   }
 
-  return promise.then(identity => saveDbIdentity(identity));
+  return promise
+    .then(identity => upgradeIdentity(currentUser, passphrase, identity))
+    .then(identity => saveDbIdentity(identity));
+}
+
+/**
+ * Upgrade a user's identity to new version.
+ *
+ * @param {User} currentUser
+ * @param {string} passphrase
+ * @param {Object} oldIdentity
+ *
+ * @return {Object}
+ */
+function upgradeIdentity(currentUser, passphrase, oldIdentity) {
+  // Upgrade identity to version 1 by creating a v1 identity, but replacing
+  // encryption keys with old ones.
+  if (oldIdentity.version === 0) {
+    return generateIdentity(1)
+      .then(identity => {
+        identity.encryptPublic = oldIdentity.encryptPublic;
+        identity.encryptPrivate = oldIdentity.encryptPrivate;
+        return identity;
+      })
+      .then(identity => {
+        const savePromise = exportIdentity(identity, passphrase).then(
+          exported => {
+            const exportedPrivate = JSON.stringify({
+              passphrase: exported.private
+            });
+
+            currentUser.set("custom_fields.encrypt_public", exported.public);
+            currentUser.set("custom_fields.encrypt_private", exportedPrivate);
+
+            return ajax("/encrypt/keys", {
+              type: "PUT",
+              data: {
+                public: exported.public,
+                private: exportedPrivate,
+                overwrite: true
+              }
+            });
+          }
+        );
+
+        return Ember.RSVP.Promise.all([identity, savePromise]).then(
+          result => result[0]
+        );
+      });
+  }
+
+  return oldIdentity;
 }
diff --git a/assets/javascripts/lib/protocol.js.es6 b/assets/javascripts/lib/protocol.js.es6
index 7fc47e1..76f727c 100644
--- a/assets/javascripts/lib/protocol.js.es6
+++ b/assets/javascripts/lib/protocol.js.es6
@@ -33,8 +33,8 @@ export const ENCRYPT_PROTOCOL_VERSION = 1;
  *
  * @return {Promise}
  */
-export function generateIdentity() {
-  const version = ENCRYPT_PROTOCOL_VERSION;
+export function generateIdentity(version) {
+  version = version || ENCRYPT_PROTOCOL_VERSION;
 
   let promise;
   if (version === 0) {
diff --git a/plugin.rb b/plugin.rb
index 99ef8e5..ad658e4 100644
--- a/plugin.rb
+++ b/plugin.rb
@@ -44,6 +44,7 @@ after_initialize do
       # +public+::    Serialized public identity
       # +private+::   Serialized private identity
       # +label+::     Private identity label
+      # +overwrite+:: Force overwrite of public and private identities
       #
       # Returns status code 200 on success or 409 if user already has an
       # identity and public identities mismatch.
@@ -54,7 +55,7 @@ after_initialize do
 
         # Check if encryption is already enabled (but not changing passphrase).
         old_identity = current_user.custom_fields['encrypt_public']
-        if old_identity && old_identity != public_identity
+        if params[:overwrite].blank? && old_identity && old_identity != public_identity
           return render_json_error(I18n.t('encrypt.enabled_already'), status: 409)
         end

GitHub sha: 7d37e259