application_controller.rb 6.87 KB
Newer Older
1 2
require 'gon'

3
class ApplicationController < ActionController::Base
4
  before_filter :store_location
gitlabhq's avatar
gitlabhq committed
5
  before_filter :authenticate_user!
6
  before_filter :reject_blocked!
7
  before_filter :check_password_expiration
8
  before_filter :add_abilities
9
  before_filter :ldap_security_check
randx's avatar
randx committed
10
  before_filter :dev_tools if Rails.env == 'development'
11
  before_filter :default_headers
12
  before_filter :add_gon_variables
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
13
  before_filter :configure_permitted_parameters, if: :devise_controller?
14
  before_filter :require_email, unless: :devise_controller?
15

gitlabhq's avatar
gitlabhq committed
16
  protect_from_forgery
17

gitlabhq's avatar
gitlabhq committed
18 19
  helper_method :abilities, :can?

20
  rescue_from Encoding::CompatibilityError do |exception|
Riyad Preukschas's avatar
Riyad Preukschas committed
21
    log_exception(exception)
Cyril's avatar
Cyril committed
22
    render "errors/encoding", layout: "errors", status: 500
23 24
  end

25
  rescue_from ActiveRecord::RecordNotFound do |exception|
Riyad Preukschas's avatar
Riyad Preukschas committed
26
    log_exception(exception)
Cyril's avatar
Cyril committed
27
    render "errors/not_found", layout: "errors", status: 404
gitlabhq's avatar
gitlabhq committed
28 29
  end

Nihad Abbasov's avatar
Nihad Abbasov committed
30
  protected
gitlabhq's avatar
gitlabhq committed
31

Riyad Preukschas's avatar
Riyad Preukschas committed
32 33 34 35 36 37
  def log_exception(exception)
    application_trace = ActionDispatch::ExceptionWrapper.new(env, exception).application_trace
    application_trace.map!{ |t| "  #{t}\n" }
    logger.error "\n#{exception.class.name} (#{exception.message}):\n#{application_trace.join}"
  end

38
  def reject_blocked!
39
    if current_user && current_user.blocked?
40
      sign_out current_user
41
      flash[:alert] = "Your account is blocked. Retry when an admin has unblocked it."
42 43 44 45
      redirect_to new_user_session_path
    end
  end

randx's avatar
randx committed
46
  def after_sign_in_path_for resource
47
    if resource.is_a?(User) && resource.respond_to?(:blocked?) && resource.blocked?
randx's avatar
randx committed
48
      sign_out resource
49
      flash[:alert] = "Your account is blocked. Retry when an admin has unblocked it."
randx's avatar
randx committed
50 51
      new_user_session_path
    else
52 53 54 55 56 57 58 59 60 61 62 63
      session[:previous_url] || root_path
    end
  end

  def store_location
  # store last url - this is needed for post-login redirect to whatever the user last visited.
    if (request.fullpath != "/users/sign_in" &&
        request.fullpath != "/users/sign_up" &&
        request.fullpath != "/users/password" &&
        request.fullpath != "/users/sign_out" &&
        !request.xhr?) # don't store ajax calls
      session[:previous_url] = request.fullpath
randx's avatar
randx committed
64 65 66
    end
  end

gitlabhq's avatar
gitlabhq committed
67 68 69 70 71 72 73 74
  def abilities
    @abilities ||= Six.new
  end

  def can?(object, action, subject)
    abilities.allowed?(object, action, subject)
  end

Nihad Abbasov's avatar
Nihad Abbasov committed
75
  def project
76 77
    id = params[:project_id] || params[:id]

78 79 80 81 82 83 84 85 86
    # Redirect from
    #   localhost/group/project.git
    # to
    #   localhost/group/project
    #
    if id =~ /\.git\Z/
      redirect_to request.original_url.gsub(/\.git\Z/, '') and return
    end

87 88 89 90
    @project = Project.find_with_namespace(id)

    if @project and can?(current_user, :read_project, @project)
      @project
91 92 93
    elsif current_user.nil?
      @project = nil
      authenticate_user!
94 95
    else
      @project = nil
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
96
      render_404 and return
97
    end
gitlabhq's avatar
gitlabhq committed
98 99
  end

Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
100 101 102 103 104 105
  def repository
    @repository ||= project.repository
  rescue Grit::NoSuchPathError
    nil
  end

106
  def add_abilities
gitlabhq's avatar
gitlabhq committed
107 108 109 110
    abilities << Ability
  end

  def authorize_project!(action)
111
    return access_denied! unless can?(current_user, action, project)
gitlabhq's avatar
gitlabhq committed
112 113
  end

114
  def authorize_code_access!
115
    return access_denied! unless can?(current_user, :download_code, project)
116 117
  end

118 119 120 121
  def authorize_push!
    return access_denied! unless can?(current_user, :push_code, project)
  end

122 123 124 125 126
  def authorize_labels!
    # Labels should be accessible for issues and/or merge requests
    authorize_read_issue! || authorize_read_merge_request!
  end

gitlabhq's avatar
gitlabhq committed
127
  def access_denied!
Cyril's avatar
Cyril committed
128
    render "errors/access_denied", layout: "errors", status: 404
129 130 131
  end

  def not_found!
Cyril's avatar
Cyril committed
132
    render "errors/not_found", layout: "errors", status: 404
133 134 135
  end

  def git_not_found!
Cyril's avatar
Cyril committed
136
    render "errors/git_not_found", layout: "errors", status: 404
gitlabhq's avatar
gitlabhq committed
137 138 139 140 141 142 143 144 145
  end

  def method_missing(method_sym, *arguments, &block)
    if method_sym.to_s =~ /^authorize_(.*)!$/
      authorize_project!($1.to_sym)
    else
      super
    end
  end
gitlabhq's avatar
gitlabhq committed
146

147 148
  def render_403
    head :forbidden
gitlabhq's avatar
gitlabhq committed
149
  end
gitlabhq's avatar
gitlabhq committed
150

151 152
  def render_404
    render file: Rails.root.join("public", "404"), layout: false, status: "404"
153 154
  end

gitlabhq's avatar
gitlabhq committed
155
  def require_non_empty_project
156
    redirect_to @project if @project.empty_repo?
gitlabhq's avatar
gitlabhq committed
157
  end
158

159 160 161 162 163
  def no_cache_headers
    response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
    response.headers["Pragma"] = "no-cache"
    response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"
  end
164

randx's avatar
randx committed
165 166
  def dev_tools
  end
167

168 169 170
  def default_headers
    headers['X-Frame-Options'] = 'DENY'
    headers['X-XSS-Protection'] = '1; mode=block'
xyb's avatar
xyb committed
171
    headers['X-UA-Compatible'] = 'IE=edge'
172
    headers['X-Content-Type-Options'] = 'nosniff'
173
    headers['Strict-Transport-Security'] = 'max-age=31536000' if Gitlab.config.gitlab.https
174
  end
175 176 177

  def add_gon_variables
    gon.default_issues_tracker = Project.issues_tracker.default_value
178
    gon.api_version = API::API.version
179
    gon.relative_url_root = Gitlab.config.gitlab.relative_url_root
180
    gon.default_avatar_url = URI::join(Gitlab.config.gitlab.url, ActionController::Base.helpers.image_path('no_avatar.png')).to_s
181 182 183 184 185

    if current_user
      gon.current_user_id = current_user.id
      gon.api_token = current_user.private_token
    end
186
  end
187 188

  def check_password_expiration
189
    if current_user && current_user.password_expires_at && current_user.password_expires_at < Time.now  && !current_user.ldap_user?
190 191 192
      redirect_to new_profile_password_path and return
    end
  end
193

194
  def ldap_security_check
195
    if current_user && current_user.requires_ldap_check?
196 197 198 199 200 201 202 203 204
      gitlab_ldap_access do |access|
        if access.allowed?(current_user)
          current_user.last_credential_check_at = Time.now
          current_user.save
        else
          sign_out current_user
          flash[:alert] = "Access denied for your LDAP account."
          redirect_to new_user_session_path
        end
205 206 207 208
      end
    end
  end

209 210 211 212
  def event_filter
    filters = cookies['event_filter'].split(',') if cookies['event_filter'].present?
    @event_filter ||= EventFilter.new(filters)
  end
213

214 215
  def gitlab_ldap_access(&block)
    Gitlab::LDAP::Access.open { |access| block.call(access) }
216 217
  end

218 219 220 221 222 223 224 225 226 227 228 229 230
  # JSON for infinite scroll via Pager object
  def pager_json(partial, count)
    html = render_to_string(
      partial,
      layout: false,
      formats: [:html]
    )

    render json: {
      html: html,
      count: count
    }
  end
231 232 233 234 235 236 237 238

  def view_to_html_string(partial)
    render_to_string(
      partial,
      layout: false,
      formats: [:html]
    )
  end
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
239 240

  def configure_permitted_parameters
241
    devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:username, :email, :password, :login, :remember_me) }
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
242 243
    devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:username, :email, :name, :password, :password_confirmation) }
  end
244 245 246 247

  def hexdigest(string)
    Digest::SHA1.hexdigest string
  end
248 249 250 251 252 253

  def require_email
    if current_user && current_user.temp_oauth_email?
      redirect_to profile_path, notice: 'Please complete your profile with email address' and return
    end
  end
gitlabhq's avatar
gitlabhq committed
254
end