Redmine 4.1.1

This commit is contained in:
Manuel Cillero 2020-11-22 21:20:06 +01:00
parent 33e7b881a5
commit 3d976f1b3b
1593 changed files with 36180 additions and 19489 deletions

View file

@ -1,5 +1,7 @@
# frozen_string_literal: true
# Redmine - project management software
# Copyright (C) 2006-2017 Jean-Philippe Lang
# Copyright (C) 2006-2019 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
@ -18,14 +20,17 @@
require 'uri'
require 'cgi'
class Unauthorized < Exception; end
class Unauthorized < StandardError; end
class ApplicationController < ActionController::Base
include Redmine::I18n
include Redmine::Pagination
include Redmine::Hook::Helper
include RoutesHelper
include AvatarsHelper
helper :routes
helper :avatars
class_attribute :accept_api_auth_actions
class_attribute :accept_rss_auth_actions
@ -52,6 +57,7 @@ class ApplicationController < ActionController::Base
end
before_action :session_expiration, :user_setup, :check_if_login_required, :set_localization, :check_password_change
after_action :record_project_usage
rescue_from ::Unauthorized, :with => :deny_access
rescue_from ::ActionView::MissingTemplate, :with => :missing_template
@ -112,7 +118,7 @@ class ApplicationController < ActionController::Base
if (key = api_key_from_request)
# Use API key
user = User.find_by_api_key(key)
elsif request.authorization.to_s =~ /\ABasic /i
elsif /\ABasic /i.match?(request.authorization.to_s)
# HTTP Basic, either username/password or API key/random
authenticate_with_http_basic do |username, password|
user = User.try_to_login(username, password) || User.find_by_api_key(username)
@ -229,9 +235,14 @@ class ApplicationController < ActionController::Base
format.any(:atom, :pdf, :csv) {
redirect_to signin_path(:back_url => url)
}
format.xml { head :unauthorized, 'WWW-Authenticate' => 'Basic realm="Redmine API"' }
format.api {
if Setting.rest_api_enabled? && accept_api_auth?
head(:unauthorized, 'WWW-Authenticate' => 'Basic realm="Redmine API"')
else
head(:forbidden)
end
}
format.js { head :unauthorized, 'WWW-Authenticate' => 'Basic realm="Redmine API"' }
format.json { head :unauthorized, 'WWW-Authenticate' => 'Basic realm="Redmine API"' }
format.any { head :unauthorized }
end
return false
@ -259,7 +270,11 @@ class ApplicationController < ActionController::Base
true
else
if @project && @project.archived?
@archived_project = @project
render_403 :message => :notice_not_authorized_archived_project
elsif @project && !@project.allows_to?(:controller => ctrl, :action => action)
# Project module is disabled
render_403
else
deny_access
end
@ -272,27 +287,31 @@ class ApplicationController < ActionController::Base
end
# Find project of id params[:id]
def find_project
@project = Project.find(params[:id])
def find_project(project_id=params[:id])
@project = Project.find(project_id)
rescue ActiveRecord::RecordNotFound
render_404
end
# Find project of id params[:project_id]
def find_project_by_project_id
@project = Project.find(params[:project_id])
rescue ActiveRecord::RecordNotFound
render_404
find_project(params[:project_id])
end
# Find project of id params[:id] if present
def find_optional_project_by_id
if params[:id].present?
find_project(params[:id])
end
end
# Find a project based on params[:project_id]
# TODO: some subclasses override this, see about merging their logic
# and authorize the user for the requested action
def find_optional_project
@project = Project.find(params[:project_id]) unless params[:project_id].blank?
allowed = User.current.allowed_to?({:controller => params[:controller], :action => params[:action]}, @project, :global => true)
allowed ? true : deny_access
rescue ActiveRecord::RecordNotFound
render_404
if params[:project_id].present?
find_project(params[:project_id])
end
authorize_global
end
# Finds and sets @project based on @object.project
@ -385,18 +404,30 @@ class ApplicationController < ActionController::Base
end
end
def record_project_usage
if @project && @project.id && User.current.logged? && User.current.allowed_to?(:view_project, @project)
Redmine::ProjectJumpBox.new(User.current).project_used(@project)
end
true
end
def back_url
url = params[:back_url]
if url.nil? && referer = request.env['HTTP_REFERER']
url = CGI.unescape(referer.to_s)
# URLs that contains the utf8=[checkmark] parameter added by Rails are
# parsed as invalid by URI.parse so the redirect to the back URL would
# not be accepted (ApplicationController#validate_back_url would return
# false)
url.gsub!(/(\?|&)utf8=\u2713&?/, '\1')
end
url
end
helper_method :back_url
def redirect_back_or_default(default, options={})
back_url = params[:back_url].to_s
if back_url.present? && valid_url = validate_back_url(back_url)
redirect_to(valid_url)
if back_url = validate_back_url(params[:back_url].to_s)
redirect_to(back_url)
return
elsif options[:referer]
redirect_to_referer_or default
@ -409,6 +440,8 @@ class ApplicationController < ActionController::Base
# Returns a validated URL string if back_url is a valid url for redirection,
# otherwise false
def validate_back_url(back_url)
return false if back_url.blank?
if CGI.unescape(back_url).include?('..')
return false
end
@ -431,11 +464,11 @@ class ApplicationController < ActionController::Base
path = uri.to_s
# Ensure that the remaining URL starts with a slash, followed by a
# non-slash character or the end
if path !~ %r{\A/([^/]|\z)}
if !%r{\A/([^/]|\z)}.match?(path)
return false
end
if path.match(%r{/(login|account/register|account/lost_password)})
if %r{/(login|account/register|account/lost_password)}.match?(path)
return false
end
@ -446,11 +479,13 @@ class ApplicationController < ActionController::Base
return path
end
private :validate_back_url
helper_method :validate_back_url
def valid_back_url?(back_url)
!!validate_back_url(back_url)
end
private :valid_back_url?
helper_method :valid_back_url?
# Redirects to the request referer if present, redirects to args or call block otherwise.
def redirect_to_referer_or(*args, &block)
@ -460,7 +495,7 @@ class ApplicationController < ActionController::Base
if args.any?
redirect_to *args
elsif block_given?
block.call
yield
else
raise "#redirect_to_referer_or takes arguments or a block"
end
@ -495,8 +530,8 @@ class ApplicationController < ActionController::Base
end
# Handler for ActionView::MissingTemplate exception
def missing_template
logger.warn "Missing template, responding with 404"
def missing_template(exception)
logger.warn "Missing template, responding with 404: #{exception}"
@project = nil
render_404
end
@ -616,7 +651,7 @@ class ApplicationController < ActionController::Base
# Returns a string that can be used as filename value in Content-Disposition header
def filename_for_content_disposition(name)
request.env['HTTP_USER_AGENT'] =~ %r{(MSIE|Trident|Edge)} ? ERB::Util.url_encode(name) : name
%r{(MSIE|Trident|Edge)}.match?(request.env['HTTP_USER_AGENT']) ? ERB::Util.url_encode(name) : name
end
def api_request?
@ -649,9 +684,9 @@ class ApplicationController < ActionController::Base
render_error "An error occurred while executing the query and has been logged. Please report this error to your Redmine administrator."
end
# Renders a 200 response for successful updates or deletions via the API
# Renders a 204 response for successful updates or deletions via the API
def render_api_ok
render_api_head :ok
render_api_head :no_content
end
# Renders a head API response