diff options
author | Tiago Botelho <tiagonbotelho@hotmail.com> | 2018-02-02 18:27:30 +0300 |
---|---|---|
committer | Tiago Botelho <tiagonbotelho@hotmail.com> | 2018-02-06 19:52:29 +0300 |
commit | 1e56b3f476f9779ec747534e94156a6b8076209c (patch) | |
tree | e9374a520232a2d96ef55bf3089dd5350db0a900 /lib | |
parent | 839829a7786dd163eccb470bf251211bfb90bd72 (diff) |
Moves project creationg to git access check for git push
Diffstat (limited to 'lib')
-rw-r--r-- | lib/api/helpers/internal_helpers.rb | 20 | ||||
-rw-r--r-- | lib/api/internal.rb | 15 | ||||
-rw-r--r-- | lib/gitlab/checks/post_push_message.rb (renamed from lib/gitlab/checks/base_project.rb) | 2 | ||||
-rw-r--r-- | lib/gitlab/checks/project_created.rb | 6 | ||||
-rw-r--r-- | lib/gitlab/checks/project_moved.rb | 4 | ||||
-rw-r--r-- | lib/gitlab/git_access.rb | 92 | ||||
-rw-r--r-- | lib/gitlab/path_regex.rb | 2 | ||||
-rw-r--r-- | lib/gitlab/user_access.rb | 3 |
8 files changed, 78 insertions, 66 deletions
diff --git a/lib/api/helpers/internal_helpers.rb b/lib/api/helpers/internal_helpers.rb index bff245fe9a2..cd59da6fc70 100644 --- a/lib/api/helpers/internal_helpers.rb +++ b/lib/api/helpers/internal_helpers.rb @@ -1,8 +1,6 @@ module API module Helpers module InternalHelpers - include Gitlab::Utils::StrongMemoize - attr_reader :redirected_path def wiki? @@ -49,10 +47,6 @@ module API ::Users::ActivityService.new(actor, 'Git SSH').execute if commands.include?(params[:action]) end - def receive_pack? - params[:action] == 'git-receive-pack' - end - def merge_request_urls ::MergeRequests::GetUrlsService.new(project).execute(params[:changes]) end @@ -66,16 +60,18 @@ module API false end - def project_namespace - strong_memoize(:project_namespace) do - project&.namespace || Namespace.find_by_full_path(project_match[:namespace_path]) - end + def project_path + project&.path || project_path_match[:project_path] + end + + def namespace_path + project&.namespace&.full_path || project_path_match[:namespace_path] end private - def project_match - @project_match ||= params[:project].match(Gitlab::PathRegex.full_project_git_path_regex) || {} + def project_path_match + @project_path_match ||= params[:project].match(Gitlab::PathRegex.full_project_git_path_regex) || {} end # rubocop:disable Gitlab/ModuleWithInstanceVariables diff --git a/lib/api/internal.rb b/lib/api/internal.rb index ed6d022df97..9285fb90cdc 100644 --- a/lib/api/internal.rb +++ b/lib/api/internal.rb @@ -42,23 +42,18 @@ module API end 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: project_namespace) + access_checker = access_checker_klass.new(actor, project, + protocol, authentication_abilities: ssh_authentication_abilities, + namespace_path: namespace_path, project_path: project_path, + redirected_path: redirected_path) begin access_checker.check(params[:action], params[:changes]) + @project ||= access_checker.project rescue Gitlab::GitAccess::UnauthorizedError, Gitlab::GitAccess::NotFoundError => e return { status: false, message: e.message } end - if receive_pack? && project.blank? - begin - @project = ::Projects::CreateFromPushService.new(user, project_match[:project_path], project_namespace, protocol).execute - rescue Gitlab::GitAccess::ProjectCreationError => e - return { status: false, message: e.message } - end - end - log_user_activity(actor) { diff --git a/lib/gitlab/checks/base_project.rb b/lib/gitlab/checks/post_push_message.rb index dd6c007b356..473c0385b34 100644 --- a/lib/gitlab/checks/base_project.rb +++ b/lib/gitlab/checks/post_push_message.rb @@ -1,6 +1,6 @@ module Gitlab module Checks - class BaseProject + class PostPushMessage def initialize(project, user, protocol) @project = project @user = user diff --git a/lib/gitlab/checks/project_created.rb b/lib/gitlab/checks/project_created.rb index bd1e204bc81..cec270d6a58 100644 --- a/lib/gitlab/checks/project_created.rb +++ b/lib/gitlab/checks/project_created.rb @@ -1,12 +1,12 @@ module Gitlab module Checks - class ProjectCreated < BaseProject + class ProjectCreated < PostPushMessage PROJECT_CREATED = "project_created".freeze def message - <<~MESSAGE.strip_heredoc + <<~MESSAGE - The private project #{project.full_path} was created. + The private project #{project.full_path} was successfully created. To configure the remote, run: git remote add origin #{url_to_repo} diff --git a/lib/gitlab/checks/project_moved.rb b/lib/gitlab/checks/project_moved.rb index eca59e88e24..3263790a876 100644 --- a/lib/gitlab/checks/project_moved.rb +++ b/lib/gitlab/checks/project_moved.rb @@ -1,6 +1,6 @@ module Gitlab module Checks - class ProjectMoved < BaseProject + class ProjectMoved < PostPushMessage REDIRECT_NAMESPACE = "redirect_namespace".freeze def initialize(project, user, protocol, redirected_path) @@ -10,7 +10,7 @@ module Gitlab end def message(rejected: false) - <<~MESSAGE.strip_heredoc + <<~MESSAGE Project '#{redirected_path}' was moved to '#{project.full_path}'. Please update your Git remote: diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb index 84299dd5790..bc1e83f77b2 100644 --- a/lib/gitlab/git_access.rb +++ b/lib/gitlab/git_access.rb @@ -28,32 +28,37 @@ module Gitlab PUSH_COMMANDS = %w{ git-receive-pack }.freeze ALL_COMMANDS = DOWNLOAD_COMMANDS + PUSH_COMMANDS - attr_reader :actor, :project, :protocol, :authentication_abilities, :redirected_path, :target_namespace + attr_reader :actor, :project, :protocol, :authentication_abilities, :namespace_path, :project_path, :redirected_path - def initialize(actor, project, protocol, authentication_abilities:, redirected_path: nil, target_namespace: nil) + def initialize(actor, project, protocol, authentication_abilities:, namespace_path: nil, project_path: nil, redirected_path: nil) @actor = actor @project = project @protocol = protocol - @redirected_path = redirected_path @authentication_abilities = authentication_abilities - @target_namespace = target_namespace + @namespace_path = namespace_path + @project_path = project_path + @redirected_path = redirected_path end def check(cmd, changes) check_protocol! check_valid_actor! check_active_user! - check_project_accessibility!(cmd) - check_project_moved! check_command_disabled!(cmd) check_command_existence!(cmd) - check_repository_existence!(cmd) + check_db_accessibility!(cmd) + + ensure_project_on_push!(cmd, changes) + + check_project_accessibility! + check_project_moved! + check_repository_existence! case cmd when *DOWNLOAD_COMMANDS check_download_access! when *PUSH_COMMANDS - check_push_access!(cmd, changes) + check_push_access!(changes) end true @@ -99,8 +104,8 @@ module Gitlab end end - def check_project_accessibility!(cmd) - unless can_create_project_in_namespace?(cmd) || can_read_project? + def check_project_accessibility! + if project.blank? || !can_read_project? raise NotFoundError, ERROR_MESSAGES[:project_not_found] end end @@ -143,16 +148,49 @@ module Gitlab end end - def check_repository_existence!(cmd) - unless can_create_project_in_namespace?(cmd) || project.repository.exists? + def check_db_accessibility!(cmd) + return unless receive_pack?(cmd) + + if Gitlab::Database.read_only? + raise UnauthorizedError, push_to_read_only_message + end + end + + def ensure_project_on_push!(cmd, changes) + return if project || deploy_key? + return unless receive_pack?(cmd) && changes == '_any' && authentication_abilities.include?(:push_code) + + namespace = Namespace.find_by_full_path(namespace_path) + + return unless user&.can?(:create_projects, namespace) + + project_params = { + path: project_path, + namespace_id: namespace.id, + visibility_level: Gitlab::VisibilityLevel::PRIVATE + } + + project = Projects::CreateService.new(user, project_params).execute + + unless project.saved? + raise ProjectCreationError, "Could not create project: #{project.errors.full_messages.join(', ')}" + end + + @project = project + user_access.project = @project + + Checks::ProjectCreated.new(project, user, protocol).add_message + end + + def check_repository_existence! + unless project.repository.exists? raise UnauthorizedError, ERROR_MESSAGES[:no_repo] end end def check_download_access! - return if deploy_key? - - passed = user_can_download_code? || + passed = deploy_key? || + user_can_download_code? || build_can_download_code? || guest_can_download_code? @@ -161,13 +199,7 @@ module Gitlab end end - def check_push_access!(cmd, changes) - if Gitlab::Database.read_only? - raise UnauthorizedError, push_to_read_only_message - end - - return if can_create_project_in_namespace?(cmd) - + def check_push_access!(changes) if project.repository_read_only? raise UnauthorizedError, ERROR_MESSAGES[:read_only] end @@ -180,8 +212,6 @@ module Gitlab raise UnauthorizedError, ERROR_MESSAGES[:upload] end - return if changes.blank? # Allow access. - check_change_access!(changes) end @@ -198,6 +228,8 @@ module Gitlab end def check_change_access!(changes) + return if changes.blank? # Allow access. + changes_list = Gitlab::ChangesList.new(changes) # Iterate over all changes to find if user allowed all of them to be applied @@ -240,14 +272,6 @@ module Gitlab end || Guest.can?(:read_project, project) end - def can_create_project_in_namespace?(cmd) - strong_memoize(:can_create_project_in_namespace) do - return false unless push?(cmd) && target_namespace && project.blank? - - user.can?(:create_projects, target_namespace) - end - end - def http? protocol == 'http' end @@ -260,10 +284,6 @@ module Gitlab command == 'git-receive-pack' end - def push?(cmd) - PUSH_COMMANDS.include?(cmd) - end - def upload_pack_disabled_over_http? !Gitlab.config.gitlab_shell.upload_pack end diff --git a/lib/gitlab/path_regex.rb b/lib/gitlab/path_regex.rb index c6a594d38d1..1fc0363904a 100644 --- a/lib/gitlab/path_regex.rb +++ b/lib/gitlab/path_regex.rb @@ -188,7 +188,7 @@ module Gitlab end def full_project_git_path_regex - @full_project_git_path_regex ||= /\A\/?(?<namespace_path>#{full_namespace_route_regex})\/(?<project_path>#{project_git_route_regex})\z/.freeze + @full_project_git_path_regex ||= %r{\A\/?(?<namespace_path>#{full_namespace_route_regex})\/(?<project_path>#{project_route_regex})\.git\z} end def full_namespace_format_regex diff --git a/lib/gitlab/user_access.rb b/lib/gitlab/user_access.rb index f357488ac61..15eb1c41213 100644 --- a/lib/gitlab/user_access.rb +++ b/lib/gitlab/user_access.rb @@ -6,7 +6,8 @@ module Gitlab [user&.id, project&.id] end - attr_reader :user, :project + attr_reader :user + attr_accessor :project def initialize(user, project: nil) @user = user |