Dry up routable lookups. Fixes #30317

Note: This changes the behavior of user lookups (see the spec change) so it acts the same way as groups and projects. Unauthenticated clients attempting to access a user page will be redirected to login whether the user exists and is publicly restricted, or does not exist at all.
This commit is contained in:
Michael Kozono 2017-05-04 14:20:13 -07:00
parent e4bcc90d95
commit 9e48f02ea8
5 changed files with 58 additions and 55 deletions

View file

@ -1,12 +1,36 @@
module RoutableActions
extend ActiveSupport::Concern
def find_routable!(routable_klass, requested_full_path, extra_authorization_method: nil)
routable = routable_klass.find_by_full_path(requested_full_path, follow_redirects: request.get?)
if authorized?(routable_klass, routable, extra_authorization_method)
ensure_canonical_path(routable, requested_full_path)
routable
else
route_not_found
nil
end
end
def authorized?(routable_klass, routable, extra_authorization_method)
action = :"read_#{routable_klass.to_s.underscore}"
return false unless can?(current_user, action, routable)
if extra_authorization_method
send(extra_authorization_method, routable)
else
true
end
end
def ensure_canonical_path(routable, requested_path)
return unless request.get?
if routable.full_path != requested_path
canonical_path = routable.try(:full_path) || routable.namespace.full_path
if canonical_path != requested_path
flash[:notice] = 'This project has moved to this location. Please update your links and bookmarks.'
redirect_to request.original_url.sub(requested_path, routable.full_path)
redirect_to request.original_url.sub(requested_path, canonical_path)
end
end
end

View file

@ -9,20 +9,11 @@ class Groups::ApplicationController < ApplicationController
private
def group
unless @group
given_path = params[:group_id] || params[:id]
@group = Group.find_by_full_path(given_path, follow_redirects: request.get?)
@group ||= find_routable!(Group, requested_full_path)
end
if @group && can?(current_user, :read_group, @group)
ensure_canonical_path(@group, given_path)
else
@group = nil
route_not_found
end
end
@group
def requested_full_path
params[:group_id] || params[:id]
end
def group_projects

View file

@ -2,6 +2,7 @@ class Projects::ApplicationController < ApplicationController
include RoutableActions
skip_before_action :authenticate_user!
before_action :redirect_git_extension
before_action :project
before_action :repository
layout 'project'
@ -10,34 +11,30 @@ class Projects::ApplicationController < ApplicationController
private
def project
unless @project
namespace = params[:namespace_id]
id = params[:project_id] || params[:id]
# Redirect from
# localhost/group/project.git
# to
# localhost/group/project
#
if params[:format] == 'git'
redirect_to request.original_url.gsub(/\.git\/?\Z/, '')
return
end
project_path = "#{namespace}/#{id}"
@project = Project.find_by_full_path(project_path, follow_redirects: request.get?)
if can?(current_user, :read_project, @project) && !@project.pending_delete?
ensure_canonical_path(@project, project_path)
else
@project = nil
route_not_found
end
def redirect_git_extension
# Redirect from
# localhost/group/project.git
# to
# localhost/group/project
#
if params[:format] == 'git'
redirect_to request.original_url.gsub(/\.git\/?\Z/, '')
return
end
end
@project
def project
@project ||= find_routable!(Project, requested_full_path, extra_authorization_method: :project_not_being_deleted?)
end
def requested_full_path
namespace = params[:namespace_id]
id = params[:project_id] || params[:id]
"#{namespace}/#{id}"
end
def project_not_being_deleted?(project)
!project.pending_delete?
end
def repository

View file

@ -93,16 +93,7 @@ class UsersController < ApplicationController
private
def user
return @user if @user
@user = User.find_by_full_path(params[:username], follow_redirects: true)
return render_404 unless @user
return render_404 unless can?(current_user, :read_user, @user)
ensure_canonical_path(@user.namespace, params[:username])
@user
@user ||= find_routable!(User, params[:username])
end
def contributed_projects

View file

@ -36,9 +36,9 @@ describe UsersController do
end
context 'when logged out' do
it 'renders 404' do
it 'redirects to login page' do
get :show, username: user.username
expect(response).to have_http_status(404)
expect(response).to redirect_to new_user_session_path
end
end
@ -88,9 +88,9 @@ describe UsersController do
context 'when a user by that username does not exist' do
context 'when logged out' do
it 'renders 404 (does not redirect to login)' do
it 'redirects to login page' do
get :show, username: 'nonexistent'
expect(response).to have_http_status(404)
expect(response).to redirect_to new_user_session_path
end
end