Commit df5fb28a authored by Sean McGivern's avatar Sean McGivern

Ensure only IDs ending in .git perform git actions

It doesn't seem possible to set constraints based on format for project
IDs ending in .git, so set the constraint on the ID and ensure the
format is nil to avoid the case where the project ID is something like
project.git.foo.
parent 13fd88fa
...@@ -442,22 +442,6 @@ Rails.application.routes.draw do ...@@ -442,22 +442,6 @@ Rails.application.routes.draw do
resources(:projects, constraints: { id: /[a-zA-Z.0-9_\-]+(?<!\.atom)/ }, except: resources(:projects, constraints: { id: /[a-zA-Z.0-9_\-]+(?<!\.atom)/ }, except:
[:new, :create, :index], path: "/") do [:new, :create, :index], path: "/") do
# Allow /info/refs, /info/refs?service=git-upload-pack, and
# /info/refs?service=git-receive-pack, but nothing else.
#
git_http_handshake = lambda do |request|
request.query_string.blank? ||
request.query_string.match(/\Aservice=git-(upload|receive)-pack\z/)
end
ref_redirect = redirect do |params, request|
path = "#{params[:namespace_id]}/#{params[:project_id]}.git/info/refs"
path << "?#{request.query_string}" unless request.query_string.blank?
path
end
get '/info/refs', constraints: git_http_handshake, to: ref_redirect
member do member do
put :transfer put :transfer
delete :remove_fork delete :remove_fork
...@@ -472,12 +456,28 @@ Rails.application.routes.draw do ...@@ -472,12 +456,28 @@ Rails.application.routes.draw do
scope module: :projects do scope module: :projects do
# Git HTTP clients ('git clone' etc.) # Git HTTP clients ('git clone' etc.)
scope constraints: { format: /(git|wiki\.git)/ } do scope constraints: { id: /.+\.git/, format: nil } do
get '/info/refs', to: 'git_http#info_refs' get '/info/refs', to: 'git_http#info_refs'
post '/git-upload-pack', to: 'git_http#git_upload_pack' post '/git-upload-pack', to: 'git_http#git_upload_pack'
post '/git-receive-pack', to: 'git_http#git_receive_pack' post '/git-receive-pack', to: 'git_http#git_receive_pack'
end end
# Allow /info/refs, /info/refs?service=git-upload-pack, and
# /info/refs?service=git-receive-pack, but nothing else.
#
git_http_handshake = lambda do |request|
request.query_string.blank? ||
request.query_string.match(/\Aservice=git-(upload|receive)-pack\z/)
end
ref_redirect = redirect do |params, request|
path = "#{params[:namespace_id]}/#{params[:project_id]}.git/info/refs"
path << "?#{request.query_string}" unless request.query_string.blank?
path
end
get '/info/refs', constraints: git_http_handshake, to: ref_redirect
# Blob routes: # Blob routes:
get '/new/*id', to: 'blob#new', constraints: { id: /.+/ }, as: 'new_blob' get '/new/*id', to: 'blob#new', constraints: { id: /.+/ }, as: 'new_blob'
post '/create/*id', to: 'blob#create', constraints: { id: /.+/ }, as: 'create_blob' post '/create/*id', to: 'blob#create', constraints: { id: /.+/ }, as: 'create_blob'
......
...@@ -2,7 +2,7 @@ require "spec_helper" ...@@ -2,7 +2,7 @@ require "spec_helper"
describe 'Git HTTP requests', lib: true do describe 'Git HTTP requests', lib: true do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project) } let(:project) { create(:project, path: 'project.git-project') }
it "gives WWW-Authenticate hints" do it "gives WWW-Authenticate hints" do
clone_get('doesnt/exist.git') clone_get('doesnt/exist.git')
...@@ -268,6 +268,59 @@ describe 'Git HTTP requests', lib: true do ...@@ -268,6 +268,59 @@ describe 'Git HTTP requests', lib: true do
end end
end end
context "when the project path doesn't end in .git" do
context "GET info/refs" do
let(:path) { "/#{project.path_with_namespace}/info/refs" }
context "when no params are added" do
before { get path }
it "redirects to the .git suffix version" do
expect(response).to redirect_to("/#{project.path_with_namespace}.git/info/refs")
end
end
context "when the upload-pack service is requested" do
let(:params) { { service: 'git-upload-pack' } }
before { get path, params }
it "redirects to the .git suffix version" do
expect(response).to redirect_to("/#{project.path_with_namespace}.git/info/refs?service=#{params[:service]}")
end
end
context "when the receive-pack service is requested" do
let(:params) { { service: 'git-receive-pack' } }
before { get path, params }
it "redirects to the .git suffix version" do
expect(response).to redirect_to("/#{project.path_with_namespace}.git/info/refs?service=#{params[:service]}")
end
end
context "when the params are anything else" do
let(:params) { { service: 'git-implode-pack' } }
before { get path, params }
it "redirects to the sign-in page" do
expect(response).to redirect_to(new_user_session_path)
end
end
end
context "POST git-upload-pack" do
it "fails to find a route" do
expect { clone_post(project.path_with_namespace) }.to raise_error(ActionController::RoutingError)
end
end
context "POST git-receive-pack" do
it "failes to find a route" do
expect { push_post(project.path_with_namespace) }.to raise_error(ActionController::RoutingError)
end
end
end
def clone_get(project, options={}) def clone_get(project, options={})
get "/#{project}/info/refs", { service: 'git-upload-pack' }, auth_env(*options.values_at(:user, :password)) get "/#{project}/info/refs", { service: 'git-upload-pack' }, auth_env(*options.values_at(:user, :password))
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment