DEV: Add tests for creating new encrypted topics

DEV: Add tests for creating new encrypted topics

diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index 2b110c5..7614bda 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -3,6 +3,7 @@ en:
     encrypted_excerpt: "This message is encrypted, please read it in the browser."
     enabled_already: "You have already enabled encrypted messages."
     only_pms: "Only private messages can be encrypted."
+    no_encrypt_keys: "Something went wrong. No encryption keys were included in the payload."
   site_settings:
     encrypt_enabled: "Enable encrypted private messages."
     encrypt_groups: "The name of groups that are able to use encryption (empty means everyone)."
diff --git a/plugin.rb b/plugin.rb
index 08f5550..cc97e80 100644
--- a/plugin.rb
+++ b/plugin.rb
@@ -214,16 +214,20 @@ after_initialize do
   NewPostManager.add_handler do |manager|
     next if !manager.args[:encrypted_raw]
 
+    if !manager.args[:encrypted_keys]
+      result = NewPostResult.new(:created_post, false)
+      result.errors.add(:base, I18n.t('encrypt.no_encrypt_keys'))
+      next result
+    end
+
+    manager.args[:raw] = manager.args[:encrypted_raw]
+
     if encrypted_title = manager.args[:encrypted_title]
       manager.args[:topic_opts] ||= {}
       manager.args[:topic_opts][:custom_fields] ||= {}
       manager.args[:topic_opts][:custom_fields][DiscourseEncrypt::TITLE_CUSTOM_FIELD] = encrypted_title
     end
 
-    if encrypted_raw = manager.args[:encrypted_raw]
-      manager.args[:raw] = encrypted_raw
-    end
-
     result = manager.perform_create_post
     if result.success? && encrypted_keys = manager.args[:encrypted_keys]
       keys = JSON.parse(encrypted_keys)
diff --git a/spec/requests/posts_controller_spec.rb b/spec/requests/posts_controller_spec.rb
new file mode 100644
index 0000000..6fa2266
--- /dev/null
+++ b/spec/requests/posts_controller_spec.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe PostsController do
+  let(:encrypt_post) { Fabricate(:encrypt_post) }
+  let(:user) { Fabricate(:user) }
+  let(:group) { Fabricate(:group) }
+
+  before do
+    sign_in(Fabricate(:admin))
+  end
+
+  context '#create' do
+    it 'works' do
+      post '/posts.json', params: {
+        raw: I18n.t('js.encrypt.encrypted_post'),
+        title: I18n.t('js.encrypt.encrypted_topic_title'),
+        archetype: Archetype.private_message,
+        target_usernames: user.username,
+        draft_key: Draft::NEW_TOPIC,
+        is_encrypted: true,
+        encrypted_title: '1$title',
+        encrypted_raw: encrypt_post.raw,
+        encrypted_keys: "{\"#{user.username}\":\"topickey\"}"
+      }
+
+      expect(response.status).to eq(200)
+    end
+
+    it 'raises an error' do
+      post '/posts.json', params: {
+        raw: I18n.t('js.encrypt.encrypted_post'),
+        title: I18n.t('js.encrypt.encrypted_topic_title'),
+        archetype: Archetype.private_message,
+        target_usernames: user.username,
+        draft_key: Draft::NEW_TOPIC,
+        is_encrypted: true,
+        encrypted_title: '1$title',
+        encrypted_raw: encrypt_post.raw
+      }
+
+      expect(response.status).to eq(422)
+      expect(JSON.parse(response.body)["errors"]).to include(I18n.t("encrypt.no_encrypt_keys"))
+    end
+  end
+end
diff --git a/test/javascripts/acceptance/encrypt-test.js.es6 b/test/javascripts/acceptance/encrypt-test.js.es6
index 405dde3..c2a9f40 100644
--- a/test/javascripts/acceptance/encrypt-test.js.es6
+++ b/test/javascripts/acceptance/encrypt-test.js.es6
@@ -15,6 +15,7 @@ import {
   generateIdentity
 } from "discourse/plugins/discourse-encrypt/lib/protocol";
 import { default as userFixtures } from "fixtures/user_fixtures";
+import { parsePostData } from "helpers/create-pretender";
 import { acceptance, updateCurrentUser } from "helpers/qunit-helpers";
 import selectKit from "helpers/select-kit-helper";
 
@@ -104,8 +105,8 @@ async function setEncryptionStatus(status) {
     await saveDbIdentity(identity);
   }
 
-  // Store key for future use.
-  return (keys[user.username] = identity);
+  keys[user.username] = exported.public;
+  return identity;
 }
 
 /**
@@ -160,7 +161,7 @@ acceptance("Encrypt", {
   pretend(server, helper) {
     server.get("/encrypt/user", request => {
       const response = {};
-      request.queryParams["usernames"].forEach(u => (response[u] = keys[u][2]));
+      request.queryParams["usernames"].forEach(u => (response[u] = keys[u]));
       return helper.response(response);
     });
 
@@ -188,12 +189,44 @@ test("meta: leak checker works", async assert => {
 });
 
 test("posting does not leak plaintext", async assert => {
-  // TODO: Skip this test because OperationError is randomly raised
-  return assert.ok(true);
-
   await setEncryptionStatus(ENCRYPT_ACTIVE);
   globalAssert = assert;
 
+  /* global server */
+  server.get("/u/search/users", () => {
+    return [
+      200,
+      { "Content-Type": "application/json" },
+      {
+        users: [
+          {
+            username: "eviltrout",
+            name: "eviltrout",
+            avatar_template: "/images/avatar.png"
+          }
+        ]
+      }
+    ];
+  });
+
+  server.post("/posts", request => {
+    const body = parsePostData(request.requestBody);
+    assert.equal(body.raw, I18n.t("encrypt.encrypted_post"));
+    assert.equal(body.title, I18n.t("encrypt.encrypted_topic_title"));
+    assert.equal(body.archetype, "private_message");
+    assert.equal(body.target_usernames, "eviltrout");
+    assert.equal(body.draft_key, "new_topic");
+    assert.equal(body.is_encrypted, "true");
+    assert.ok(body.encrypted_title.startsWith("1$"));
+    assert.ok(body.encrypted_raw.startsWith("1$"));
+    assert.ok(JSON.parse(body.encrypted_keys).eviltrout);
+    return [
+      200,
+      { "Content-Type": "application/json" },
+      { action: "create_post", post: { topic_id: 34 } }
+    ];
+  });
+
   const composerActions = selectKit(".composer-actions");
 
   await visit("/");
@@ -201,6 +234,9 @@ test("posting does not leak plaintext", async assert => {
   await composerActions.expand();
   await composerActions.selectRowByValue("reply_as_private_message");
   await click(".reply-details a");
+  await fillIn("#private-message-users", "admin");
+  await keyEvent("#private-message-users", "keydown", 8);
+  await keyEvent("#private-message-users", "keydown", 13);
 
   requests = [];
   let waiting = setTimeout(() => (waiting = null), 3000);

GitHub sha: 76d97cec

2 Likes