about summary refs log tree commit diff
path: root/app/controllers/concerns
diff options
context:
space:
mode:
authorStarfall <us@starfall.systems>2022-01-31 12:50:14 -0600
committerStarfall <us@starfall.systems>2022-01-31 12:50:14 -0600
commit17265f47f8f931e70699088dd8bd2a1c7b78112b (patch)
treea1dde2630cd8e481cc4c5d047c4af241a251def0 /app/controllers/concerns
parent129962006c2ebcd195561ac556887dc87d32081c (diff)
parentd6f3261c6cb810ea4eb6f74b9ee62af0d94cbd52 (diff)
Merge branch 'glitchsoc'
Diffstat (limited to 'app/controllers/concerns')
-rw-r--r--app/controllers/concerns/account_owned_concern.rb5
-rw-r--r--app/controllers/concerns/accountable_concern.rb4
-rw-r--r--app/controllers/concerns/captcha_concern.rb59
-rw-r--r--app/controllers/concerns/sign_in_token_authentication_concern.rb20
-rw-r--r--app/controllers/concerns/theming_concern.rb80
-rw-r--r--app/controllers/concerns/two_factor_authentication_concern.rb26
-rw-r--r--app/controllers/concerns/user_tracking_concern.rb6
7 files changed, 176 insertions, 24 deletions
diff --git a/app/controllers/concerns/account_owned_concern.rb b/app/controllers/concerns/account_owned_concern.rb
index 62e379846..25149d03f 100644
--- a/app/controllers/concerns/account_owned_concern.rb
+++ b/app/controllers/concerns/account_owned_concern.rb
@@ -8,6 +8,7 @@ module AccountOwnedConcern
     before_action :set_account, if: :account_required?
     before_action :check_account_approval, if: :account_required?
     before_action :check_account_suspension, if: :account_required?
+    before_action :check_account_confirmation, if: :account_required?
   end
 
   private
@@ -28,6 +29,10 @@ module AccountOwnedConcern
     not_found if @account.local? && @account.user_pending?
   end
 
+  def check_account_confirmation
+    not_found if @account.local? && !@account.user_confirmed?
+  end
+
   def check_account_suspension
     if @account.suspended_permanently?
       permanent_suspension_response
diff --git a/app/controllers/concerns/accountable_concern.rb b/app/controllers/concerns/accountable_concern.rb
index 3cdcffc51..87d62478d 100644
--- a/app/controllers/concerns/accountable_concern.rb
+++ b/app/controllers/concerns/accountable_concern.rb
@@ -3,7 +3,7 @@
 module AccountableConcern
   extend ActiveSupport::Concern
 
-  def log_action(action, target)
-    Admin::ActionLog.create(account: current_account, action: action, target: target)
+  def log_action(action, target, options = {})
+    Admin::ActionLog.create(account: current_account, action: action, target: target, recorded_changes: options.stringify_keys)
   end
 end
diff --git a/app/controllers/concerns/captcha_concern.rb b/app/controllers/concerns/captcha_concern.rb
new file mode 100644
index 000000000..538c1ffb1
--- /dev/null
+++ b/app/controllers/concerns/captcha_concern.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+module CaptchaConcern
+  extend ActiveSupport::Concern
+  include Hcaptcha::Adapters::ViewMethods
+
+  included do
+    helper_method :render_captcha
+  end
+
+  def captcha_available?
+    ENV['HCAPTCHA_SECRET_KEY'].present? && ENV['HCAPTCHA_SITE_KEY'].present?
+  end
+
+  def captcha_enabled?
+    captcha_available? && Setting.captcha_enabled
+  end
+
+  def captcha_user_bypass?
+    false
+  end
+
+  def captcha_required?
+    captcha_enabled? && !captcha_user_bypass?
+  end
+
+  def check_captcha!
+    return true unless captcha_required?
+
+    if verify_hcaptcha
+      true
+    else
+      if block_given?
+        message = flash[:hcaptcha_error]
+        flash.delete(:hcaptcha_error)
+        yield message
+      end
+      false
+    end
+  end
+
+  def extend_csp_for_captcha!
+    policy = request.content_security_policy
+    return unless captcha_required? && policy.present?
+
+    %w(script_src frame_src style_src connect_src).each do |directive|
+      values = policy.send(directive)
+      values << 'https://hcaptcha.com' unless values.include?('https://hcaptcha.com') || values.include?('https:')
+      values << 'https://*.hcaptcha.com' unless values.include?('https://*.hcaptcha.com') || values.include?('https:')
+      policy.send(directive, *values)
+    end
+  end
+
+  def render_captcha
+    return unless captcha_required?
+
+    hcaptcha_tags
+  end
+end
diff --git a/app/controllers/concerns/sign_in_token_authentication_concern.rb b/app/controllers/concerns/sign_in_token_authentication_concern.rb
index 016ab8f52..4eb3d7181 100644
--- a/app/controllers/concerns/sign_in_token_authentication_concern.rb
+++ b/app/controllers/concerns/sign_in_token_authentication_concern.rb
@@ -16,14 +16,18 @@ module SignInTokenAuthenticationConcern
   end
 
   def authenticate_with_sign_in_token
-    user = self.resource = find_user
-
-    if user.present? && session[:attempt_user_id].present? && session[:attempt_user_updated_at] != user.updated_at.to_s
-      restart_session
-    elsif user_params.key?(:sign_in_token_attempt) && session[:attempt_user_id]
-      authenticate_with_sign_in_token_attempt(user)
-    elsif user.present? && user.external_or_valid_password?(user_params[:password])
-      prompt_for_sign_in_token(user)
+    if user_params[:email].present?
+      user = self.resource = find_user_from_params
+      prompt_for_sign_in_token(user) if user&.external_or_valid_password?(user_params[:password])
+    elsif session[:attempt_user_id]
+      user = self.resource = User.find_by(id: session[:attempt_user_id])
+      return if user.nil?
+
+      if session[:attempt_user_updated_at] != user.updated_at.to_s
+        restart_session
+      elsif user_params.key?(:sign_in_token_attempt)
+        authenticate_with_sign_in_token_attempt(user)
+      end
     end
   end
 
diff --git a/app/controllers/concerns/theming_concern.rb b/app/controllers/concerns/theming_concern.rb
new file mode 100644
index 000000000..1ee3256c0
--- /dev/null
+++ b/app/controllers/concerns/theming_concern.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+module ThemingConcern
+  extend ActiveSupport::Concern
+
+  def use_pack(pack_name)
+    @core = resolve_pack_with_common(Themes.instance.core, pack_name)
+    @theme = resolve_pack_with_common(Themes.instance.flavour(current_flavour), pack_name, current_skin)
+  end
+
+  private
+
+  def valid_pack_data?(data, pack_name)
+    data['pack'].is_a?(Hash) && [String, Hash].any? { |c| data['pack'][pack_name].is_a?(c) }
+  end
+
+  def nil_pack(data)
+    {
+      use_common: true,
+      flavour: data['name'],
+      pack: nil,
+      preload: nil,
+      skin: nil,
+      supported_locales: data['locales'],
+    }
+  end
+
+  def pack(data, pack_name, skin)
+    pack_data = {
+      use_common: true,
+      flavour: data['name'],
+      pack: pack_name,
+      preload: nil,
+      skin: nil,
+      supported_locales: data['locales'],
+    }
+
+    return pack_data unless data['pack'][pack_name].is_a?(Hash)
+
+    pack_data[:use_common] = false if data['pack'][pack_name]['use_common'] == false
+    pack_data[:pack] = nil unless data['pack'][pack_name]['filename']
+
+    preloads = data['pack'][pack_name]['preload']
+    pack_data[:preload] = [preloads] if preloads.is_a?(String)
+    pack_data[:preload] = preloads if preloads.is_a?(Array)
+
+    if skin != 'default' && data['skin'][skin]
+      pack_data[:skin] = skin if data['skin'][skin].include?(pack_name)
+    elsif data['pack'][pack_name]['stylesheet']
+      pack_data[:skin] = 'default'
+    end
+
+    pack_data
+  end
+
+  def resolve_pack(data, pack_name, skin)
+    return pack(data, pack_name, skin) if valid_pack_data?(data, pack_name)
+    return if data['name'].blank?
+
+    fallbacks = []
+    if data.key?('fallback')
+      fallbacks = data['fallback'] if data['fallback'].is_a?(Array)
+      fallbacks = [data['fallback']] if data['fallback'].is_a?(String)
+    elsif data['name'] != Setting.default_settings['flavour']
+      fallbacks = [Setting.default_settings['flavour']]
+    end
+
+    fallbacks.each do |fallback|
+      return resolve_pack(Themes.instance.flavour(fallback), pack_name) if Themes.instance.flavour(fallback)
+    end
+
+    nil
+  end
+
+  def resolve_pack_with_common(data, pack_name, skin = 'default')
+    result = resolve_pack(data, pack_name, skin) || nil_pack(data)
+    result[:common] = resolve_pack(data, 'common', skin) if result.delete(:use_common)
+    result
+  end
+end
diff --git a/app/controllers/concerns/two_factor_authentication_concern.rb b/app/controllers/concerns/two_factor_authentication_concern.rb
index d3f00a4b4..c9477a1d4 100644
--- a/app/controllers/concerns/two_factor_authentication_concern.rb
+++ b/app/controllers/concerns/two_factor_authentication_concern.rb
@@ -35,16 +35,20 @@ module TwoFactorAuthenticationConcern
   end
 
   def authenticate_with_two_factor
-    user = self.resource = find_user
-
-    if user.present? && session[:attempt_user_id].present? && session[:attempt_user_updated_at] != user.updated_at.to_s
-      restart_session
-    elsif user.webauthn_enabled? && user_params.key?(:credential) && session[:attempt_user_id]
-      authenticate_with_two_factor_via_webauthn(user)
-    elsif user_params.key?(:otp_attempt) && session[:attempt_user_id]
-      authenticate_with_two_factor_via_otp(user)
-    elsif user.present? && user.external_or_valid_password?(user_params[:password])
-      prompt_for_two_factor(user)
+    if user_params[:email].present?
+      user = self.resource = find_user_from_params
+      prompt_for_two_factor(user) if user&.external_or_valid_password?(user_params[:password])
+    elsif session[:attempt_user_id]
+      user = self.resource = User.find_by(id: session[:attempt_user_id])
+      return if user.nil?
+
+      if session[:attempt_user_updated_at] != user.updated_at.to_s
+        restart_session
+      elsif user.webauthn_enabled? && user_params.key?(:credential)
+        authenticate_with_two_factor_via_webauthn(user)
+      elsif user_params.key?(:otp_attempt)
+        authenticate_with_two_factor_via_otp(user)
+      end
     end
   end
 
@@ -53,7 +57,7 @@ module TwoFactorAuthenticationConcern
 
     if valid_webauthn_credential?(user, webauthn_credential)
       on_authentication_success(user, :webauthn)
-      render json: { redirect_path: root_path }, status: :ok
+      render json: { redirect_path: after_sign_in_path_for(user) }, status: :ok
     else
       on_authentication_failure(user, :webauthn, :invalid_credential)
       render json: { error: t('webauthn_credentials.invalid_credential') }, status: :unprocessable_entity
diff --git a/app/controllers/concerns/user_tracking_concern.rb b/app/controllers/concerns/user_tracking_concern.rb
index efda37fae..45f3aab0d 100644
--- a/app/controllers/concerns/user_tracking_concern.rb
+++ b/app/controllers/concerns/user_tracking_concern.rb
@@ -3,7 +3,7 @@
 module UserTrackingConcern
   extend ActiveSupport::Concern
 
-  UPDATE_SIGN_IN_HOURS = 24
+  UPDATE_SIGN_IN_FREQUENCY = 24.hours.freeze
 
   included do
     before_action :update_user_sign_in
@@ -12,10 +12,10 @@ module UserTrackingConcern
   private
 
   def update_user_sign_in
-    current_user.update_sign_in!(request) if user_needs_sign_in_update?
+    current_user.update_sign_in! if user_needs_sign_in_update?
   end
 
   def user_needs_sign_in_update?
-    user_signed_in? && (current_user.current_sign_in_at.nil? || current_user.current_sign_in_at < UPDATE_SIGN_IN_HOURS.hours.ago)
+    user_signed_in? && (current_user.current_sign_in_at.nil? || current_user.current_sign_in_at < UPDATE_SIGN_IN_FREQUENCY.ago)
   end
 end