Fix templates API endpoint when project name has dots

parent 13ee246a
---
title: Fix templates API endpoint when project name has dots
merge_request: 31758
author:
type: fixed
...@@ -5,6 +5,10 @@ module API ...@@ -5,6 +5,10 @@ module API
include PaginationParams include PaginationParams
TEMPLATE_TYPES = %w[dockerfiles gitignores gitlab_ci_ymls licenses].freeze TEMPLATE_TYPES = %w[dockerfiles gitignores gitlab_ci_ymls licenses].freeze
# The regex is needed to ensure a period (e.g. agpl-3.0)
# isn't confused with a format type. We also need to allow encoded
# values (e.g. C%2B%2B for C++), so allow % and + as well.
TEMPLATE_NAMES_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(name: /[\w%.+-]+/)
before { authenticate_non_get! } before { authenticate_non_get! }
...@@ -36,10 +40,8 @@ module API ...@@ -36,10 +40,8 @@ module API
optional :project, type: String, desc: 'The project name to use when expanding placeholders in the template. Only affects licenses' optional :project, type: String, desc: 'The project name to use when expanding placeholders in the template. Only affects licenses'
optional :fullname, type: String, desc: 'The full name of the copyright holder to use when expanding placeholders in the template. Only affects licenses' optional :fullname, type: String, desc: 'The full name of the copyright holder to use when expanding placeholders in the template. Only affects licenses'
end end
# The regex is needed to ensure a period (e.g. agpl-3.0)
# isn't confused with a format type. We also need to allow encoded get ':id/templates/:type/:name', requirements: TEMPLATE_NAMES_ENDPOINT_REQUIREMENTS do
# values (e.g. C%2B%2B for C++), so allow % and + as well.
get ':id/templates/:type/:name', requirements: { name: /[\w%.+-]+/ } do
template = TemplateFinder template = TemplateFinder
.build(params[:type], user_project, name: params[:name]) .build(params[:type], user_project, name: params[:name])
.execute .execute
......
...@@ -7,16 +7,24 @@ describe API::ProjectTemplates do ...@@ -7,16 +7,24 @@ describe API::ProjectTemplates do
let_it_be(:private_project) { create(:project, :private) } let_it_be(:private_project) { create(:project, :private) }
let_it_be(:developer) { create(:user) } let_it_be(:developer) { create(:user) }
let(:url_encoded_path) { "#{public_project.namespace.path}%2F#{public_project.path}" }
before do before do
private_project.add_developer(developer) private_project.add_developer(developer)
end end
describe 'GET /projects/:id/templates/:type' do shared_examples 'accepts project paths with dots' do
it 'accepts project paths with dots' do it do
get api("/projects/#{public_project.namespace.path}%2F#{public_project.path}/templates/dockerfiles") subject
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
end end
end
describe 'GET /projects/:id/templates/:type' do
it_behaves_like 'accepts project paths with dots' do
subject { get api("/projects/#{url_encoded_path}/templates/dockerfiles") }
end
it 'returns dockerfiles' do it 'returns dockerfiles' do
get api("/projects/#{public_project.id}/templates/dockerfiles") get api("/projects/#{public_project.id}/templates/dockerfiles")
...@@ -81,6 +89,10 @@ describe API::ProjectTemplates do ...@@ -81,6 +89,10 @@ describe API::ProjectTemplates do
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('public_api/v4/template_list') expect(response).to match_response_schema('public_api/v4/template_list')
end end
it_behaves_like 'accepts project paths with dots' do
subject { get api("/projects/#{url_encoded_path}/templates/licenses") }
end
end end
describe 'GET /projects/:id/templates/:type/:key' do describe 'GET /projects/:id/templates/:type/:key' do
...@@ -150,6 +162,10 @@ describe API::ProjectTemplates do ...@@ -150,6 +162,10 @@ describe API::ProjectTemplates do
expect(response).to match_response_schema('public_api/v4/license') expect(response).to match_response_schema('public_api/v4/license')
end end
it_behaves_like 'accepts project paths with dots' do
subject { get api("/projects/#{url_encoded_path}/templates/gitlab_ci_ymls/Android") }
end
shared_examples 'path traversal attempt' do |template_type| shared_examples 'path traversal attempt' do |template_type|
it 'rejects invalid filenames' do it 'rejects invalid filenames' do
get api("/projects/#{public_project.id}/templates/#{template_type}/%2e%2e%2fPython%2ea") get api("/projects/#{public_project.id}/templates/#{template_type}/%2e%2e%2fPython%2ea")
...@@ -179,5 +195,9 @@ describe API::ProjectTemplates do ...@@ -179,5 +195,9 @@ describe API::ProjectTemplates do
expect(content).to include('Project Placeholder') expect(content).to include('Project Placeholder')
expect(content).to include("Copyright (C) #{Time.now.year} Fullname Placeholder") expect(content).to include("Copyright (C) #{Time.now.year} Fullname Placeholder")
end end
it_behaves_like 'accepts project paths with dots' do
subject { get api("/projects/#{url_encoded_path}/templates/licenses/mit") }
end
end end
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