DEV: Split plugin.rb into multiple files

DEV: Split plugin.rb into multiple files

diff --git a/app/controllers/encrypt_controller.rb b/app/controllers/encrypt_controller.rb
new file mode 100644
index 0000000..248662a
--- /dev/null
+++ b/app/controllers/encrypt_controller.rb
@@ -0,0 +1,150 @@
+# frozen_string_literal: true
+
+class DiscourseEncrypt::EncryptController < ApplicationController
+  requires_plugin DiscourseEncrypt::PLUGIN_NAME
+
+  before_action :ensure_logged_in
+  before_action :ensure_encrypt_enabled
+  skip_before_action :check_xhr
+
+  # Saves a user's identity in their custom fields.
+  #
+  # Params:
+  # +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.
+  def update_keys
+    public_identity  = params.require(:public)
+    private_identity = params[:private]
+    private_id_label = params[:label]
+
+    # Check if encryption is already enabled (but not changing passphrase).
+    old_identity = current_user.custom_fields['encrypt_public']
+    if params[:overwrite].blank? && old_identity && old_identity != public_identity
+      return render_json_error(I18n.t('encrypt.enabled_already'), status: 409)
+    end
+
+    current_user.custom_fields['encrypt_public'] = public_identity
+
+    if private_identity.present?
+      if private_id_label.present?
+        data = JSON.parse(current_user.custom_fields['encrypt_private']) rescue {}
+        data[private_id_label.downcase] = private_identity
+        current_user.custom_fields['encrypt_private'] = JSON.dump(data)
+      else
+        current_user.custom_fields['encrypt_private'] = private_identity
+      end
+    end
+
+    current_user.save_custom_fields
+
+    render json: success_json
+  end
+
+  # Delete a user's identity from the private identity.
+  #
+  # Params:
+  # +label+::     Private identity label
+  #
+  # Returns status code 200 after label is deleted.
+  def delete_key
+    private_id_label = params.require(:label)
+
+    data = JSON.parse(current_user.custom_fields['encrypt_private']) rescue {}
+    if data.delete(private_id_label)
+      current_user.custom_fields['encrypt_private'] = JSON.dump(data)
+      current_user.save_custom_fields
+    end
+
+    render json: success_json
+  end
+
+  # Gets public identities of a set of users.
+  #
+  # Params:
+  # +usernames+::   Array of usernames
+  #
+  # Returns status code 200 and a hash of usernames and their public
+  # identities.
+  def show_user
+    usernames = params.require(:usernames)
+
+    identities = Hash[User.where(username: usernames).map { |u| [u.username, u.custom_fields['encrypt_public']] }]
+
+    render json: identities
+  end
+
+  # Resets encryption keys for a user.
+  #
+  # Params:
+  # +user_id+::   ID of user to be reset
+  #
+  # Returns status code 200 after user is reset.
+  def reset_user
+    user_id = params.require(:user_id)
+
+    user = User.find_by(id: user_id)
+    raise Discourse::NotFound if user.blank?
+
+    guardian.ensure_can_edit!(user)
+
+    if params[:everything] == 'true'
+      TopicAllowedUser
+        .joins(topic: :_custom_fields)
+        .where(topic_custom_fields: { name: DiscourseEncrypt::TITLE_CUSTOM_FIELD })
+        .where(topic_allowed_users: { user_id: user.id })
+        .delete_all
+
+      PluginStoreRow
+        .where(plugin_name: 'discourse-encrypt')
+        .where("key LIKE 'key_%_' || ?", user.id)
+        .delete_all
+    end
+
+    # Delete encryption keys.
+    user.custom_fields.delete('encrypt_public')
+    user.custom_fields.delete('encrypt_private')
+    user.save_custom_fields
+
+    render json: success_json
+  end
+
+  # Updates an encrypted post, used immediately after creating one to
+  # update signature.
+  #
+  # Params:
+  # +post_id+::       ID of post to be updated
+  # +encrypted_raw+:: Encrypted raw with signature included
+  #
+  # Returns status code 200 after post is updated.
+  def update_post
+    post_id = params.require(:post_id)
+    encrypted_raw = params.require(:encrypted_raw)
+
+    post = Post.find_by(id: post_id)
+    guardian.ensure_can_edit!(post)
+
+    if post.updated_at < 5.seconds.ago
+      return render_json_error(I18n.t('too_late_to_edit'), status: 409)
+    end
+
+    post.update!(raw: encrypted_raw)
+
+    render json: success_json
+  end
+
+  private
+
+  def ensure_encrypt_enabled
+    groups = current_user.groups.pluck(:name)
+    encrypt_groups = SiteSetting.encrypt_groups.split('|')
+
+    if !SiteSetting.encrypt_groups.empty? && (groups & encrypt_groups).empty?
+      raise Discourse::InvalidAccess
+    end
+  end
+end
diff --git a/app/jobs/scheduled/encrypt_consistency.rb b/app/jobs/scheduled/encrypt_consistency.rb
index 3f44646..5958108 100644
--- a/app/jobs/scheduled/encrypt_consistency.rb
+++ b/app/jobs/scheduled/encrypt_consistency.rb
@@ -32,7 +32,6 @@ module Jobs
         SQL
       ).each do |row|
         Discourse.warn('User has topic key, but was not invited to topic.', user_id: row.user_id, topic_id: row.topic_id)
-        # DiscourseEncrypt::Store.remove("key_#{row.topic_id}_#{row.user_id}")
       end
     end
   end
diff --git a/lib/encrypted_post_creator.rb b/lib/encrypted_post_creator.rb
index 41c2c70..4c77b90 100644
--- a/lib/encrypted_post_creator.rb
+++ b/lib/encrypted_post_creator.rb
@@ -26,7 +26,7 @@ class EncryptedPostCreator < PostCreator
       if !@opts[:topic_key]
         users.each do |user|
           key = EncryptedPostCreator.export_key(user, topic_key)
-          DiscourseEncrypt::Store.set("key_#{@post.topic_id}_#{user.id}", key)
+          DiscourseEncrypt::set_key(@post.topic_id, user.id, key)
         end
       end
     end
diff --git a/lib/post_extensions.rb b/lib/post_extensions.rb
new file mode 100644
index 0000000..afa4a38
--- /dev/null
+++ b/lib/post_extensions.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+module PostExtensions
+  def is_encrypted?
+    !!(topic&.is_encrypted? &&
+        raw.match(/\A[A-Za-z0-9+\\\/=$]+(\n.*)?\Z/))
+  end
+end
diff --git a/lib/topic_extensions.rb b/lib/topic_extensions.rb
new file mode 100644
index 0000000..0288346
--- /dev/null
+++ b/lib/topic_extensions.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module TopicExtensions
+  def is_encrypted?
+    !!(private_message? &&
+        custom_fields &&
+        custom_fields[DiscourseEncrypt::TITLE_CUSTOM_FIELD])
+  end
+
+  def remove_allowed_user(removed_by, user)
+    ret = super
+    DiscourseEncrypt::del_key(id, user.id) if ret
+    ret
+  end
+end
diff --git a/lib/topics_controller_extensions.rb b/lib/topics_controller_extensions.rb
new file mode 100644
index 0000000..5f82bed
--- /dev/null
+++ b/lib/topics_controller_extensions.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module TopicsControllerExtensions
+  def update
+    @topic ||= Topic.find_by(id: params[:topic_id])
+
+    if @topic.is_encrypted? && encrypted_title = params[:encrypted_title].presence
+      guardian.ensure_can_edit!(@topic)
+      @topic.custom_fields[DiscourseEncrypt::TITLE_CUSTOM_FIELD] = params.delete(:encrypted_title)
+      @topic.save_custom_fields
+    end
+
+    super
+  end
+
+  def invite
+    @topic ||= Topic.find_by(id: params[:topic_id])
+
+    if @topic.is_encrypted?
+      if params[:key].present?
+        @user ||= User.find_by_username_or_email(params[:user])
+        guardian.ensure_can_invite_to!(@topic)
+        DiscourseEncrypt::set_key(@topic.id, @user.id, params[:key])
+      else
+        return render_json_error(I18n.t("js.encrypt.cannot_invite"))
+      end
+    end
+
+    super
+  end
+
+  def invite_group
+    @topic ||= Topic.find_by(id: params[:topic_id])
+
+    if @topic.is_encrypted?
+      return render_json_error(I18n.t("js.encrypt.cannot_invite_group"))
+    end
+
+    super
+  end
+end
diff --git a/lib/user_extensions.rb b/lib/user_extensions.rb
new file mode 100644
index 0000000..eb7385b

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

GitHub sha: 4d449163

1 Like