PageRenderTime 51ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/app/controllers/application_controller.rb

https://gitlab.com/toanalien/gitlab-ce
Ruby | 389 lines | 296 code | 75 blank | 18 comment | 58 complexity | 32322bf2c92f003973f416a9b91f5690 MD5 | raw file
  1. require 'gon'
  2. require 'fogbugz'
  3. class ApplicationController < ActionController::Base
  4. include Gitlab::CurrentSettings
  5. include Gitlab::GonHelper
  6. include GitlabRoutingHelper
  7. include PageLayoutHelper
  8. include WorkhorseHelper
  9. before_action :authenticate_user_from_token!
  10. before_action :authenticate_user!
  11. before_action :validate_user_service_ticket!
  12. before_action :reject_blocked!
  13. before_action :check_password_expiration
  14. before_action :check_2fa_requirement
  15. before_action :ldap_security_check
  16. before_action :sentry_context
  17. before_action :default_headers
  18. before_action :add_gon_variables
  19. before_action :configure_permitted_parameters, if: :devise_controller?
  20. before_action :require_email, unless: :devise_controller?
  21. protect_from_forgery with: :exception
  22. helper_method :abilities, :can?, :current_application_settings
  23. helper_method :import_sources_enabled?, :github_import_enabled?, :github_import_configured?, :gitlab_import_enabled?, :gitlab_import_configured?, :bitbucket_import_enabled?, :bitbucket_import_configured?, :gitorious_import_enabled?, :google_code_import_enabled?, :fogbugz_import_enabled?, :git_import_enabled?
  24. rescue_from Encoding::CompatibilityError do |exception|
  25. log_exception(exception)
  26. render "errors/encoding", layout: "errors", status: 500
  27. end
  28. rescue_from ActiveRecord::RecordNotFound do |exception|
  29. log_exception(exception)
  30. render_404
  31. end
  32. def redirect_back_or_default(default: root_path, options: {})
  33. redirect_to request.referer.present? ? :back : default, options
  34. end
  35. protected
  36. def sentry_context
  37. if Rails.env.production? && current_application_settings.sentry_enabled
  38. if current_user
  39. Raven.user_context(
  40. id: current_user.id,
  41. email: current_user.email,
  42. username: current_user.username,
  43. )
  44. end
  45. Raven.tags_context(program: sentry_program_context)
  46. end
  47. end
  48. def sentry_program_context
  49. if Sidekiq.server?
  50. 'sidekiq'
  51. else
  52. 'rails'
  53. end
  54. end
  55. # From https://github.com/plataformatec/devise/wiki/How-To:-Simple-Token-Authentication-Example
  56. # https://gist.github.com/josevalim/fb706b1e933ef01e4fb6
  57. def authenticate_user_from_token!
  58. user_token = if params[:authenticity_token].presence
  59. params[:authenticity_token].presence
  60. elsif params[:private_token].presence
  61. params[:private_token].presence
  62. elsif request.headers['PRIVATE-TOKEN'].present?
  63. request.headers['PRIVATE-TOKEN']
  64. end
  65. user = user_token && User.find_by_authentication_token(user_token.to_s)
  66. if user
  67. # Notice we are passing store false, so the user is not
  68. # actually stored in the session and a token is needed
  69. # for every request. If you want the token to work as a
  70. # sign in token, you can simply remove store: false.
  71. sign_in user, store: false
  72. end
  73. end
  74. def authenticate_user!(*args)
  75. if redirect_to_home_page_url?
  76. redirect_to current_application_settings.home_page_url and return
  77. end
  78. super(*args)
  79. end
  80. def log_exception(exception)
  81. application_trace = ActionDispatch::ExceptionWrapper.new(env, exception).application_trace
  82. application_trace.map!{ |t| " #{t}\n" }
  83. logger.error "\n#{exception.class.name} (#{exception.message}):\n#{application_trace.join}"
  84. end
  85. def reject_blocked!
  86. if current_user && current_user.blocked?
  87. sign_out current_user
  88. flash[:alert] = "Your account is blocked. Retry when an admin has unblocked it."
  89. redirect_to new_user_session_path
  90. end
  91. end
  92. def after_sign_in_path_for(resource)
  93. if resource.is_a?(User) && resource.respond_to?(:blocked?) && resource.blocked?
  94. sign_out resource
  95. flash[:alert] = "Your account is blocked. Retry when an admin has unblocked it."
  96. new_user_session_path
  97. else
  98. stored_location_for(:redirect) || stored_location_for(resource) || root_path
  99. end
  100. end
  101. def after_sign_out_path_for(resource)
  102. current_application_settings.after_sign_out_path.presence || new_user_session_path
  103. end
  104. def abilities
  105. Ability.abilities
  106. end
  107. def can?(object, action, subject)
  108. abilities.allowed?(object, action, subject)
  109. end
  110. def access_denied!
  111. render "errors/access_denied", layout: "errors", status: 404
  112. end
  113. def git_not_found!
  114. render "errors/git_not_found.html", layout: "errors", status: 404
  115. end
  116. def render_403
  117. head :forbidden
  118. end
  119. def render_404
  120. render file: Rails.root.join("public", "404"), layout: false, status: "404"
  121. end
  122. def no_cache_headers
  123. response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
  124. response.headers["Pragma"] = "no-cache"
  125. response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"
  126. end
  127. def default_headers
  128. headers['X-Frame-Options'] = 'DENY'
  129. headers['X-XSS-Protection'] = '1; mode=block'
  130. headers['X-UA-Compatible'] = 'IE=edge'
  131. headers['X-Content-Type-Options'] = 'nosniff'
  132. # Enabling HSTS for non-standard ports would send clients to the wrong port
  133. if Gitlab.config.gitlab.https and Gitlab.config.gitlab.port == 443
  134. headers['Strict-Transport-Security'] = 'max-age=31536000'
  135. end
  136. end
  137. def validate_user_service_ticket!
  138. return unless signed_in? && session[:service_tickets]
  139. valid = session[:service_tickets].all? do |provider, ticket|
  140. Gitlab::OAuth::Session.valid?(provider, ticket)
  141. end
  142. unless valid
  143. session[:service_tickets] = nil
  144. sign_out current_user
  145. redirect_to new_user_session_path
  146. end
  147. end
  148. def check_password_expiration
  149. if current_user && current_user.password_expires_at && current_user.password_expires_at < Time.now && !current_user.ldap_user?
  150. redirect_to new_profile_password_path and return
  151. end
  152. end
  153. def check_2fa_requirement
  154. if two_factor_authentication_required? && current_user && !current_user.two_factor_enabled? && !skip_two_factor?
  155. redirect_to profile_two_factor_auth_path
  156. end
  157. end
  158. def ldap_security_check
  159. if current_user && current_user.requires_ldap_check?
  160. return unless current_user.try_obtain_ldap_lease
  161. unless Gitlab::LDAP::Access.allowed?(current_user)
  162. sign_out current_user
  163. flash[:alert] = "Access denied for your LDAP account."
  164. redirect_to new_user_session_path
  165. end
  166. end
  167. end
  168. def event_filter
  169. filters = cookies['event_filter'].split(',') if cookies['event_filter'].present?
  170. @event_filter ||= EventFilter.new(filters)
  171. end
  172. def gitlab_ldap_access(&block)
  173. Gitlab::LDAP::Access.open { |access| block.call(access) }
  174. end
  175. # JSON for infinite scroll via Pager object
  176. def pager_json(partial, count)
  177. html = render_to_string(
  178. partial,
  179. layout: false,
  180. formats: [:html]
  181. )
  182. render json: {
  183. html: html,
  184. count: count
  185. }
  186. end
  187. def view_to_html_string(partial, locals = {})
  188. render_to_string(
  189. partial,
  190. locals: locals,
  191. layout: false,
  192. formats: [:html]
  193. )
  194. end
  195. def configure_permitted_parameters
  196. devise_parameter_sanitizer.permit(:sign_in, keys: [:username, :email, :password, :login, :remember_me, :otp_attempt])
  197. end
  198. def hexdigest(string)
  199. Digest::SHA1.hexdigest string
  200. end
  201. def require_email
  202. if current_user && current_user.temp_oauth_email?
  203. redirect_to profile_path, notice: 'Please complete your profile with email address' and return
  204. end
  205. end
  206. def set_filters_params
  207. set_default_sort
  208. params[:scope] = 'all' if params[:scope].blank?
  209. params[:state] = 'opened' if params[:state].blank?
  210. @sort = params[:sort]
  211. @filter_params = params.dup
  212. if @project
  213. @filter_params[:project_id] = @project.id
  214. elsif @group
  215. @filter_params[:group_id] = @group.id
  216. else
  217. # TODO: this filter ignore issues/mr created in public or
  218. # internal repos where you are not a member. Enable this filter
  219. # or improve current implementation to filter only issues you
  220. # created or assigned or mentioned
  221. # @filter_params[:authorized_only] = true
  222. end
  223. @filter_params
  224. end
  225. def get_issues_collection
  226. set_filters_params
  227. @issuable_finder = IssuesFinder.new(current_user, @filter_params)
  228. @issuable_finder.execute
  229. end
  230. def get_merge_requests_collection
  231. set_filters_params
  232. @issuable_finder = MergeRequestsFinder.new(current_user, @filter_params)
  233. @issuable_finder.execute
  234. end
  235. def import_sources_enabled?
  236. !current_application_settings.import_sources.empty?
  237. end
  238. def github_import_enabled?
  239. current_application_settings.import_sources.include?('github')
  240. end
  241. def github_import_configured?
  242. Gitlab::OAuth::Provider.enabled?(:github)
  243. end
  244. def gitlab_import_enabled?
  245. request.host != 'gitlab.com' && current_application_settings.import_sources.include?('gitlab')
  246. end
  247. def gitlab_import_configured?
  248. Gitlab::OAuth::Provider.enabled?(:gitlab)
  249. end
  250. def bitbucket_import_enabled?
  251. current_application_settings.import_sources.include?('bitbucket')
  252. end
  253. def bitbucket_import_configured?
  254. Gitlab::OAuth::Provider.enabled?(:bitbucket) && Gitlab::BitbucketImport.public_key.present?
  255. end
  256. def gitorious_import_enabled?
  257. current_application_settings.import_sources.include?('gitorious')
  258. end
  259. def google_code_import_enabled?
  260. current_application_settings.import_sources.include?('google_code')
  261. end
  262. def fogbugz_import_enabled?
  263. current_application_settings.import_sources.include?('fogbugz')
  264. end
  265. def git_import_enabled?
  266. current_application_settings.import_sources.include?('git')
  267. end
  268. def two_factor_authentication_required?
  269. current_application_settings.require_two_factor_authentication
  270. end
  271. def two_factor_grace_period
  272. current_application_settings.two_factor_grace_period
  273. end
  274. def two_factor_grace_period_expired?
  275. date = current_user.otp_grace_period_started_at
  276. date && (date + two_factor_grace_period.hours) < Time.current
  277. end
  278. def skip_two_factor?
  279. session[:skip_tfa] && session[:skip_tfa] > Time.current
  280. end
  281. def browser_supports_u2f?
  282. browser.chrome? && browser.version.to_i >= 41 && !browser.device.mobile?
  283. end
  284. def redirect_to_home_page_url?
  285. # If user is not signed-in and tries to access root_path - redirect him to landing page
  286. # Don't redirect to the default URL to prevent endless redirections
  287. return false unless current_application_settings.home_page_url.present?
  288. home_page_url = current_application_settings.home_page_url.chomp('/')
  289. root_urls = [Gitlab.config.gitlab['url'].chomp('/'), root_url.chomp('/')]
  290. return false if root_urls.include?(home_page_url)
  291. current_user.nil? && root_path == request.path
  292. end
  293. # U2F (universal 2nd factor) devices need a unique identifier for the application
  294. # to perform authentication.
  295. # https://developers.yubico.com/U2F/App_ID.html
  296. def u2f_app_id
  297. request.base_url
  298. end
  299. private
  300. def set_default_sort
  301. key = if is_a_listing_page_for?('issues') || is_a_listing_page_for?('merge_requests')
  302. 'issuable_sort'
  303. end
  304. cookies[key] = params[:sort] if key && params[:sort].present?
  305. params[:sort] = cookies[key] if key
  306. params[:sort] ||= 'id_desc'
  307. end
  308. def is_a_listing_page_for?(page_type)
  309. controller_name, action_name = params.values_at(:controller, :action)
  310. (controller_name == "projects/#{page_type}" && action_name == 'index') ||
  311. (controller_name == 'groups' && action_name == page_type) ||
  312. (controller_name == 'dashboard' && action_name == page_type)
  313. end
  314. end