FEATURE: Restrict plugin to specific groups.

FEATURE: Restrict plugin to specific groups.

diff --git a/assets/javascripts/discourse/connectors/user-preferences-account/encrypt.hbs b/assets/javascripts/discourse/connectors/user-preferences-account/encrypt.hbs
index 357f25c..5f7abde 100644
--- a/assets/javascripts/discourse/connectors/user-preferences-account/encrypt.hbs
+++ b/assets/javascripts/discourse/connectors/user-preferences-account/encrypt.hbs
@@ -1,4 +1,4 @@
-{{#if siteSettings.encrypt_enabled}}
+{{#if isPluginEnabled}}
   <div class="control-group pref-title">
     <label class="control-label">{{i18n 'encrypt.title'}}</label>
     <div class="controls">
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 6a828fc..2afb4de 100644
--- a/assets/javascripts/discourse/connectors/user-preferences-account/encrypt.js.es6
+++ b/assets/javascripts/discourse/connectors/user-preferences-account/encrypt.js.es6
@@ -31,6 +31,10 @@ export default {
   setupComponent(args, component) {
     const currentUser = Discourse.User.current();
     if (args.model.get("id") === currentUser.get("id")) {
+      const groups = (args.model.get("groups") || []).map(group =>
+        group.get("name")
+      );
+      const encryptGroups = Discourse.SiteSettings.encrypt_groups.split("|");
       component.setProperties({
         model: args.model,
         handler: hideComponentIfDisabled(component),
@@ -48,6 +52,10 @@ export default {
         inProgress: false,
         /** @var Whether current user is the same as model user. */
         isCurrentUser: true,
+        /** @var Whether plugin is enabled for current user. */
+        isPluginEnabled:
+          Discourse.SiteSettings.encrypt_groups.length === 0 ||
+          groups.some(group => encryptGroups.includes(group)),
         /** @var Whether the encryption is enabled or not. */
         isEncryptEnabled: false,
         /** @var Whether the encryption is active on this device. */
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index 9ae2cc1..d210392 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -4,3 +4,4 @@ en:
     enabled_already: "You have already enabled encrypted messages."
   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/config/settings.yml b/config/settings.yml
index e3ca865..7b7345d 100644
--- a/config/settings.yml
+++ b/config/settings.yml
@@ -2,4 +2,8 @@ plugins:
   encrypt_enabled:
     client: true
     default: true
-    refresh: true
\ No newline at end of file
+    refresh: true
+  encrypt_groups:
+    default: ""
+    client: true
+    type: list
diff --git a/plugin.rb b/plugin.rb
index 24e0498..561dba2 100644
--- a/plugin.rb
+++ b/plugin.rb
@@ -48,6 +48,11 @@ after_initialize do
         private_key = params.require(:private_key)
         salt        = params.require(:salt)
 
+        # Check if encrypt settings are visible to user.
+        groups = current_user.groups.pluck(:name)
+        encrypt_groups = SiteSetting.encrypt_groups.split("|")
+        raise Discourse::InvalidAccess if !SiteSetting.encrypt_groups.empty? && (groups & encrypt_groups).empty?
+
         # Check if encryption is already enabled (but not changing passphrase).
         old_public_key = current_user.custom_fields['encrypt_public_key']
         if old_public_key && old_public_key != public_key
diff --git a/spec/requests/encrypt_controller_spec.rb b/spec/requests/encrypt_controller_spec.rb
index 06ecbcb..25266e2 100644
--- a/spec/requests/encrypt_controller_spec.rb
+++ b/spec/requests/encrypt_controller_spec.rb
@@ -38,6 +38,30 @@ describe ::DiscourseEncrypt::EncryptController do
       expect(response.status).to eq(403)
     end
 
+    it 'does not work when user is not allowed' do
+      group = Fabricate(:group)
+      SiteSetting.encrypt_groups = group.name
+
+      user = Fabricate(:user)
+      sign_in(user)
+
+      put '/encrypt/keys', params: {
+        public_key: '-- the public key --',
+        private_key: '-- the private key --',
+        salt: '-- the salt --'
+      }
+      expect(response.status).to eq(403)
+
+      Fabricate(:group_user, group: group, user: user)
+
+      put '/encrypt/keys', params: {
+        public_key: '-- the public key --',
+        private_key: '-- the private key --',
+        salt: '-- the salt --'
+      }
+      expect(response.status).to eq(200)
+    end
+
     it 'saves user keys' do
       sign_in(user3)
 
diff --git a/test/javascripts/acceptance/encrypt-settings-test.js.es6 b/test/javascripts/acceptance/encrypt-settings-test.js.es6
new file mode 100644
index 0000000..c573239
--- /dev/null
+++ b/test/javascripts/acceptance/encrypt-settings-test.js.es6
@@ -0,0 +1,55 @@
+import { acceptance, replaceCurrentUser } from "helpers/qunit-helpers";
+
+// TODO: Figure out why `await` is not enough.
+function sleep(time) {
+  return new Promise(resolve => {
+    setTimeout(() => resolve(), time);
+  });
+}
+
+acceptance("Encrypt - Settings", {
+  loggedIn: true,
+  settings: { encrypt_enabled: true, encrypt_groups: "" }
+});
+
+test("encrypt settings visible only to allowed groups", async assert => {
+  await visit("/u/eviltrout/preferences");
+  await sleep(1500);
+
+  assert.ok(find(".encrypt").text().length > 0, "encrypt settings are visible");
+
+  Discourse.SiteSettings.encrypt_groups = "allowed_group";
+
+  replaceCurrentUser({
+    groups: [
+      Ember.Object.create({
+        id: 1,
+        name: "not_allowed_group"
+      })
+    ]
+  });
+
+  await visit("/u/eviltrout/preferences");
+  await sleep(1500);
+  assert.ok(
+    find(".encrypt").text().length === 0,
+    "encrypt settings are not visible"
+  );
+
+  replaceCurrentUser({
+    groups: [
+      Ember.Object.create({
+        id: 1,
+        name: "not_allowed_group"
+      }),
+      Ember.Object.create({
+        id: 2,
+        name: "allowed_group"
+      })
+    ]
+  });
+
+  await visit("/u/eviltrout/preferences");
+  await sleep(1500);
+  assert.ok(find(".encrypt").text().length > 0, "encrypt settings are visible");
+});
diff --git a/test/javascripts/acceptance/encrypt-test.js.es6 b/test/javascripts/acceptance/encrypt-test.js.es6
index 27dd15c..51c071e 100644
--- a/test/javascripts/acceptance/encrypt-test.js.es6
+++ b/test/javascripts/acceptance/encrypt-test.js.es6
@@ -126,7 +126,7 @@ function sleep(time) {
 
 acceptance("Encrypt", {
   loggedIn: true,
-  settings: { encrypt_enabled: true },
+  settings: { encrypt_enabled: true, encrypt_groups: "" },
 
   beforeEach() {
     // Hook `XMLHttpRequest` to search for leaked plaintext.

GitHub sha: 98faa9c8