2016-11-15 16:56:29 +01:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2016-02-20 22:53:20 +01:00
|
|
|
class ApplicationController < ActionController::Base
|
|
|
|
# Prevent CSRF attacks by raising an exception.
|
|
|
|
# For APIs, you may want to use :null_session instead.
|
|
|
|
protect_from_forgery with: :exception
|
2016-03-25 14:12:24 +01:00
|
|
|
|
2017-04-24 02:44:05 +02:00
|
|
|
force_ssl if: :https_enabled?
|
|
|
|
|
2017-04-08 02:30:50 +02:00
|
|
|
include Localized
|
2017-04-30 00:28:16 +02:00
|
|
|
include UserTrackingConcern
|
2018-05-11 13:20:58 +02:00
|
|
|
include SessionTrackingConcern
|
2019-07-21 22:32:16 +02:00
|
|
|
include CacheConcern
|
2019-07-30 11:10:46 +02:00
|
|
|
include DomainControlHelper
|
2017-04-16 12:51:30 +02:00
|
|
|
|
|
|
|
helper_method :current_account
|
2017-06-25 23:51:32 +02:00
|
|
|
helper_method :current_session
|
2017-12-04 08:26:40 +01:00
|
|
|
helper_method :current_flavour
|
2017-12-01 04:29:47 +01:00
|
|
|
helper_method :current_skin
|
2017-04-16 12:51:30 +02:00
|
|
|
helper_method :single_user_mode?
|
2018-02-28 19:04:53 +01:00
|
|
|
helper_method :use_seamless_external_login?
|
2019-07-30 11:10:46 +02:00
|
|
|
helper_method :whitelist_mode?
|
2016-08-24 17:56:44 +02:00
|
|
|
|
2016-09-08 02:40:51 +02:00
|
|
|
rescue_from ActionController::RoutingError, with: :not_found
|
2017-01-15 00:30:23 +01:00
|
|
|
rescue_from ActionController::InvalidAuthenticityToken, with: :unprocessable_entity
|
2018-05-26 01:09:30 +02:00
|
|
|
rescue_from ActionController::UnknownFormat, with: :not_acceptable
|
2019-08-30 01:34:47 +02:00
|
|
|
rescue_from ActionController::ParameterMissing, with: :bad_request
|
2020-01-04 01:54:07 +01:00
|
|
|
rescue_from Paperclip::AdapterRegistry::NoHandlerError, with: :bad_request
|
2019-08-30 01:34:47 +02:00
|
|
|
rescue_from ActiveRecord::RecordNotFound, with: :not_found
|
2017-11-11 20:23:33 +01:00
|
|
|
rescue_from Mastodon::NotPermittedError, with: :forbidden
|
2019-08-18 18:04:18 +02:00
|
|
|
rescue_from HTTP::Error, OpenSSL::SSL::SSLError, with: :internal_server_error
|
2019-08-30 01:34:47 +02:00
|
|
|
rescue_from Mastodon::RaceConditionError, with: :service_unavailable
|
2020-03-08 15:17:39 +01:00
|
|
|
rescue_from Mastodon::RateLimitExceededError, with: :too_many_requests
|
2016-09-08 02:40:51 +02:00
|
|
|
|
2016-10-06 15:42:00 +02:00
|
|
|
before_action :store_current_location, except: :raise_not_found, unless: :devise_controller?
|
Change unconfirmed user login behaviour (#11375)
Allow access to account settings, 2FA, authorized applications, and
account deletions to unconfirmed and pending users, as well as
users who had their accounts disabled. Suspended users cannot update
their e-mail or password or delete their account.
Display account status on account settings page, for example, when
an account is frozen, limited, unconfirmed or pending review.
After sign up, login users straight away and show a simple page that
tells them the status of their account with links to account settings
and logout, to reduce onboarding friction and allow users to correct
wrongly typed e-mail addresses.
Move the final sign-up step of SSO integrations to be the same
as above to reduce code duplication.
2019-07-22 10:48:50 +02:00
|
|
|
before_action :require_functional!, if: :user_signed_in?
|
2016-10-02 17:11:08 +02:00
|
|
|
|
2019-08-16 02:08:35 +02:00
|
|
|
skip_before_action :verify_authenticity_token, only: :raise_not_found
|
|
|
|
|
2016-09-08 02:40:51 +02:00
|
|
|
def raise_not_found
|
2016-09-29 21:28:21 +02:00
|
|
|
raise ActionController::RoutingError, "No route matches #{params[:unmatched_route]}"
|
2016-09-08 02:40:51 +02:00
|
|
|
end
|
|
|
|
|
2016-10-02 17:11:08 +02:00
|
|
|
private
|
|
|
|
|
2017-04-24 02:44:05 +02:00
|
|
|
def https_enabled?
|
2019-09-07 02:47:51 +02:00
|
|
|
Rails.env.production? && !request.path.start_with?('/health')
|
2017-04-24 02:44:05 +02:00
|
|
|
end
|
|
|
|
|
2019-07-11 20:11:09 +02:00
|
|
|
def authorized_fetch_mode?
|
2019-07-30 11:10:46 +02:00
|
|
|
ENV['AUTHORIZED_FETCH'] == 'true' || Rails.configuration.x.whitelist_mode
|
2019-07-11 20:11:09 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
def public_fetch_mode?
|
|
|
|
!authorized_fetch_mode?
|
|
|
|
end
|
|
|
|
|
2016-10-02 17:11:08 +02:00
|
|
|
def store_current_location
|
2018-02-22 00:51:30 +01:00
|
|
|
store_location_for(:user, request.url) unless request.format == :json
|
2016-10-02 17:11:08 +02:00
|
|
|
end
|
|
|
|
|
2016-11-28 18:45:13 +01:00
|
|
|
def require_admin!
|
2018-04-03 13:07:32 +02:00
|
|
|
forbidden unless current_user&.admin?
|
2016-11-28 18:45:13 +01:00
|
|
|
end
|
|
|
|
|
2017-11-11 20:23:33 +01:00
|
|
|
def require_staff!
|
2018-04-03 13:07:32 +02:00
|
|
|
forbidden unless current_user&.staff?
|
2017-11-11 20:23:33 +01:00
|
|
|
end
|
|
|
|
|
Change unconfirmed user login behaviour (#11375)
Allow access to account settings, 2FA, authorized applications, and
account deletions to unconfirmed and pending users, as well as
users who had their accounts disabled. Suspended users cannot update
their e-mail or password or delete their account.
Display account status on account settings page, for example, when
an account is frozen, limited, unconfirmed or pending review.
After sign up, login users straight away and show a simple page that
tells them the status of their account with links to account settings
and logout, to reduce onboarding friction and allow users to correct
wrongly typed e-mail addresses.
Move the final sign-up step of SSO integrations to be the same
as above to reduce code duplication.
2019-07-22 10:48:50 +02:00
|
|
|
def require_functional!
|
|
|
|
redirect_to edit_user_registration_path unless current_user.functional?
|
2016-12-06 18:03:30 +01:00
|
|
|
end
|
|
|
|
|
2017-08-05 04:24:58 +02:00
|
|
|
def after_sign_out_path_for(_resource_or_scope)
|
|
|
|
new_user_session_path
|
|
|
|
end
|
|
|
|
|
2017-12-01 04:29:47 +01:00
|
|
|
def pack(data, pack_name, skin = 'default')
|
2017-11-21 07:13:37 +01:00
|
|
|
return nil unless pack?(data, pack_name)
|
|
|
|
pack_data = {
|
2017-12-07 00:34:19 +01:00
|
|
|
common: pack_name == 'common' ? nil : resolve_pack(data['name'] ? Themes.instance.flavour(current_flavour) : Themes.instance.core, 'common', skin),
|
2017-12-04 08:26:40 +01:00
|
|
|
flavour: data['name'],
|
2017-11-21 07:13:37 +01:00
|
|
|
pack: pack_name,
|
|
|
|
preload: nil,
|
2017-12-01 04:29:47 +01:00
|
|
|
skin: nil,
|
2017-12-08 04:07:47 +01:00
|
|
|
supported_locales: data['locales'],
|
2017-11-21 07:13:37 +01:00
|
|
|
}
|
|
|
|
if data['pack'][pack_name].is_a?(Hash)
|
|
|
|
pack_data[:common] = nil if data['pack'][pack_name]['use_common'] == false
|
|
|
|
pack_data[:pack] = nil unless data['pack'][pack_name]['filename']
|
|
|
|
if data['pack'][pack_name]['preload']
|
|
|
|
pack_data[:preload] = [data['pack'][pack_name]['preload']] if data['pack'][pack_name]['preload'].is_a?(String)
|
|
|
|
pack_data[:preload] = data['pack'][pack_name]['preload'] if data['pack'][pack_name]['preload'].is_a?(Array)
|
|
|
|
end
|
2017-12-01 04:29:47 +01:00
|
|
|
if skin != 'default' && data['skin'][skin]
|
|
|
|
pack_data[:skin] = skin if data['skin'][skin].include?(pack_name)
|
|
|
|
else # default skin
|
|
|
|
pack_data[:skin] = 'default' if data['pack'][pack_name]['stylesheet']
|
|
|
|
end
|
2017-11-21 07:13:37 +01:00
|
|
|
end
|
|
|
|
pack_data
|
|
|
|
end
|
|
|
|
|
|
|
|
def pack?(data, pack_name)
|
|
|
|
if data['pack'].is_a?(Hash) && data['pack'].key?(pack_name)
|
|
|
|
return true if data['pack'][pack_name].is_a?(String) || data['pack'][pack_name].is_a?(Hash)
|
|
|
|
end
|
|
|
|
false
|
|
|
|
end
|
|
|
|
|
2017-12-01 04:29:47 +01:00
|
|
|
def nil_pack(data, pack_name, skin = 'default')
|
2017-11-21 07:13:37 +01:00
|
|
|
{
|
2017-12-04 08:26:40 +01:00
|
|
|
common: pack_name == 'common' ? nil : resolve_pack(data['name'] ? Themes.instance.flavour(current_flavour) : Themes.instance.core, 'common', skin),
|
|
|
|
flavour: data['name'],
|
2017-11-21 07:13:37 +01:00
|
|
|
pack: nil,
|
|
|
|
preload: nil,
|
2017-12-01 04:29:47 +01:00
|
|
|
skin: nil,
|
2017-12-08 04:07:47 +01:00
|
|
|
supported_locales: data['locales'],
|
2017-11-21 07:13:37 +01:00
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2017-12-01 04:29:47 +01:00
|
|
|
def resolve_pack(data, pack_name, skin = 'default')
|
|
|
|
result = pack(data, pack_name, skin)
|
2017-11-21 07:13:37 +01:00
|
|
|
unless result
|
|
|
|
if data['name'] && data.key?('fallback')
|
|
|
|
if data['fallback'].nil?
|
2017-12-01 04:29:47 +01:00
|
|
|
return nil_pack(data, pack_name, skin)
|
2017-12-04 08:26:40 +01:00
|
|
|
elsif data['fallback'].is_a?(String) && Themes.instance.flavour(data['fallback'])
|
2017-12-07 23:49:54 +01:00
|
|
|
return resolve_pack(Themes.instance.flavour(data['fallback']), pack_name)
|
2017-11-21 07:13:37 +01:00
|
|
|
elsif data['fallback'].is_a?(Array)
|
|
|
|
data['fallback'].each do |fallback|
|
2017-12-07 23:49:54 +01:00
|
|
|
return resolve_pack(Themes.instance.flavour(fallback), pack_name) if Themes.instance.flavour(fallback)
|
2017-11-21 07:13:37 +01:00
|
|
|
end
|
|
|
|
end
|
2017-12-01 04:29:47 +01:00
|
|
|
return nil_pack(data, pack_name, skin)
|
2017-11-21 07:13:37 +01:00
|
|
|
end
|
2017-12-07 23:49:54 +01:00
|
|
|
return data.key?('name') && data['name'] != Setting.default_settings['flavour'] ? resolve_pack(Themes.instance.flavour(Setting.default_settings['flavour']), pack_name) : nil_pack(data, pack_name, skin)
|
2017-11-21 07:13:37 +01:00
|
|
|
end
|
|
|
|
result
|
|
|
|
end
|
|
|
|
|
|
|
|
def use_pack(pack_name)
|
|
|
|
@core = resolve_pack(Themes.instance.core, pack_name)
|
2017-12-04 08:26:40 +01:00
|
|
|
@theme = resolve_pack(Themes.instance.flavour(current_flavour), pack_name, current_skin)
|
2017-11-21 07:13:37 +01:00
|
|
|
end
|
|
|
|
|
2016-08-18 17:13:41 +02:00
|
|
|
protected
|
|
|
|
|
2018-09-09 04:10:44 +02:00
|
|
|
def truthy_param?(key)
|
|
|
|
ActiveModel::Type::Boolean.new.cast(params[key])
|
|
|
|
end
|
|
|
|
|
2017-05-01 22:24:36 +02:00
|
|
|
def forbidden
|
|
|
|
respond_with_error(403)
|
2016-09-08 02:40:51 +02:00
|
|
|
end
|
|
|
|
|
2017-05-01 22:24:36 +02:00
|
|
|
def not_found
|
|
|
|
respond_with_error(404)
|
2017-01-15 00:30:23 +01:00
|
|
|
end
|
|
|
|
|
2017-05-01 22:24:36 +02:00
|
|
|
def gone
|
|
|
|
respond_with_error(410)
|
2017-04-23 05:21:10 +02:00
|
|
|
end
|
|
|
|
|
2017-01-15 00:30:23 +01:00
|
|
|
def unprocessable_entity
|
2017-05-01 22:24:36 +02:00
|
|
|
respond_with_error(422)
|
2016-10-05 13:26:44 +02:00
|
|
|
end
|
|
|
|
|
2018-05-26 01:09:30 +02:00
|
|
|
def not_acceptable
|
|
|
|
respond_with_error(406)
|
|
|
|
end
|
|
|
|
|
2019-08-30 01:34:47 +02:00
|
|
|
def bad_request
|
|
|
|
respond_with_error(400)
|
|
|
|
end
|
|
|
|
|
2019-08-18 18:04:18 +02:00
|
|
|
def internal_server_error
|
|
|
|
respond_with_error(500)
|
|
|
|
end
|
|
|
|
|
2019-08-30 01:34:47 +02:00
|
|
|
def service_unavailable
|
|
|
|
respond_with_error(503)
|
|
|
|
end
|
|
|
|
|
2020-03-08 15:17:39 +01:00
|
|
|
def too_many_requests
|
|
|
|
respond_with_error(429)
|
|
|
|
end
|
|
|
|
|
2017-04-15 16:46:27 +02:00
|
|
|
def single_user_mode?
|
2019-07-19 01:44:42 +02:00
|
|
|
@single_user_mode ||= Rails.configuration.x.single_user_mode && Account.where('id > 0').exists?
|
2017-04-15 16:46:27 +02:00
|
|
|
end
|
|
|
|
|
2018-02-28 19:04:53 +01:00
|
|
|
def use_seamless_external_login?
|
|
|
|
Devise.pam_authentication || Devise.ldap_authentication
|
2018-02-02 10:18:55 +01:00
|
|
|
end
|
|
|
|
|
2016-08-18 17:13:41 +02:00
|
|
|
def current_account
|
2019-06-25 20:18:15 +02:00
|
|
|
return @current_account if defined?(@current_account)
|
|
|
|
|
|
|
|
@current_account = current_user&.account
|
2016-08-18 17:13:41 +02:00
|
|
|
end
|
2016-11-29 15:49:39 +01:00
|
|
|
|
2017-06-25 23:51:32 +02:00
|
|
|
def current_session
|
2019-06-25 20:18:15 +02:00
|
|
|
return @current_session if defined?(@current_session)
|
|
|
|
|
|
|
|
@current_session = SessionActivation.find_by(session_id: cookies.signed['_session_id']) if cookies.signed['_session_id'].present?
|
2017-06-25 23:51:32 +02:00
|
|
|
end
|
|
|
|
|
2017-12-04 08:26:40 +01:00
|
|
|
def current_flavour
|
2018-08-24 13:34:51 +02:00
|
|
|
return Setting.flavour unless Themes.instance.flavours.include? current_user&.setting_flavour
|
2017-12-04 08:26:40 +01:00
|
|
|
current_user.setting_flavour
|
2017-12-01 04:29:47 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def current_skin
|
2018-08-24 13:34:51 +02:00
|
|
|
return Setting.skin unless Themes.instance.skins_for(current_flavour).include? current_user&.setting_skin
|
2017-12-01 04:29:47 +01:00
|
|
|
current_user.setting_skin
|
|
|
|
end
|
|
|
|
|
2017-04-21 18:11:20 +02:00
|
|
|
def respond_with_error(code)
|
2019-12-30 04:38:18 +01:00
|
|
|
respond_to do |format|
|
2020-01-04 22:54:06 +01:00
|
|
|
format.any do
|
|
|
|
use_pack 'error'
|
|
|
|
render "errors/#{code}", layout: 'error', status: code, formats: [:html]
|
|
|
|
end
|
2019-12-30 04:38:18 +01:00
|
|
|
format.json { render json: { error: Rack::Utils::HTTP_STATUS_CODES[code] }, status: code }
|
|
|
|
end
|
2017-04-21 18:11:20 +02:00
|
|
|
end
|
2016-02-20 22:53:20 +01:00
|
|
|
end
|