Commit db132bae authored by Markus Koller's avatar Markus Koller

Support redirect paths starting with a dash

We use a leading dash for certain things like the WebIDE, which
had the side effect of losing the `params[:continue][:to]` param when
opening the WebIDE on a project where the user doesn't have push access
and therefore needs to fork the project first.
parent 8fd2c084
...@@ -5,8 +5,8 @@ module InternalRedirect ...@@ -5,8 +5,8 @@ module InternalRedirect
def safe_redirect_path(path) def safe_redirect_path(path)
return unless path return unless path
# Verify that the string starts with a `/` but not a double `/`. # Verify that the string starts with a `/` and a known route character.
return unless path =~ %r{^/\w.*$} return unless path =~ %r{^/[-\w].*$}
uri = URI(path) uri = URI(path)
# Ignore anything path of the redirect except for the path, querystring and, # Ignore anything path of the redirect except for the path, querystring and,
......
---
title: Resolve "500 error when forking via the web IDE button"
merge_request: 29909
author:
type: fixed
...@@ -15,44 +15,71 @@ describe InternalRedirect do ...@@ -15,44 +15,71 @@ describe InternalRedirect do
subject(:controller) { controller_class.new } subject(:controller) { controller_class.new }
describe '#safe_redirect_path' do describe '#safe_redirect_path' do
it 'is `nil` for invalid uris' do where(:input) do
expect(controller.safe_redirect_path('Hello world')).to be_nil [
'Hello world',
'//example.com/hello/world',
'https://example.com/hello/world'
]
end end
it 'is `nil` for paths trying to include a host' do with_them 'being invalid' do
expect(controller.safe_redirect_path('//example.com/hello/world')).to be_nil it 'returns nil' do
expect(controller.safe_redirect_path(input)).to be_nil
end
end
where(:input) do
[
'/hello/world',
'/-/ide/project/path'
]
end end
it 'returns the path if it is valid' do with_them 'being valid' do
expect(controller.safe_redirect_path('/hello/world')).to eq('/hello/world') it 'returns the path' do
expect(controller.safe_redirect_path(input)).to eq(input)
end end
it 'returns the path with querystring if it is valid' do it 'returns the path with querystring and fragment' do
expect(controller.safe_redirect_path('/hello/world?hello=world#L123')) expect(controller.safe_redirect_path("#{input}?hello=world#L123"))
.to eq('/hello/world?hello=world#L123') .to eq("#{input}?hello=world#L123")
end
end end
end end
describe '#safe_redirect_path_for_url' do describe '#safe_redirect_path_for_url' do
it 'is `nil` for invalid urls' do where(:input) do
expect(controller.safe_redirect_path_for_url('Hello world')).to be_nil [
'Hello world',
'http://example.com/hello/world',
'http://test.host:3000/hello/world'
]
end end
it 'is `nil` for urls from a with a different host' do with_them 'being invalid' do
expect(controller.safe_redirect_path_for_url('http://example.com/hello/world')).to be_nil it 'returns nil' do
expect(controller.safe_redirect_path_for_url(input)).to be_nil
end
end end
it 'is `nil` for urls from a with a different port' do where(:input) do
expect(controller.safe_redirect_path_for_url('http://test.host:3000/hello/world')).to be_nil [
'http://test.host/hello/world'
]
end end
it 'returns the path if the url is on the same host' do with_them 'being on the same host' do
expect(controller.safe_redirect_path_for_url('http://test.host/hello/world')).to eq('/hello/world') let(:path) { URI(input).path }
it 'returns the path' do
expect(controller.safe_redirect_path_for_url(input)).to eq(path)
end end
it 'returns the path including querystring if the url is on the same host' do it 'returns the path with querystring and fragment' do
expect(controller.safe_redirect_path_for_url('http://test.host/hello/world?hello=world#L123')) expect(controller.safe_redirect_path_for_url("#{input}?hello=world#L123"))
.to eq('/hello/world?hello=world#L123') .to eq("#{path}?hello=world#L123")
end
end end
end end
...@@ -82,12 +109,16 @@ describe InternalRedirect do ...@@ -82,12 +109,16 @@ describe InternalRedirect do
end end
describe '#host_allowed?' do describe '#host_allowed?' do
it 'allows uris with the same host and port' do it 'allows URI with the same host and port' do
expect(controller.host_allowed?(URI('http://test.host/test'))).to be(true) expect(controller.host_allowed?(URI('http://test.host/test'))).to be(true)
end end
it 'rejects uris with other host and port' do it 'rejects URI with other host' do
expect(controller.host_allowed?(URI('http://example.com/test'))).to be(false) expect(controller.host_allowed?(URI('http://example.com/test'))).to be(false)
end end
it 'rejects URI with other port' do
expect(controller.host_allowed?(URI('http://test.host:3000/test'))).to be(false)
end
end end
end end
...@@ -115,24 +115,34 @@ describe Projects::ForksController do ...@@ -115,24 +115,34 @@ describe Projects::ForksController do
end end
describe 'POST create' do describe 'POST create' do
def post_create def post_create(params = {})
post :create, post :create,
params: { params: {
namespace_id: project.namespace, namespace_id: project.namespace,
project_id: project, project_id: project,
namespace_key: user.namespace.id namespace_key: user.namespace.id
} }.merge(params)
end end
context 'when user is signed in' do context 'when user is signed in' do
it 'responds with status 302' do before do
sign_in(user) sign_in(user)
end
it 'responds with status 302' do
post_create post_create
expect(response).to have_gitlab_http_status(302) expect(response).to have_gitlab_http_status(302)
expect(response).to redirect_to(namespace_project_import_path(user.namespace, project)) expect(response).to redirect_to(namespace_project_import_path(user.namespace, project))
end end
it 'passes continue params to the redirect' do
continue_params = { to: '/-/ide/project/path', notice: 'message' }
post_create continue: continue_params
expect(response).to have_gitlab_http_status(302)
expect(response).to redirect_to(namespace_project_import_path(user.namespace, project, continue: continue_params))
end
end end
context 'when user is not signed in' do context 'when user is not signed in' do
......
...@@ -118,19 +118,31 @@ describe 'Projects > Files > User edits files', :js do ...@@ -118,19 +118,31 @@ describe 'Projects > Files > User edits files', :js do
wait_for_requests wait_for_requests
end end
it 'inserts a content of a file in a forked project' do def expect_fork_prompt
click_link('.gitignore')
find('.js-edit-blob').click
expect(page).to have_link('Fork') expect(page).to have_link('Fork')
expect(page).to have_button('Cancel') expect(page).to have_button('Cancel')
expect(page).to have_content(
"You're not allowed to edit files in this project directly. "\
"Please fork this project, make your changes there, and submit a merge request."
)
end
click_link('Fork') def expect_fork_status
expect(page).to have_content( expect(page).to have_content(
"You're not allowed to make changes to this project directly. "\ "You're not allowed to make changes to this project directly. "\
"A fork of this project has been created that you can make changes in, so you can submit a merge request." "A fork of this project has been created that you can make changes in, so you can submit a merge request."
) )
end
it 'inserts a content of a file in a forked project' do
click_link('.gitignore')
click_button('Edit')
expect_fork_prompt
click_link('Fork')
expect_fork_status
find('.file-editor', match: :first) find('.file-editor', match: :first)
...@@ -140,12 +152,24 @@ describe 'Projects > Files > User edits files', :js do ...@@ -140,12 +152,24 @@ describe 'Projects > Files > User edits files', :js do
expect(evaluate_script('ace.edit("editor").getValue()')).to eq('*.rbca') expect(evaluate_script('ace.edit("editor").getValue()')).to eq('*.rbca')
end end
it 'opens the Web IDE in a forked project' do
click_link('.gitignore')
click_button('Web IDE')
expect_fork_prompt
click_link('Fork')
expect_fork_status
expect(page).to have_css('.ide .multi-file-tab', text: '.gitignore')
end
it 'commits an edited file in a forked project' do it 'commits an edited file in a forked project' do
click_link('.gitignore') click_link('.gitignore')
find('.js-edit-blob').click find('.js-edit-blob').click
expect(page).to have_link('Fork') expect_fork_prompt
expect(page).to have_button('Cancel')
click_link('Fork') click_link('Fork')
......
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