FEATURE: Add support for post revisions.

FEATURE: Add support for post revisions.

diff --git a/assets/javascripts/discourse/initializers/hook-decrypt-revision.js.es6 b/assets/javascripts/discourse/initializers/hook-decrypt-revision.js.es6
new file mode 100644
index 0000000..c216d3f
--- /dev/null
+++ b/assets/javascripts/discourse/initializers/hook-decrypt-revision.js.es6
@@ -0,0 +1,57 @@
+import Post from "discourse/models/post";
+import { cookAsync } from "discourse/lib/text";
+import { decrypt } from "discourse/plugins/discourse-encrypt/lib/keys";
+import {
+  ENCRYPT_DISABLED,
+  getEncryptionStatus,
+  getTopicKey,
+  hasTopicKey
+} from "discourse/plugins/discourse-encrypt/lib/discourse";
+
+export default {
+  name: "hook-decrypt-revision",
+
+  initialize(container) {
+    const currentUser = container.lookup("current-user:main");
+    if (getEncryptionStatus(currentUser) === ENCRYPT_DISABLED) {
+      return;
+    }
+
+    Post.reopenClass({
+      loadRevision() {
+        return this._super(...arguments).then(result => {
+          if (!hasTopicKey(result.topic_id)) {
+            return result;
+          }
+
+          const topicKey = getTopicKey(result.topic_id);
+          return Promise.all([
+            topicKey.then(k => decrypt(k, result.raws.previous)),
+            topicKey.then(k => decrypt(k, result.raws.current))
+          ])
+            .then(([previous, current]) =>
+              Promise.all([
+                previous,
+                cookAsync(previous),
+                current,
+                cookAsync(current)
+              ])
+            )
+            .then(([prevRaw, prevCooked, currRaw, currCooked]) => {
+              result.body_changes.side_by_side = `
+                <div class="revision-content">${prevCooked}</div>
+                <div class="revision-content">${currCooked}</div>`;
+              result.body_changes.side_by_side_markdown = `
+                <table class="markdown">
+                  <tr>
+                    <td class="diff-del">${prevRaw}</td>
+                    <td class="diff-ins">${currRaw}</td>
+                  </tr>
+                </table>`;
+              return result;
+            });
+        });
+      }
+    });
+  }
+};
diff --git a/plugin.rb b/plugin.rb
index beabaad..138f368 100644
--- a/plugin.rb
+++ b/plugin.rb
@@ -173,16 +173,6 @@ after_initialize do
   ::Topic.class_eval { prepend TopicExtensions }
 
   module PostExtensions
-    # Hide version (staff) and public version (regular users) because post
-    # revisions will not be decrypted.
-    def version
-      is_encrypted? ? 1 : super
-    end
-
-    def public_version
-      is_encrypted? ? 1 : super
-    end
-
     def is_encrypted?
       !!(topic && topic.is_encrypted?)
     end
@@ -332,6 +322,29 @@ after_initialize do
     scope&.user.present? && object.topic.private_message?
   end
 
+  # +topic_id+ and +raws+
+  #
+  # Topic's ID and previous and current raw values for encrypted topics.
+  #
+  # These values are required by `Post.loadRevision` to decrypt the
+  # ciphertexts and perform client-sided diff.
+
+  add_to_serializer(:post_revision, :topic_id) do
+    post.topic_id
+  end
+
+  add_to_serializer(:post_revision, :include_topic_id?) do
+    post.is_encrypted?
+  end
+
+  add_to_serializer(:post_revision, :raws) do
+    { previous: previous["raw"], current: current["raw"] }
+  end
+
+  add_to_serializer(:post_revision, :include_raws?) do
+    post.is_encrypted?
+  end
+
   DiscourseEncrypt::Engine.routes.draw do
     put  '/encrypt/keys'  => 'encrypt#update_keys'
     get  '/encrypt/user'  => 'encrypt#show_user'

GitHub sha: 3ae5a762