Commit 3be9d2c4 authored by Ben Ford's avatar Ben Ford Committed by Douwe Maan

Add ability to create directories in the editor

Simply type a name with a `/` directory separator and new directories
will be created. This does not do the fancy UI work that github.com
does, but it will get the job done.

I could not find tests for file creation, so I didn't add a test for
this slight behaviour modification. I did test directory traversals
though, using both absolute paths like `/tmp/foo.txt` and relative paths
like `../../foo.txt`. Neither case escaped the repository, though
attempting to traverse with a relative path resulted in a 500 error that
did not affect application stability upon reload.
parent ae99720a
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
development
- Adds ability to create directories using the web editor
v 8.2.0 (unreleased) v 8.2.0 (unreleased)
- Improved performance of replacing references in comments - Improved performance of replacing references in comments
- Show last project commit to default branch on project home page - Show last project commit to default branch on project home page
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
.editor-file-name { .editor-file-name {
.new-file-name { .new-file-name {
display: inline-block; display: inline-block;
width: 200px; width: 450px;
} }
.form-control { .form-control {
......
...@@ -161,7 +161,7 @@ class Projects::BlobController < Projects::ApplicationController ...@@ -161,7 +161,7 @@ class Projects::BlobController < Projects::ApplicationController
if params[:file].present? if params[:file].present?
params[:file_name] = params[:file].original_filename params[:file_name] = params[:file].original_filename
end end
File.join(@path, File.basename(params[:file_name])) File.join(@path, params[:file_name])
else else
@path @path
end end
......
...@@ -5,5 +5,16 @@ module Files ...@@ -5,5 +5,16 @@ module Files
def commit def commit
repository.commit_dir(current_user, @file_path, @commit_message, @target_branch) repository.commit_dir(current_user, @file_path, @commit_message, @target_branch)
end end
def validate
super
unless @file_path =~ Gitlab::Regex.file_path_regex
raise_error(
'Your changes could not be committed, because the file path ' +
Gitlab::Regex.file_path_regex_message
)
end
end
end end
end end
...@@ -9,12 +9,17 @@ module Files ...@@ -9,12 +9,17 @@ module Files
def validate def validate
super super
file_name = File.basename(@file_path) if @file_path =~ Gitlab::Regex.directory_traversal_regex
raise_error(
'Your changes could not be committed, because the file name ' +
Gitlab::Regex.directory_traversal_regex_message
)
end
unless file_name =~ Gitlab::Regex.file_name_regex unless @file_path =~ Gitlab::Regex.file_path_regex
raise_error( raise_error(
'Your changes could not be committed, because the file name ' + 'Your changes could not be committed, because the file name ' +
Gitlab::Regex.file_name_regex_message Gitlab::Regex.file_path_regex_message
) )
end end
......
...@@ -90,6 +90,16 @@ Feature: Project Source Browse Files ...@@ -90,6 +90,16 @@ Feature: Project Source Browse Files
Then I am on the new file page Then I am on the new file page
And I see a commit error message And I see a commit error message
@javascript
Scenario: I can create file with a directory name
Given I click on "New file" link in repo
And I fill the new file name with a new directory
And I edit code
And I fill the commit message
And I click on "Commit changes"
Then I am redirected to the new file with directory
And I should see its new content
@javascript @javascript
Scenario: I can edit file Scenario: I can edit file
Given I click on ".gitignore" file in repo Given I click on ".gitignore" file in repo
......
...@@ -78,6 +78,10 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps ...@@ -78,6 +78,10 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
fill_in :file_name, with: 'Spaces Not Allowed' fill_in :file_name, with: 'Spaces Not Allowed'
end end
step 'I fill the new file name with a new directory' do
fill_in :file_name, with: new_file_name_with_directory
end
step 'I fill the commit message' do step 'I fill the commit message' do
fill_in :commit_message, with: 'Not yet a commit message.', visible: true fill_in :commit_message, with: 'Not yet a commit message.', visible: true
end end
...@@ -238,6 +242,11 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps ...@@ -238,6 +242,11 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
@project.namespace, @project, 'master/' + new_file_name)) @project.namespace, @project, 'master/' + new_file_name))
end end
step 'I am redirected to the new file with directory' do
expect(current_path).to eq(namespace_project_blob_path(
@project.namespace, @project, 'master/' + new_file_name_with_directory))
end
step 'I am redirected to the new file on new branch' do step 'I am redirected to the new file on new branch' do
expect(current_path).to eq(namespace_project_blob_path( expect(current_path).to eq(namespace_project_blob_path(
@project.namespace, @project, 'new_branch_name/' + new_file_name)) @project.namespace, @project, 'new_branch_name/' + new_file_name))
...@@ -335,6 +344,12 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps ...@@ -335,6 +344,12 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
'not_a_file.md' 'not_a_file.md'
end end
# Constant value that is a valid filename with directory and
# not a filename present at root of the seed repository.
def new_file_name_with_directory
'foo/bar/baz.txt'
end
# Constant value that is a valid directory and # Constant value that is a valid directory and
# not a directory present at root of the seed repository. # not a directory present at root of the seed repository.
def new_dir_name def new_dir_name
......
...@@ -51,6 +51,23 @@ module Gitlab ...@@ -51,6 +51,23 @@ module Gitlab
"can contain only letters, digits, '_', '-' and '.'. " "can contain only letters, digits, '_', '-' and '.'. "
end end
def file_path_regex
@file_path_regex ||= /\A[a-zA-Z0-9_\-\.\/]*\z/.freeze
end
def file_path_regex_message
"can contain only letters, digits, '_', '-' and '.'. Separate directories with a '/'. "
end
def directory_traversal_regex
@directory_traversal_regex ||= /\.{2}/.freeze
end
def directory_traversal_regex_message
"cannot include directory traversal. "
end
def archive_formats_regex def archive_formats_regex
# |zip|tar| tar.gz | tar.bz2 | # |zip|tar| tar.gz | tar.bz2 |
......
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