diff options
author | Tiago Botelho <tiagonbotelho@hotmail.com> | 2018-01-19 13:04:14 +0000 |
---|---|---|
committer | Tiago Botelho <tiagonbotelho@hotmail.com> | 2018-02-06 13:35:35 +0000 |
commit | 32b2ff26011a5274bdb8a3dd41ad360a67c3148a (patch) | |
tree | 56064e3de4e9ca505730bdf1af3597ba8ead499f | |
parent | 35882e681b681f68a818bda9a8d2624edfecc219 (diff) | |
download | gitlab-ce-32b2ff26011a5274bdb8a3dd41ad360a67c3148a.tar.gz |
Adds remote messsage when project is created in a push over SSH or HTTP
-rw-r--r-- | app/controllers/projects/git_http_controller.rb | 38 | ||||
-rw-r--r-- | app/models/project.rb | 4 | ||||
-rw-r--r-- | lib/api/helpers/internal_helpers.rb | 16 | ||||
-rw-r--r-- | lib/api/internal.rb | 17 | ||||
-rw-r--r-- | lib/gitlab/checks/new_project.rb | 60 | ||||
-rw-r--r-- | lib/gitlab/git_access.rb | 35 | ||||
-rw-r--r-- | lib/gitlab/git_access_wiki.rb | 4 | ||||
-rw-r--r-- | spec/lib/gitlab/git_access_spec.rb | 20 |
8 files changed, 150 insertions, 44 deletions
diff --git a/app/controllers/projects/git_http_controller.rb b/app/controllers/projects/git_http_controller.rb index 97c0f5b8c87..6010423c243 100644 --- a/app/controllers/projects/git_http_controller.rb +++ b/app/controllers/projects/git_http_controller.rb @@ -11,10 +11,14 @@ class Projects::GitHttpController < Projects::GitHttpClientController def info_refs log_user_activity if upload_pack? - if project.blank? && params[:service] == 'git-receive-pack' + if user && project.blank? && receive_pack? @project = ::Projects::CreateService.new(user, project_params).execute - return render_ok if @project.saved? + if @project.saved? + Gitlab::Checks::NewProject.new(user, @project, 'http').add_new_project_message + else + raise Gitlab::GitAccess::NotFoundError, 'Could not create project' + end end render_ok @@ -32,15 +36,6 @@ class Projects::GitHttpController < Projects::GitHttpClientController private - def project_params - { - description: "", - path: params[:project_id].gsub("\.git", ''), - namespace_id: namespace.id.to_s, - visibility_level: Gitlab::VisibilityLevel::PRIVATE.to_s - } - end - def download_request? upload_pack? end @@ -49,6 +44,10 @@ class Projects::GitHttpController < Projects::GitHttpClientController git_command == 'git-upload-pack' end + def receive_pack? + git_command == 'git-receive-pack' + end + def git_command if action_name == 'info_refs' params[:service] @@ -74,10 +73,6 @@ class Projects::GitHttpController < Projects::GitHttpClientController @access ||= access_klass.new(access_actor, project, 'http', authentication_abilities: authentication_abilities, redirected_path: redirected_path, target_namespace: namespace) end - def namespace - @namespace = Namespace.find_by_path_or_name(params[:namespace_id]) - end - def access_actor return user if user return :ci if ci? @@ -93,6 +88,19 @@ class Projects::GitHttpController < Projects::GitHttpClientController @access_klass ||= wiki? ? Gitlab::GitAccessWiki : Gitlab::GitAccess end + def project_params + { + description: "", + path: Project.parse_project_id(params[:project_id]), + namespace_id: namespace&.id, + visibility_level: Gitlab::VisibilityLevel::PRIVATE.to_s + } + end + + def namespace + @namespace ||= Namespace.find_by_path_or_name(params[:namespace_id]) + end + def log_user_activity Users::ActivityService.new(user, 'pull').execute end diff --git a/app/models/project.rb b/app/models/project.rb index 12d5f28f5ea..a4d83b2a79a 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -468,6 +468,10 @@ class Project < ActiveRecord::Base def group_ids joins(:namespace).where(namespaces: { type: 'Group' }).select(:namespace_id) end + + def parse_project_id(project_id) + project_id.gsub("\.git", '') + end end # returns all ancestor-groups upto but excluding the given namespace diff --git a/lib/api/helpers/internal_helpers.rb b/lib/api/helpers/internal_helpers.rb index eb67de81a0d..c0fcae43638 100644 --- a/lib/api/helpers/internal_helpers.rb +++ b/lib/api/helpers/internal_helpers.rb @@ -29,6 +29,10 @@ module API {} end + def receive_pack? + params[:action] == 'git-receive-pack' + end + def fix_git_env_repository_paths(env, repository_path) if obj_dir_relative = env['GIT_OBJECT_DIRECTORY_RELATIVE'].presence env['GIT_OBJECT_DIRECTORY'] = File.join(repository_path, obj_dir_relative) @@ -62,6 +66,18 @@ module API private + def project_path_regex + @project_regex ||= /\A(?<namespace_id>#{Gitlab::PathRegex.full_namespace_route_regex})\/(?<project_id>#{Gitlab::PathRegex.project_git_route_regex})\z/.freeze + end + + def project_match + @match ||= params[:project].match(project_path_regex).captures + end + + def namespace + @namespace ||= Namespace.find_by_path_or_name(project_match[:namespace_id]) + end + # rubocop:disable Gitlab/ModuleWithInstanceVariables def set_project if params[:gl_repository] diff --git a/lib/api/internal.rb b/lib/api/internal.rb index a83f714a1f3..f641ef457a3 100644 --- a/lib/api/internal.rb +++ b/lib/api/internal.rb @@ -43,7 +43,7 @@ module API access_checker_klass = wiki? ? Gitlab::GitAccessWiki : Gitlab::GitAccess access_checker = access_checker_klass - .new(actor, project, protocol, authentication_abilities: ssh_authentication_abilities, redirected_path: redirected_path, target_namespace: user.namespace) + .new(actor, project, protocol, authentication_abilities: ssh_authentication_abilities, redirected_path: redirected_path, target_namespace: namespace) begin access_checker.check(params[:action], params[:changes]) @@ -51,17 +51,21 @@ module API return { status: false, message: e.message } end - if project.blank? && params[:action] == 'git-receive-pack' + if user && project.blank? && receive_pack? project_params = { description: "", - path: params[:project].split('/').last.gsub("\.git", ''), - namespace_id: user.namespace.id.to_s, + path: Project.parse_project_id(project_match[:project_name]), + namespace_id: namespace&.id, visibility_level: Gitlab::VisibilityLevel::PRIVATE.to_s } @project = ::Projects::CreateService.new(user, project_params).execute - return { status: false, message: "Could not create project" } unless @project.saved? + if @project.saved? + Gitlab::Checks::NewProject.new(user, @project, protocol).add_new_project_message + else + return { status: false, message: "Could not create project" } + end end log_user_activity(actor) @@ -221,7 +225,10 @@ module API # key could be used if user redirect_message = Gitlab::Checks::ProjectMoved.fetch_redirect_message(user.id, project.id) + new_project_message = Gitlab::Checks::NewProject.fetch_new_project_message(user.id, project.id) + output[:redirected_message] = redirect_message if redirect_message + output[:new_project_message] = new_project_message if new_project_message end output diff --git a/lib/gitlab/checks/new_project.rb b/lib/gitlab/checks/new_project.rb new file mode 100644 index 00000000000..40d0acefaba --- /dev/null +++ b/lib/gitlab/checks/new_project.rb @@ -0,0 +1,60 @@ +module Gitlab + module Checks + class NewProject + NEW_PROJECT = "new_project".freeze + + def initialize(user, project, protocol) + @user = user + @project = project + @protocol = protocol + end + + def self.fetch_new_project_message(user_id, project_id) + new_project_key = new_project_message_key(user_id, project_id) + + Gitlab::Redis::SharedState.with do |redis| + message = redis.get(new_project_key) + redis.del(new_project_key) + message + end + end + + def add_new_project_message + Gitlab::Redis::SharedState.with do |redis| + key = self.class.new_project_message_key(user.id, project.id) + redis.setex(key, 5.minutes, new_project_message) + end + end + + def new_project_message + <<~MESSAGE.strip_heredoc + + The private project #{project.full_path} was created. + + To configure the remote, run: + git remote add origin #{git_url} + + To view the project, visit: + #{project_url} + + MESSAGE + end + + private + + attr_reader :project, :user, :protocol + + def self.new_project_message_key(user_id, project_id) + "#{NEW_PROJECT}:#{user_id}:#{project_id}" + end + + def project_url + Gitlab::Routing.url_helpers.project_url(project) + end + + def git_url + protocol == 'ssh' ? project.ssh_url_to_repo : project.http_url_to_repo + end + end + end +end diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb index 7de8a99f9dc..598506aa418 100644 --- a/lib/gitlab/git_access.rb +++ b/lib/gitlab/git_access.rb @@ -13,6 +13,7 @@ module Gitlab 'This deploy key does not have write access to this project.', no_repo: 'A repository for this project does not exist yet.', project_not_found: 'The project you were looking for could not be found.', + namespace_not_found: 'The namespace you were looking for could not be found.', account_blocked: 'Your account has been blocked.', command_not_allowed: "The command you're trying to execute is not allowed.", upload_pack_disabled_over_http: 'Pulling over HTTP is not allowed.', @@ -41,18 +42,18 @@ module Gitlab check_protocol! check_valid_actor! check_active_user! - check_project_accessibility! + check_project_accessibility!(cmd) check_project_moved! check_command_disabled!(cmd) check_command_existence!(cmd) - check_repository_existence! - check_repository_creation! + check_repository_existence!(cmd) case cmd when *DOWNLOAD_COMMANDS check_download_access! when *PUSH_COMMANDS - check_push_access!(changes) + check_push_access!(cmd, changes) + check_repository_creation!(cmd) end true @@ -98,8 +99,8 @@ module Gitlab end end - def check_project_accessibility! - if (project.blank? || !can_read_project?) && !can_create_project_in_namespace? + def check_project_accessibility!(cmd) + if (project.blank? || !can_read_project?) && !can_create_project_in_namespace?(cmd) raise NotFoundError, ERROR_MESSAGES[:project_not_found] end end @@ -142,16 +143,20 @@ module Gitlab end end - def check_repository_existence! - if (project.blank? || !project.repository.exists?) && !can_create_project_in_namespace? + def check_repository_existence!(cmd) + if (project.blank? || !project.repository.exists?) && !can_create_project_in_namespace?(cmd) raise UnauthorizedError, ERROR_MESSAGES[:no_repo] end end - def check_repository_creation! - return unless target_namespace + def check_repository_creation!(cmd) + return unless project.blank? - unless can_create_project_in_namespace? + unless target_namespace + raise NotFoundError, ERROR_MESSAGES[:namespace_not_found] + end + + unless can_create_project_in_namespace?(cmd) raise UnauthorizedError, ERROR_MESSAGES[:create] end end @@ -168,8 +173,8 @@ module Gitlab end end - def check_push_access!(changes) - return if can_create_project_in_namespace? + def check_push_access!(cmd, changes) + return if project.blank? && can_create_project_in_namespace?(cmd) if project.repository_read_only? raise UnauthorizedError, ERROR_MESSAGES[:read_only] @@ -247,8 +252,8 @@ module Gitlab end || Guest.can?(:read_project, project) end - def can_create_project_in_namespace? - return unless target_namespace + def can_create_project_in_namespace?(cmd) + return false unless PUSH_COMMANDS.include?(cmd) && target_namespace user.can?(:create_projects, target_namespace) end diff --git a/lib/gitlab/git_access_wiki.rb b/lib/gitlab/git_access_wiki.rb index 1c9477e84b2..f679b5e8ed6 100644 --- a/lib/gitlab/git_access_wiki.rb +++ b/lib/gitlab/git_access_wiki.rb @@ -25,6 +25,10 @@ module Gitlab true end + def check_repository_creation!(cmd) + # Method not used in wiki + end + def push_to_read_only_message ERROR_MESSAGES[:read_only] end diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb index 2009a8ac48c..457e219c1a5 100644 --- a/spec/lib/gitlab/git_access_spec.rb +++ b/spec/lib/gitlab/git_access_spec.rb @@ -501,15 +501,17 @@ describe Gitlab::GitAccess do end aggregate_failures do - matrix.each do |action, allowed| - check = -> { access.send(:check_push_access!, changes[action]) } - - if allowed - expect(&check).not_to raise_error, - -> { "expected #{action} to be allowed" } - else - expect(&check).to raise_error(Gitlab::GitAccess::UnauthorizedError), - -> { "expected #{action} to be disallowed" } + Gitlab::GitAccess::ALL_COMMANDS.each do |cmd| + matrix.each do |action, allowed| + check = -> { access.send(:check_push_access!, cmd, changes[action]) } + + if allowed + expect(&check).not_to raise_error, + -> { "expected #{action} to be allowed" } + else + expect(&check).to raise_error(Gitlab::GitAccess::UnauthorizedError), + -> { "expected #{action} to be disallowed" } + end end end end |