| Total Complexity | 64 |
| Total Lines | 280 |
| Duplicated Lines | 2.5 % |
| Changes | 5 | ||
| Bugs | 0 | Features | 0 |
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like ApplicationController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | # frozen_string_literal: true |
||
| 19 | class ApplicationController < ActionController::Base |
||
| 20 | include BbbServer |
||
| 21 | include Errors |
||
| 22 | |||
| 23 | before_action :block_unknown_hosts, :redirect_to_https, :set_user_domain, :set_user_settings, :maintenance_mode?, |
||
| 24 | :migration_error?, :user_locale, :check_admin_password, :check_user_role |
||
| 25 | |||
| 26 | protect_from_forgery with: :exceptions |
||
| 27 | |||
| 28 | # Retrieves the current user. |
||
| 29 | def current_user |
||
| 30 | @current_user ||= User.includes(:role, :main_room).find_by(id: session[:user_id]) |
||
| 31 | |||
| 32 | if Rails.configuration.loadbalanced_configuration |
||
| 33 | if @current_user && !@current_user.has_role?(:super_admin) && |
||
| 34 | @current_user.provider != @user_domain |
||
| 35 | @current_user = nil |
||
| 36 | session.clear |
||
| 37 | end |
||
| 38 | end |
||
| 39 | |||
| 40 | @current_user |
||
| 41 | end |
||
| 42 | helper_method :current_user |
||
| 43 | |||
| 44 | def bbb_server |
||
| 45 | @bbb_server ||= Rails.configuration.loadbalanced_configuration ? bbb(@user_domain) : bbb("greenlight") |
||
| 46 | end |
||
| 47 | |||
| 48 | # Block unknown hosts to mitigate host header injection attacks |
||
| 49 | def block_unknown_hosts |
||
| 50 | return if Rails.configuration.hosts.blank? |
||
| 51 | raise UnsafeHostError, "#{request.host} is not a safe host" unless Rails.configuration.hosts.include?(request.host) |
||
| 52 | end |
||
| 53 | |||
| 54 | # Force SSL |
||
| 55 | def redirect_to_https |
||
| 56 | if Rails.configuration.loadbalanced_configuration && request.headers["X-Forwarded-Proto"] == "http" |
||
| 57 | redirect_to protocol: "https://" |
||
| 58 | end |
||
| 59 | end |
||
| 60 | |||
| 61 | # Sets the user domain variable |
||
| 62 | def set_user_domain |
||
| 63 | if Rails.env.test? || !Rails.configuration.loadbalanced_configuration |
||
| 64 | @user_domain = "greenlight" |
||
| 65 | else |
||
| 66 | @user_domain = parse_user_domain(request.host) |
||
| 67 | |||
| 68 | check_provider_exists |
||
| 69 | end |
||
| 70 | end |
||
| 71 | |||
| 72 | # Sets the settinfs variable |
||
| 73 | def set_user_settings |
||
| 74 | @settings = Setting.includes(:features).find_or_create_by(provider: @user_domain) |
||
| 75 | end |
||
| 76 | |||
| 77 | # Redirects the user to a Maintenance page if turned on |
||
| 78 | def maintenance_mode? |
||
| 79 | if ENV["MAINTENANCE_MODE"] == "true" |
||
| 80 | render "errors/greenlight_error", status: 503, formats: :html, |
||
| 81 | locals: { |
||
| 82 | status_code: 503, |
||
| 83 | message: I18n.t("errors.maintenance.message"), |
||
| 84 | help: I18n.t("errors.maintenance.help"), |
||
| 85 | } |
||
| 86 | end |
||
| 87 | |||
| 88 | maintenance_string = @settings.get_value("Maintenance Banner").presence || Rails.configuration.maintenance_window |
||
| 89 | if maintenance_string.present? |
||
| 90 | flash.now[:maintenance] = maintenance_string unless cookies[:maintenance_window] == maintenance_string |
||
| 91 | end |
||
| 92 | end |
||
| 93 | |||
| 94 | # Show an information page when migration fails and there is a version error. |
||
| 95 | def migration_error? |
||
| 96 | render :migration_error, status: 500 unless ENV["DB_MIGRATE_FAILED"].blank? |
||
| 97 | end |
||
| 98 | |||
| 99 | # Sets the appropriate locale. |
||
| 100 | def user_locale(user = current_user) |
||
| 101 | locale = if user && user.language != 'default' |
||
| 102 | user.language |
||
| 103 | else |
||
| 104 | Rails.configuration.default_locale.presence || http_accept_language.language_region_compatible_from(I18n.available_locales) |
||
| 105 | end |
||
| 106 | |||
| 107 | begin |
||
| 108 | I18n.locale = locale.tr('-', '_') unless locale.nil? |
||
| 109 | rescue |
||
| 110 | # Default to English if there are any issues in language |
||
| 111 | logger.error("Support: User locale is not supported (#{locale}") |
||
| 112 | I18n.locale = "en" |
||
| 113 | end |
||
| 114 | end |
||
| 115 | |||
| 116 | # Checks to make sure that the admin has changed his password from the default |
||
| 117 | def check_admin_password |
||
| 118 | if current_user&.has_role?(:admin) && current_user.email == "[email protected]" && |
||
| 119 | current_user&.greenlight_account? && current_user&.authenticate(Rails.configuration.admin_password_default) |
||
| 120 | |||
| 121 | flash.now[:alert] = I18n.t("default_admin", |
||
| 122 | edit_link: change_password_path(user_uid: current_user.uid)).html_safe |
||
| 123 | end |
||
| 124 | end |
||
| 125 | |||
| 126 | # Checks if the user is banned and logs him out if he is |
||
| 127 | def check_user_role |
||
| 128 | if current_user&.has_role? :denied |
||
| 129 | session.delete(:user_id) |
||
| 130 | redirect_to root_path, flash: { alert: I18n.t("registration.banned.fail") } |
||
| 131 | elsif current_user&.has_role? :pending |
||
| 132 | session.delete(:user_id) |
||
| 133 | redirect_to root_path, flash: { alert: I18n.t("registration.approval.fail") } |
||
| 134 | end |
||
| 135 | end |
||
| 136 | |||
| 137 | # Relative root helper (when deploying to subdirectory). |
||
| 138 | def relative_root |
||
| 139 | Rails.configuration.relative_url_root || "" |
||
| 140 | end |
||
| 141 | helper_method :relative_root |
||
| 142 | |||
| 143 | # Determines if the BigBlueButton endpoint is configured (or set to default). |
||
| 144 | def bigbluebutton_endpoint_default? |
||
| 145 | return false if Rails.configuration.loadbalanced_configuration |
||
| 146 | Rails.configuration.bigbluebutton_endpoint_default == Rails.configuration.bigbluebutton_endpoint |
||
| 147 | end |
||
| 148 | helper_method :bigbluebutton_endpoint_default? |
||
| 149 | |||
| 150 | def allow_greenlight_accounts? |
||
| 151 | return Rails.configuration.allow_user_signup unless Rails.configuration.loadbalanced_configuration |
||
| 152 | return false unless @user_domain && !@user_domain.empty? && Rails.configuration.allow_user_signup |
||
| 153 | return false if @user_domain == "greenlight" |
||
| 154 | # Proceed with retrieving the provider info |
||
| 155 | begin |
||
| 156 | provider_info = retrieve_provider_info(@user_domain, 'api2', 'getUserGreenlightCredentials') |
||
| 157 | provider_info['provider'] == 'greenlight' |
||
| 158 | rescue => e |
||
| 159 | logger.error "Error in checking if greenlight accounts are allowed: #{e}" |
||
| 160 | false |
||
| 161 | end |
||
| 162 | end |
||
| 163 | helper_method :allow_greenlight_accounts? |
||
| 164 | |||
| 165 | # Determine if Greenlight is configured to allow user signups. |
||
| 166 | def allow_user_signup? |
||
| 167 | Rails.configuration.allow_user_signup |
||
| 168 | end |
||
| 169 | helper_method :allow_user_signup? |
||
| 170 | |||
| 171 | # Gets all configured omniauth providers. |
||
| 172 | def configured_providers |
||
| 173 | Rails.configuration.providers.select do |provider| |
||
| 174 | Rails.configuration.send("omniauth_#{provider}") |
||
| 175 | end |
||
| 176 | end |
||
| 177 | helper_method :configured_providers |
||
| 178 | |||
| 179 | # Indicates whether users are allowed to share rooms |
||
| 180 | def shared_access_allowed |
||
| 181 | @settings.get_value("Shared Access") == "true" |
||
| 182 | end |
||
| 183 | helper_method :shared_access_allowed |
||
| 184 | |||
| 185 | # Indicates whether users are allowed to share rooms |
||
| 186 | def recording_consent_required? |
||
| 187 | @settings.get_value("Require Recording Consent") == "true" |
||
| 188 | end |
||
| 189 | helper_method :recording_consent_required? |
||
| 190 | |||
| 191 | # Returns a list of allowed file types |
||
| 192 | def allowed_file_types |
||
| 193 | Rails.configuration.allowed_file_types |
||
| 194 | end |
||
| 195 | helper_method :allowed_file_types |
||
| 196 | |||
| 197 | # Returns the page that the logo redirects to when clicked on |
||
| 198 | def home_page |
||
| 199 | return admins_path if current_user.has_role? :super_admin |
||
| 200 | return current_user.main_room if current_user.role.get_permission("can_create_rooms") |
||
| 201 | cant_create_rooms_path |
||
| 202 | end |
||
| 203 | helper_method :home_page |
||
| 204 | |||
| 205 | # Parses the url for the user domain |
||
| 206 | View Code Duplication | def parse_user_domain(hostname) |
|
| 207 | return hostname.split('.').first if Rails.configuration.url_host.empty? |
||
| 208 | Rails.configuration.url_host.split(',').each do |url_host| |
||
| 209 | return hostname.chomp(url_host).chomp('.') if hostname.include?(url_host) |
||
| 210 | end |
||
| 211 | '' |
||
| 212 | end |
||
| 213 | |||
| 214 | # Include user domain in lograge logs |
||
| 215 | def append_info_to_payload(payload) |
||
| 216 | super |
||
| 217 | payload[:host] = @user_domain |
||
| 218 | end |
||
| 219 | |||
| 220 | # Manually handle BigBlueButton errors |
||
| 221 | rescue_from BigBlueButton::BigBlueButtonException do |ex| |
||
| 222 | logger.error "BigBlueButtonException: #{ex}" |
||
| 223 | render "errors/bigbluebutton_error" |
||
| 224 | end |
||
| 225 | |||
| 226 | # Manually deal with 401 errors |
||
| 227 | rescue_from CanCan::AccessDenied do |_exception| |
||
| 228 | if current_user |
||
| 229 | render "errors/greenlight_error" |
||
| 230 | else |
||
| 231 | # Store the current url as a cookie to redirect to after sigining in |
||
| 232 | cookies[:return_to] = request.url |
||
| 233 | |||
| 234 | # Get the correct signin path |
||
| 235 | path = if allow_greenlight_accounts? |
||
| 236 | signin_path |
||
| 237 | elsif Rails.configuration.loadbalanced_configuration |
||
| 238 | "#{Rails.configuration.relative_url_root}/auth/bn_launcher" |
||
| 239 | else |
||
| 240 | signin_path |
||
| 241 | end |
||
| 242 | |||
| 243 | redirect_to path |
||
| 244 | end |
||
| 245 | end |
||
| 246 | |||
| 247 | private |
||
| 248 | |||
| 249 | def check_provider_exists |
||
| 250 | # Checks to see if the user exists |
||
| 251 | begin |
||
| 252 | # Check if the session has already checked that the user exists |
||
| 253 | # and return true if they did for this domain |
||
| 254 | return if session[:provider_exists] == @user_domain |
||
| 255 | |||
| 256 | retrieve_provider_info(@user_domain, 'api2', 'getUserGreenlightCredentials') |
||
| 257 | |||
| 258 | # Add a session variable if the provider exists |
||
| 259 | session[:provider_exists] = @user_domain |
||
| 260 | rescue => e |
||
| 261 | logger.error "Error in retrieve provider info: #{e}" |
||
| 262 | @hide_signin = true |
||
| 263 | if e.message.eql? "No user with that id exists" |
||
| 264 | set_default_settings |
||
| 265 | |||
| 266 | render "errors/greenlight_error", locals: { message: I18n.t("errors.not_found.user_not_found.message"), |
||
| 267 | help: I18n.t("errors.not_found.user_not_found.help") } |
||
| 268 | elsif e.message.eql? "Provider not included." |
||
| 269 | set_default_settings |
||
| 270 | |||
| 271 | render "errors/greenlight_error", locals: { message: I18n.t("errors.not_found.user_missing.message"), |
||
| 272 | help: I18n.t("errors.not_found.user_missing.help") } |
||
| 273 | elsif e.message.eql? "That user has no configured provider." |
||
| 274 | if Setting.exists?(provider: @user_domain) |
||
| 275 | # Keep the branding |
||
| 276 | @settings = Setting.find_by(provider: @user_domain) |
||
| 277 | else |
||
| 278 | set_default_settings |
||
| 279 | end |
||
| 280 | |||
| 281 | render "errors/greenlight_error", locals: { status_code: 501, |
||
| 282 | message: I18n.t("errors.no_provider.message"), |
||
| 283 | help: I18n.t("errors.no_provider.help") } |
||
| 284 | else |
||
| 285 | set_default_settings |
||
| 286 | |||
| 287 | render "errors/greenlight_error", locals: { status_code: 500, message: I18n.t("errors.internal.message"), |
||
| 288 | help: I18n.t("errors.internal.help"), display_back: true } |
||
| 289 | end |
||
| 290 | end |
||
| 291 | end |
||
| 292 | |||
| 293 | def set_default_settings |
||
| 294 | # Use the default site settings |
||
| 295 | @user_domain = "greenlight" |
||
| 296 | @settings = Setting.find_or_create_by(provider: @user_domain) |
||
| 297 | end |
||
| 298 | end |
||
| 299 |