DEV: Use better names for initializers and files

DEV: Use better names for initializers and files

diff --git a/assets/javascripts/discourse/controllers/generate-paper-key.js b/assets/javascripts/discourse/controllers/generate-paper-key.js
index 016ee54..d4349c3 100644
--- a/assets/javascripts/discourse/controllers/generate-paper-key.js
+++ b/assets/javascripts/discourse/controllers/generate-paper-key.js
@@ -1,7 +1,7 @@
 import { ajax } from "discourse/lib/ajax";
 import ModalFunctionality from "discourse/mixins/modal-functionality";
 import { getIdentity } from "discourse/plugins/discourse-encrypt/lib/discourse";
-import { generatePaperKey } from "discourse/plugins/discourse-encrypt/lib/paper_key";
+import { generatePaperKey } from "discourse/plugins/discourse-encrypt/lib/paper-key";
 import { exportIdentity } from "discourse/plugins/discourse-encrypt/lib/protocol";
 
 export default Ember.Controller.extend(ModalFunctionality, {
diff --git a/assets/javascripts/discourse/initializers/decrypt-post-revision.js b/assets/javascripts/discourse/initializers/decrypt-post-revision.js
new file mode 100644
index 0000000..09b6fa0
--- /dev/null
+++ b/assets/javascripts/discourse/initializers/decrypt-post-revision.js
@@ -0,0 +1,59 @@
+import { cookAsync } from "discourse/lib/text";
+import Post from "discourse/models/post";
+import {
+  ENCRYPT_ACTIVE,
+  getEncryptionStatus,
+  getTopicKey,
+  hasTopicKey,
+} from "discourse/plugins/discourse-encrypt/lib/discourse";
+import { decrypt } from "discourse/plugins/discourse-encrypt/lib/protocol";
+import { Promise } from "rsvp";
+
+export default {
+  name: "decrypt-post-revisions",
+
+  initialize(container) {
+    const currentUser = container.lookup("current-user:main");
+    const siteSettings = container.lookup("site-settings:main");
+    if (getEncryptionStatus(currentUser, siteSettings) !== ENCRYPT_ACTIVE) {
+      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.raw,
+                cookAsync(previous.raw),
+                current.raw,
+                cookAsync(current.raw),
+              ])
+            )
+            .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/assets/javascripts/discourse/initializers/decrypt-posts.js b/assets/javascripts/discourse/initializers/decrypt-posts.js
new file mode 100644
index 0000000..5f44dea
--- /dev/null
+++ b/assets/javascripts/discourse/initializers/decrypt-posts.js
@@ -0,0 +1,479 @@
+import { iconHTML, iconNode } from "discourse-common/lib/icon-library";
+import { renderSpinner } from "discourse/helpers/loading-spinner";
+import { ajax } from "discourse/lib/ajax";
+import lightbox from "discourse/lib/lightbox";
+import {
+  fetchUnseenHashtags,
+  linkSeenHashtags,
+} from "discourse/lib/link-hashtags";
+import {
+  fetchUnseenMentions,
+  linkSeenMentions,
+} from "discourse/lib/link-mentions";
+import { loadOneboxes } from "discourse/lib/load-oneboxes";
+import { withPluginApi } from "discourse/lib/plugin-api";
+import showModal from "discourse/lib/show-modal";
+import { cookAsync } from "discourse/lib/text";
+import { markdownNameFromFileName } from "discourse/lib/uploads";
+import { base64ToBuffer } from "discourse/plugins/discourse-encrypt/lib/base64";
+import DebouncedQueue from "discourse/plugins/discourse-encrypt/lib/debounced-queue";
+import {
+  ENCRYPT_DISABLED,
+  getEncryptionStatus,
+  getIdentity,
+  getTopicKey,
+  getUserIdentities,
+  hasTopicKey,
+  hasTopicTitle,
+} from "discourse/plugins/discourse-encrypt/lib/discourse";
+import {
+  decrypt,
+  verify,
+} from "discourse/plugins/discourse-encrypt/lib/protocol";
+import { downloadEncryptedFile } from "discourse/plugins/discourse-encrypt/lib/uploads";
+import I18n from "I18n";
+import { ATTACHMENT_CSS_CLASS } from "pretty-text/engines/discourse-markdown-it";
+import {
+  MISSING,
+  lookupCachedUploadUrl,
+  lookupUncachedUploadUrls,
+} from "pretty-text/upload-short-url";
+import { Promise } from "rsvp";
+
+/*
+ * Debounced queues for fetching information about user identities, mentions,
+ * hashtags and short upload URLs from the server.
+ */
+
+let userIdentitiesQueues;
+let mentionsQueues = [];
+let hashtagsQueue;
+let shortUrlsQueue;
+
+function checkMetadata(attrs, expected) {
+  const actual = {
+    user_id: attrs.user_id,
+    user_name: attrs.username,
+    created_at: attrs.created_at,
+    updated_at: attrs.updated_at,
+    topic_id: attrs.topicId,
+    post_id: attrs.id,
+    post_number: attrs.post_number,
+  };
+
+  const diff = [];
+  Object.keys(expected).forEach((attr) => {
+    if (
+      attr === "raw" ||
+      attr === "signed_by_id" ||
+      attr === "signed_by_name" ||
+      // Check user_id only if username matches, so it does not report
+      // username and user_id.
+      (attr === "user_id" && attrs.user_name !== expected.user_name)
+    ) {
+      return;
+    }
+
+    let a = actual[attr];
+    let b = expected[attr];
+    let isDifferent = a !== b;
+
+    if (attr === "created_at" || attr === "updated_at") {
+      a = new Date(a);
+      b = new Date(b);
+      isDifferent = Math.abs(a - b) >= 5000; // Account for time skew.
+    }
+
+    if (isDifferent) {
+      diff.push({ attr, actual: a, expected: b });
+    }
+  });
+
+  if (expected.signed_by_name !== attrs.username) {
+    diff.push({
+      attr: "signed_by_name",
+      actual: expected.signed_by_name,
+      expected: attrs.username,
+    });
+  }
+
+  // eslint-disable-next-line no-console
+  if (console && console.warn && diff.length > 0) {
+    let warning = "";
+    warning += `Integrity check for post #${attrs.post_number} (post ID ${attrs.id}) failed.\n`;
+    diff.forEach(
+      (d) =>
+        (warning += `  - ${d.attr} - expected "${d.expected}" vs actual "${d.actual}"\n`)
+    );
+
+    // eslint-disable-next-line no-console
+    console.warn(warning);
+  }
+
+  return diff;
+}
+
+function resolveShortUrlElement($el) {
+  const shortUrl = $el.data("orig-src") || $el.data("orig-href");
+  const data = lookupCachedUploadUrl(shortUrl);
+  const url = data.short_path;
+  if (!url) {
+    return;
+  }
+
+  const topicId = $el.closest("[data-topic-id]").data("topic-id");
+  const keyPromise = $el.data("key")
+    ? new Promise((resolve, reject) => {
+        window.crypto.subtle
+          .importKey(
+            "raw",
+            base64ToBuffer($el.data("key")),
+            { name: "AES-GCM", length: 256 },
+            true,
+            ["encrypt", "decrypt"]
+          )
+          .then(resolve, reject);
+      })
+    : getTopicKey(topicId);
+
+  if ($el.prop("tagName") === "A") {
+    $el.removeAttr("data-orig-href");
+    if (url === MISSING) {
+      return;
+    }
+
+    $el.attr("href", url);
+
+    const isEncrypted = $el.data("key") || $el.text().endsWith(".encrypted");
+    if (!isEncrypted || !$el.hasClass(ATTACHMENT_CSS_CLASS)) {
+      return;
+    }
+
+    $el.on("click", () => {
+      downloadEncryptedFile(url, keyPromise, { type: $el.data("type") }).then(
+        (file) => {

[... diff too long, it was truncated ...]

GitHub sha: 8544b1ebb373c955880ed80d82764430f5131691

This commit appears in #116 which was approved by eviltrout. It was merged by udan11.