141 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Ruby
		
	
	
	
			
		
		
	
	
			141 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Ruby
		
	
	
	
# frozen_string_literal: true
 | 
						|
 | 
						|
module Gitlab
 | 
						|
  class GitAccessSnippet < GitAccess
 | 
						|
    extend ::Gitlab::Utils::Override
 | 
						|
 | 
						|
    ERROR_MESSAGES = {
 | 
						|
      authentication_mechanism: 'The authentication mechanism is not supported.',
 | 
						|
      read_snippet: 'You are not allowed to read this snippet.',
 | 
						|
      update_snippet: 'You are not allowed to update this snippet.',
 | 
						|
      snippet_not_found: 'The snippet you were looking for could not be found.',
 | 
						|
      no_repo: 'The snippet repository you were looking for could not be found.'
 | 
						|
    }.freeze
 | 
						|
 | 
						|
    alias_method :snippet, :container
 | 
						|
 | 
						|
    def initialize(actor, snippet, protocol, **kwargs)
 | 
						|
      super(actor, snippet, protocol, **kwargs)
 | 
						|
 | 
						|
      @auth_result_type = nil
 | 
						|
      @authentication_abilities &= [:download_code, :push_code]
 | 
						|
    end
 | 
						|
 | 
						|
    override :project
 | 
						|
    def project
 | 
						|
      container.project if container.is_a?(ProjectSnippet)
 | 
						|
    end
 | 
						|
 | 
						|
    override :check
 | 
						|
    def check(cmd, changes)
 | 
						|
      check_snippet_accessibility!
 | 
						|
 | 
						|
      super
 | 
						|
    end
 | 
						|
 | 
						|
    override :download_ability
 | 
						|
    def download_ability
 | 
						|
      :read_snippet
 | 
						|
    end
 | 
						|
 | 
						|
    override :push_ability
 | 
						|
    def push_ability
 | 
						|
      :update_snippet
 | 
						|
    end
 | 
						|
 | 
						|
    private
 | 
						|
 | 
						|
    # TODO: Implement EE/Geo https://gitlab.com/gitlab-org/gitlab/issues/205629
 | 
						|
    override :check_custom_action
 | 
						|
    def check_custom_action
 | 
						|
      # snippets never return custom actions, such as geo replication.
 | 
						|
    end
 | 
						|
 | 
						|
    override :check_valid_actor!
 | 
						|
    def check_valid_actor!
 | 
						|
      # TODO: Investigate if expanding actor/authentication types are needed.
 | 
						|
      # https://gitlab.com/gitlab-org/gitlab/issues/202190
 | 
						|
      if actor && !allowed_actor?
 | 
						|
        raise ForbiddenError, error_message(:authentication_mechanism)
 | 
						|
      end
 | 
						|
 | 
						|
      super
 | 
						|
    end
 | 
						|
 | 
						|
    def allowed_actor?
 | 
						|
      actor.is_a?(User) || actor.instance_of?(Key)
 | 
						|
    end
 | 
						|
 | 
						|
    override :check_push_access!
 | 
						|
    def check_push_access!
 | 
						|
      raise ForbiddenError, error_message(:update_snippet) unless user
 | 
						|
 | 
						|
      if snippet&.repository_read_only?
 | 
						|
        raise ForbiddenError, error_message(:read_only)
 | 
						|
      end
 | 
						|
 | 
						|
      check_change_access!
 | 
						|
    end
 | 
						|
 | 
						|
    def check_snippet_accessibility!
 | 
						|
      if snippet.blank?
 | 
						|
        raise NotFoundError, error_message(:snippet_not_found)
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
    override :can_read_project?
 | 
						|
    def can_read_project?
 | 
						|
      return true if user&.migration_bot?
 | 
						|
 | 
						|
      super
 | 
						|
    end
 | 
						|
 | 
						|
    override :can_download?
 | 
						|
    def can_download?
 | 
						|
      guest_can_download? || user_can_download?
 | 
						|
    end
 | 
						|
 | 
						|
    override :download_forbidden_message
 | 
						|
    def download_forbidden_message
 | 
						|
      error_message(:read_snippet)
 | 
						|
    end
 | 
						|
 | 
						|
    override :check_change_access!
 | 
						|
    def check_change_access!
 | 
						|
      unless user_can_push?
 | 
						|
        raise ForbiddenError, error_message(:update_snippet)
 | 
						|
      end
 | 
						|
 | 
						|
      check_size_before_push!
 | 
						|
      check_access!
 | 
						|
      check_push_size!
 | 
						|
    end
 | 
						|
 | 
						|
    override :check_access!
 | 
						|
    def check_access!
 | 
						|
      changes_list.each do |change|
 | 
						|
        # If user does not have access to make at least one change, cancel all
 | 
						|
        # push by allowing the exception to bubble up
 | 
						|
        Checks::SnippetCheck.new(change, default_branch: snippet.default_branch, root_ref: snippet.repository.root_ref, logger: logger).validate!
 | 
						|
        Checks::PushFileCountCheck.new(change, repository: repository, limit: Snippet.max_file_limit, logger: logger).validate!
 | 
						|
      end
 | 
						|
    rescue Checks::TimedLogger::TimeoutError
 | 
						|
      raise TimeoutError, logger.full_message
 | 
						|
    end
 | 
						|
 | 
						|
    override :user_access
 | 
						|
    def user_access
 | 
						|
      @user_access ||= UserAccessSnippet.new(user, snippet: snippet)
 | 
						|
    end
 | 
						|
 | 
						|
    override :check_size_limit?
 | 
						|
    def check_size_limit?
 | 
						|
      return false if user&.migration_bot?
 | 
						|
 | 
						|
      super
 | 
						|
    end
 | 
						|
  end
 | 
						|
end
 | 
						|
 | 
						|
Gitlab::GitAccessSnippet.prepend_mod_with('Gitlab::GitAccessSnippet')
 |