module Gitlab
  module JWT
    class ContainerRegistryAuthenticationService < BaseService
      AUDIENCE = 'container_registry'

      def execute
        return error('not found', 404) unless registry.enabled

        if params[:offline_token]
          return error('forbidden', 403) unless current_user
        end

        return error('forbidden', 401) if scopes.blank?

        { token: authorized_token(scopes).encoded }
      end

      def self.full_access_token(*names)
        registry = Gitlab.config.registry
        token = ::JWT::RSAToken.new(registry.key)
        token.issuer = registry.issuer
        token.audience = AUDIENCE
        token[:access] = names.map do |name|
          { type: 'repository', name: name, actions: %w(pull push) }
        end
        token.encoded
      end

      private

      def authorized_token(access)
        token = ::JWT::RSAToken.new(registry.key)
        token.issuer = registry.issuer
        token.audience = params[:service]
        token.subject = current_user.try(:username)
        token[:access] = access
        token
      end

      def scopes
        return unless params[:scope]

        @scopes ||= begin
          scope = process_scope(params[:scope])
          [scope].compact
        end
      end

      def process_scope(scope)
        type, name, actions = scope.split(':', 3)
        actions = actions.split(',')

        case type
        when 'repository'
          process_repository_access(type, name, actions)
        end
      end

      def process_repository_access(type, name, actions)
        requested_project = Project.find_with_namespace(name)
        return unless requested_project

        actions = actions.select do |action|
          can_access?(requested_project, action)
        end

        { type: type, name: name, actions: actions } if actions.present?
      end

<<<<<<< HEAD
    def can_access?(requested_project, requested_action)
      return false unless requested_project.container_registry_enabled?

      case requested_action
      when 'pull'
        requested_project == project || can?(current_user, :read_container_registry, requested_project)
      when 'push'
        requested_project == project || can?(current_user, :create_container_registry, requested_project)
      else
        false
=======
      def can_access?(requested_project, requested_action)
        case requested_action
        when 'pull'
          requested_project.public? || requested_project == project || can?(current_user, :read_container_registry, requested_project)
        when 'push'
          requested_project == project || can?(current_user, :create_container_registry, requested_project)
        else
          false
        end
>>>>>>> docker-registry
      end

      def registry
        Gitlab.config.registry
      end
    end
  end
end
