From 35636272c0164372954b52a8a957ba08d645330d Mon Sep 17 00:00:00 2001 From: multiple creatures Date: Mon, 26 Aug 2019 11:39:40 -0500 Subject: detect spam registrations + include account approvals/rejections in transparancy log --- .../admin/pending_accounts_controller.rb | 18 ++++++++++-- app/helpers/log_helper.rb | 13 +++++++++ app/models/user.rb | 17 ++++++------ app/workers/registration_janitor_worker.rb | 32 ++++++++++++++++++++++ 4 files changed, 70 insertions(+), 10 deletions(-) create mode 100644 app/workers/registration_janitor_worker.rb diff --git a/app/controllers/admin/pending_accounts_controller.rb b/app/controllers/admin/pending_accounts_controller.rb index b62a9bc84..f297b7c9d 100644 --- a/app/controllers/admin/pending_accounts_controller.rb +++ b/app/controllers/admin/pending_accounts_controller.rb @@ -9,8 +9,16 @@ module Admin end def batch + names = Account.where(id: form_account_batch_params['account_ids'].map(&:to_i)).pluck(:username) + @form = Form::AccountBatch.new(form_account_batch_params.merge(current_account: current_account, action: action_from_button)) @form.save + + if action_from_button == 'approve' + user_friendly_action_log(current_account, :approve_registration, names) + else + user_friendly_action_log(current_account, :reject_registration, names) + end rescue ActionController::ParameterMissing flash[:alert] = I18n.t('admin.accounts.no_account_selected') ensure @@ -18,12 +26,18 @@ module Admin end def approve_all - Form::AccountBatch.new(current_account: current_account, account_ids: User.pending.pluck(:account_id), action: 'approve').save + account_ids = User.pending.pluck(:account_id) + names = Account.where(id: account_ids).pluck(:username) + Form::AccountBatch.new(current_account: current_account, account_ids: account_ids, action: 'approve').save + user_friendly_action_log(current_account, :approve_registration, names, "Approved all peneding accounts.") redirect_to admin_pending_accounts_path(current_params) end def reject_all - Form::AccountBatch.new(current_account: current_account, account_ids: User.pending.pluck(:account_id), action: 'reject').save + account_ids = User.pending.pluck(:account_id) + names = Account.where(id: account_ids).pluck(:username) + Form::AccountBatch.new(current_account: current_account, account_ids: account_ids, action: 'reject').save + user_friendly_action_log(current_account, :reject_registration, names, "Rejected all pending accounts.") redirect_to admin_pending_accounts_path(current_params) end diff --git a/app/helpers/log_helper.rb b/app/helpers/log_helper.rb index 86ee7be7e..9dd44e72d 100644 --- a/app/helpers/log_helper.rb +++ b/app/helpers/log_helper.rb @@ -103,6 +103,19 @@ module LogHelper when :memorialize LogWorker.perform_async("\xf0\x9f\x8f\x85 <#{source}> memorialized an account.") + + when :approve_registration + if target.respond_to?('map') + LogWorker.perform_async("\u2705 <#{source}> approved the account of #{target.map { |acct| "<#{acct}>" }.join(', ')}.\n\n#{reason ? "Comment: #{reason}" : ''}") + else + LogWorker.perform_async("\u2705 <#{source}> approved the account of <#{target}>.\n\n#{reason ? "Comment: #{reason}" : ''}") + end + when :reject_registration + if target.respond_to?('map') + LogWorker.perform_async("\u274c <#{source}> rejected the account of #{target.map { |acct| "<#{acct}>" }.join(', ')}.\n\n#{reason ? "Comment: #{reason}" : ''}") + else + LogWorker.perform_async("\u274c <#{source}> rejected the account of <#{target}>.\n\n#{reason ? "Comment: #{reason}" : ''}") + end end end end diff --git a/app/models/user.rb b/app/models/user.rb index a0786aa69..11289a0a5 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -198,7 +198,7 @@ class User < ApplicationRecord if new_user && approved? prepare_new_user! elsif new_user - notify_staff_about_pending_account! + RegistrationJanitorWorker.perform_async(id) end end @@ -242,6 +242,14 @@ class User < ApplicationRecord save! end + def notify_staff_about_pending_account! + LogWorker.perform_async("\xf0\x9f\x86\x95 New account <#{Account.find(account_id).username}> is awaiting admin approval.\n\nReview (moderators only): https://#{Rails.configuration.x.web_domain || Rails.configuration.x.local_domain}/admin/pending_accounts") + User.staff.includes(:account).each do |u| + next unless u.allows_pending_account_emails? + AdminMailer.new_pending_account(u.account, self).deliver_later + end + end + def wants_larger_menus? @wants_larger_menus ||= (settings.larger_menus || false) end @@ -496,13 +504,6 @@ class User < ApplicationRecord regenerate_feed! if needs_feed_update? end - def notify_staff_about_pending_account! - User.staff.includes(:account).each do |u| - next unless u.allows_pending_account_emails? - AdminMailer.new_pending_account(u.account, self).deliver_later - end - end - def regenerate_feed! return unless Redis.current.setnx("account:#{account_id}:regeneration", true) Redis.current.expire("account:#{account_id}:regeneration", 1.day.seconds) diff --git a/app/workers/registration_janitor_worker.rb b/app/workers/registration_janitor_worker.rb new file mode 100644 index 000000000..e3130a6bb --- /dev/null +++ b/app/workers/registration_janitor_worker.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +class RegistrationJanitorWorker + include Sidekiq::Worker + include LogHelper + + def perform(user_id) + user = User.find(user_id) + janitor = janitor_account || Account.representative + + spam_triggers = ENV.fetch('REGISTRATION_SPAM_TRIGGERS', '').split('|').map { |phrase| phrase.strip } + + intro = user.invite_request&.text + # normalize it + intro = intro.gsub(/[\u200b-\u200d\ufeff\u200e\u200f]/, '').strip.downcase unless intro.nil? + + return user.notify_staff_about_pending_account! unless intro.blank? || intro.split.count < 5 || spam_triggers.any? { |phrase| phrase.in?(intro) } + + user_friendly_action_log(janitor, :reject_registration, user.account.username, "Registration was spam filtered.") + Form::AccountBatch.new(current_account: janitor, account_ids: user.account.id, action: 'reject').save + rescue ActiveRecord::RecordNotFound, ActiveRecord::RecordInvalid + true + end + + private + + def janitor_account + account_id = ENV.fetch('JANITOR_USER', '').to_i + return if account_id == 0 + Account.find_by(id: account_id) + end +end -- cgit