summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKrasimir Angelov <kangelov@gitlab.com>2019-09-04 10:07:49 +1200
committerKrasimir Angelov <kangelov@gitlab.com>2019-09-04 10:07:49 +1200
commitc4b804c6dbf0183e0cec1cb95b7da743b21ff2c4 (patch)
tree201810b2721fc05bdafc65fd3cb9fdc1dd947151
parent89409a1925d65d4a62b523b5a7c0650287250cb5 (diff)
downloadgitlab-ce-61927-internal-api-namespace.tar.gz
Rename API::Internal class to API::Internal::Base61927-internal-api-namespace
so that we can use API::Internal namespace. Related to https://gitlab.com/gitlab-org/gitlab-ce/issues/61927.
-rw-r--r--.rubocop_todo.yml2
-rw-r--r--lib/api/api.rb2
-rw-r--r--lib/api/internal.rb294
-rw-r--r--lib/api/internal/base.rb296
-rw-r--r--spec/requests/api/internal/base_spec.rb (renamed from spec/requests/api/internal_spec.rb)2
5 files changed, 299 insertions, 297 deletions
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index be147d72f71..f1f8ff6e862 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -218,7 +218,7 @@ Lint/UriEscapeUnescape:
- 'app/models/project_services/drone_ci_service.rb'
- 'spec/lib/google_api/auth_spec.rb'
- 'spec/requests/api/files_spec.rb'
- - 'spec/requests/api/internal_spec.rb'
+ - 'spec/requests/api/internal/base_spec.rb'
# Offense count: 1
# Configuration parameters: CheckForMethodsWithNoSideEffects.
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 219ed45eff6..aa6a67d817a 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -118,7 +118,7 @@ module API
mount ::API::GroupContainerRepositories
mount ::API::GroupVariables
mount ::API::ImportGithub
- mount ::API::Internal
+ mount ::API::Internal::Base
mount ::API::Issues
mount ::API::JobArtifacts
mount ::API::Jobs
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
deleted file mode 100644
index 088ea5bd79a..00000000000
--- a/lib/api/internal.rb
+++ /dev/null
@@ -1,294 +0,0 @@
-# frozen_string_literal: true
-
-module API
- # Internal access API
- class Internal < Grape::API
- before { authenticate_by_gitlab_shell_token! }
-
- helpers ::API::Helpers::InternalHelpers
- helpers ::Gitlab::Identifier
-
- UNKNOWN_CHECK_RESULT_ERROR = 'Unknown check result'.freeze
-
- helpers do
- def response_with_status(code: 200, success: true, message: nil, **extra_options)
- status code
- { status: success, message: message }.merge(extra_options).compact
- end
-
- def lfs_authentication_url(project)
- # This is a separate method so that EE can alter its behaviour more
- # easily.
- project.http_url_to_repo
- end
- end
-
- namespace 'internal' do
- # Check if git command is allowed for project
- #
- # Params:
- # key_id - ssh key id for Git over SSH
- # user_id - user id for Git over HTTP or over SSH in keyless SSH CERT mode
- # username - user name for Git over SSH in keyless SSH cert mode
- # protocol - Git access protocol being used, e.g. HTTP or SSH
- # project - project full_path (not path on disk)
- # action - git action (git-upload-pack or git-receive-pack)
- # changes - changes as "oldrev newrev ref", see Gitlab::ChangesList
- # rubocop: disable CodeReuse/ActiveRecord
- post "/allowed" do
- # Stores some Git-specific env thread-safely
- env = parse_env
- Gitlab::Git::HookEnv.set(gl_repository, env) if project
-
- actor =
- if params[:key_id]
- Key.find_by(id: params[:key_id])
- elsif params[:user_id]
- User.find_by(id: params[:user_id])
- elsif params[:username]
- UserFinder.new(params[:username]).find_by_username
- end
-
- protocol = params[:protocol]
-
- actor.update_last_used_at if actor.is_a?(Key)
- user =
- if actor.is_a?(Key)
- actor.user
- else
- actor
- end
-
- access_checker_klass = repo_type.access_checker_class
- 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)
-
- check_result = begin
- result = access_checker.check(params[:action], params[:changes])
- @project ||= access_checker.project
- result
- rescue Gitlab::GitAccess::UnauthorizedError => e
- break response_with_status(code: 401, success: false, message: e.message)
- rescue Gitlab::GitAccess::TimeoutError => e
- break response_with_status(code: 503, success: false, message: e.message)
- rescue Gitlab::GitAccess::NotFoundError => e
- break response_with_status(code: 404, success: false, message: e.message)
- end
-
- log_user_activity(actor)
-
- case check_result
- when ::Gitlab::GitAccessResult::Success
- payload = {
- gl_repository: gl_repository,
- gl_project_path: gl_project_path,
- gl_id: Gitlab::GlId.gl_id(user),
- gl_username: user&.username,
- git_config_options: [],
- gitaly: gitaly_payload(params[:action]),
- gl_console_messages: check_result.console_messages
- }
-
- # Custom option for git-receive-pack command
- receive_max_input_size = Gitlab::CurrentSettings.receive_max_input_size.to_i
- if receive_max_input_size > 0
- payload[:git_config_options] << "receive.maxInputSize=#{receive_max_input_size.megabytes}"
- end
-
- response_with_status(**payload)
- when ::Gitlab::GitAccessResult::CustomAction
- response_with_status(code: 300, message: check_result.message, payload: check_result.payload)
- else
- response_with_status(code: 500, success: false, message: UNKNOWN_CHECK_RESULT_ERROR)
- end
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- # rubocop: disable CodeReuse/ActiveRecord
- post "/lfs_authenticate" do
- status 200
-
- if params[:key_id]
- actor = Key.find(params[:key_id])
- actor.update_last_used_at
- elsif params[:user_id]
- actor = User.find_by(id: params[:user_id])
- raise ActiveRecord::RecordNotFound.new("No such user id!") unless actor
- else
- raise ActiveRecord::RecordNotFound.new("No key_id or user_id passed!")
- end
-
- Gitlab::LfsToken
- .new(actor)
- .authentication_payload(lfs_authentication_url(project))
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- get "/merge_request_urls" do
- merge_request_urls
- end
-
- #
- # Get a ssh key using the fingerprint
- #
- # rubocop: disable CodeReuse/ActiveRecord
- get "/authorized_keys" do
- fingerprint = params.fetch(:fingerprint) do
- Gitlab::InsecureKeyFingerprint.new(params.fetch(:key)).fingerprint
- end
- key = Key.find_by(fingerprint: fingerprint)
- not_found!("Key") if key.nil?
- present key, with: Entities::SSHKey
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- #
- # Discover user by ssh key, user id or username
- #
- # rubocop: disable CodeReuse/ActiveRecord
- get "/discover" do
- if params[:key_id]
- key = Key.find(params[:key_id])
- user = key.user
- elsif params[:user_id]
- user = User.find_by(id: params[:user_id])
- elsif params[:username]
- user = UserFinder.new(params[:username]).find_by_username
- end
-
- present user, with: Entities::UserSafe
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- get "/check" do
- {
- api_version: API.version,
- gitlab_version: Gitlab::VERSION,
- gitlab_rev: Gitlab.revision,
- redis: redis_ping
- }
- end
-
- get "/broadcast_messages" do
- if messages = BroadcastMessage.current
- present messages, with: Entities::BroadcastMessage
- else
- []
- end
- end
-
- get "/broadcast_message" do
- if message = BroadcastMessage.current&.last
- present message, with: Entities::BroadcastMessage
- else
- {}
- end
- end
-
- # rubocop: disable CodeReuse/ActiveRecord
- post '/two_factor_recovery_codes' do
- status 200
-
- if params[:key_id]
- key = Key.find_by(id: params[:key_id])
-
- if key
- key.update_last_used_at
- else
- break { 'success' => false, 'message' => 'Could not find the given key' }
- end
-
- if key.is_a?(DeployKey)
- break { success: false, message: 'Deploy keys cannot be used to retrieve recovery codes' }
- end
-
- user = key.user
-
- unless user
- break { success: false, message: 'Could not find a user for the given key' }
- end
- elsif params[:user_id]
- user = User.find_by(id: params[:user_id])
-
- unless user
- break { success: false, message: 'Could not find the given user' }
- end
- end
-
- unless user.two_factor_enabled?
- break { success: false, message: 'Two-factor authentication is not enabled for this user' }
- end
-
- codes = nil
-
- ::Users::UpdateService.new(current_user, user: user).execute! do |user|
- codes = user.generate_otp_backup_codes!
- end
-
- { success: true, recovery_codes: codes }
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- post '/pre_receive' do
- status 200
-
- reference_counter_increased = Gitlab::ReferenceCounter.new(params[:gl_repository]).increase
-
- { reference_counter_increased: reference_counter_increased }
- end
-
- post "/notify_post_receive" do
- status 200
-
- # TODO: Re-enable when Gitaly is processing the post-receive notification
- # return unless Gitlab::GitalyClient.enabled?
- #
- # begin
- # repository = wiki? ? project.wiki.repository : project.repository
- # Gitlab::GitalyClient::NotificationService.new(repository.raw_repository).post_receive
- # rescue GRPC::Unavailable => e
- # render_api_error!(e, 500)
- # end
- end
-
- post '/post_receive' do
- status 200
-
- response = Gitlab::InternalPostReceive::Response.new
- user = identify(params[:identifier])
- project = Gitlab::GlRepository.parse(params[:gl_repository]).first
- push_options = Gitlab::PushOptions.new(params[:push_options])
-
- response.reference_counter_decreased = Gitlab::ReferenceCounter.new(params[:gl_repository]).decrease
-
- PostReceive.perform_async(params[:gl_repository], params[:identifier],
- params[:changes], push_options.as_json)
-
- mr_options = push_options.get(:merge_request)
- if mr_options.present?
- message = process_mr_push_options(mr_options, project, user, params[:changes])
- response.add_alert_message(message)
- end
-
- broadcast_message = BroadcastMessage.current&.last&.message
- response.add_alert_message(broadcast_message)
-
- response.add_merge_request_urls(merge_request_urls)
-
- # A user is not guaranteed to be returned; an orphaned write deploy
- # key could be used
- if user
- redirect_message = Gitlab::Checks::ProjectMoved.fetch_message(user.id, project.id)
- project_created_message = Gitlab::Checks::ProjectCreated.fetch_message(user.id, project.id)
-
- response.add_basic_message(redirect_message)
- response.add_basic_message(project_created_message)
- end
-
- present response, with: Entities::InternalPostReceive::Response
- end
- end
- end
-end
diff --git a/lib/api/internal/base.rb b/lib/api/internal/base.rb
new file mode 100644
index 00000000000..622032b8355
--- /dev/null
+++ b/lib/api/internal/base.rb
@@ -0,0 +1,296 @@
+# frozen_string_literal: true
+
+module API
+ # Internal access API
+ module Internal
+ class Base < Grape::API
+ before { authenticate_by_gitlab_shell_token! }
+
+ helpers ::API::Helpers::InternalHelpers
+ helpers ::Gitlab::Identifier
+
+ UNKNOWN_CHECK_RESULT_ERROR = 'Unknown check result'.freeze
+
+ helpers do
+ def response_with_status(code: 200, success: true, message: nil, **extra_options)
+ status code
+ { status: success, message: message }.merge(extra_options).compact
+ end
+
+ def lfs_authentication_url(project)
+ # This is a separate method so that EE can alter its behaviour more
+ # easily.
+ project.http_url_to_repo
+ end
+ end
+
+ namespace 'internal' do
+ # Check if git command is allowed for project
+ #
+ # Params:
+ # key_id - ssh key id for Git over SSH
+ # user_id - user id for Git over HTTP or over SSH in keyless SSH CERT mode
+ # username - user name for Git over SSH in keyless SSH cert mode
+ # protocol - Git access protocol being used, e.g. HTTP or SSH
+ # project - project full_path (not path on disk)
+ # action - git action (git-upload-pack or git-receive-pack)
+ # changes - changes as "oldrev newrev ref", see Gitlab::ChangesList
+ # rubocop: disable CodeReuse/ActiveRecord
+ post "/allowed" do
+ # Stores some Git-specific env thread-safely
+ env = parse_env
+ Gitlab::Git::HookEnv.set(gl_repository, env) if project
+
+ actor =
+ if params[:key_id]
+ Key.find_by(id: params[:key_id])
+ elsif params[:user_id]
+ User.find_by(id: params[:user_id])
+ elsif params[:username]
+ UserFinder.new(params[:username]).find_by_username
+ end
+
+ protocol = params[:protocol]
+
+ actor.update_last_used_at if actor.is_a?(Key)
+ user =
+ if actor.is_a?(Key)
+ actor.user
+ else
+ actor
+ end
+
+ access_checker_klass = repo_type.access_checker_class
+ 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)
+
+ check_result = begin
+ result = access_checker.check(params[:action], params[:changes])
+ @project ||= access_checker.project
+ result
+ rescue Gitlab::GitAccess::UnauthorizedError => e
+ break response_with_status(code: 401, success: false, message: e.message)
+ rescue Gitlab::GitAccess::TimeoutError => e
+ break response_with_status(code: 503, success: false, message: e.message)
+ rescue Gitlab::GitAccess::NotFoundError => e
+ break response_with_status(code: 404, success: false, message: e.message)
+ end
+
+ log_user_activity(actor)
+
+ case check_result
+ when ::Gitlab::GitAccessResult::Success
+ payload = {
+ gl_repository: gl_repository,
+ gl_project_path: gl_project_path,
+ gl_id: Gitlab::GlId.gl_id(user),
+ gl_username: user&.username,
+ git_config_options: [],
+ gitaly: gitaly_payload(params[:action]),
+ gl_console_messages: check_result.console_messages
+ }
+
+ # Custom option for git-receive-pack command
+ receive_max_input_size = Gitlab::CurrentSettings.receive_max_input_size.to_i
+ if receive_max_input_size > 0
+ payload[:git_config_options] << "receive.maxInputSize=#{receive_max_input_size.megabytes}"
+ end
+
+ response_with_status(**payload)
+ when ::Gitlab::GitAccessResult::CustomAction
+ response_with_status(code: 300, message: check_result.message, payload: check_result.payload)
+ else
+ response_with_status(code: 500, success: false, message: UNKNOWN_CHECK_RESULT_ERROR)
+ end
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ post "/lfs_authenticate" do
+ status 200
+
+ if params[:key_id]
+ actor = Key.find(params[:key_id])
+ actor.update_last_used_at
+ elsif params[:user_id]
+ actor = User.find_by(id: params[:user_id])
+ raise ActiveRecord::RecordNotFound.new("No such user id!") unless actor
+ else
+ raise ActiveRecord::RecordNotFound.new("No key_id or user_id passed!")
+ end
+
+ Gitlab::LfsToken
+ .new(actor)
+ .authentication_payload(lfs_authentication_url(project))
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ get "/merge_request_urls" do
+ merge_request_urls
+ end
+
+ #
+ # Get a ssh key using the fingerprint
+ #
+ # rubocop: disable CodeReuse/ActiveRecord
+ get "/authorized_keys" do
+ fingerprint = params.fetch(:fingerprint) do
+ Gitlab::InsecureKeyFingerprint.new(params.fetch(:key)).fingerprint
+ end
+ key = Key.find_by(fingerprint: fingerprint)
+ not_found!("Key") if key.nil?
+ present key, with: Entities::SSHKey
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ #
+ # Discover user by ssh key, user id or username
+ #
+ # rubocop: disable CodeReuse/ActiveRecord
+ get "/discover" do
+ if params[:key_id]
+ key = Key.find(params[:key_id])
+ user = key.user
+ elsif params[:user_id]
+ user = User.find_by(id: params[:user_id])
+ elsif params[:username]
+ user = UserFinder.new(params[:username]).find_by_username
+ end
+
+ present user, with: Entities::UserSafe
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ get "/check" do
+ {
+ api_version: API.version,
+ gitlab_version: Gitlab::VERSION,
+ gitlab_rev: Gitlab.revision,
+ redis: redis_ping
+ }
+ end
+
+ get "/broadcast_messages" do
+ if messages = BroadcastMessage.current
+ present messages, with: Entities::BroadcastMessage
+ else
+ []
+ end
+ end
+
+ get "/broadcast_message" do
+ if message = BroadcastMessage.current&.last
+ present message, with: Entities::BroadcastMessage
+ else
+ {}
+ end
+ end
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ post '/two_factor_recovery_codes' do
+ status 200
+
+ if params[:key_id]
+ key = Key.find_by(id: params[:key_id])
+
+ if key
+ key.update_last_used_at
+ else
+ break { 'success' => false, 'message' => 'Could not find the given key' }
+ end
+
+ if key.is_a?(DeployKey)
+ break { success: false, message: 'Deploy keys cannot be used to retrieve recovery codes' }
+ end
+
+ user = key.user
+
+ unless user
+ break { success: false, message: 'Could not find a user for the given key' }
+ end
+ elsif params[:user_id]
+ user = User.find_by(id: params[:user_id])
+
+ unless user
+ break { success: false, message: 'Could not find the given user' }
+ end
+ end
+
+ unless user.two_factor_enabled?
+ break { success: false, message: 'Two-factor authentication is not enabled for this user' }
+ end
+
+ codes = nil
+
+ ::Users::UpdateService.new(current_user, user: user).execute! do |user|
+ codes = user.generate_otp_backup_codes!
+ end
+
+ { success: true, recovery_codes: codes }
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ post '/pre_receive' do
+ status 200
+
+ reference_counter_increased = Gitlab::ReferenceCounter.new(params[:gl_repository]).increase
+
+ { reference_counter_increased: reference_counter_increased }
+ end
+
+ post "/notify_post_receive" do
+ status 200
+
+ # TODO: Re-enable when Gitaly is processing the post-receive notification
+ # return unless Gitlab::GitalyClient.enabled?
+ #
+ # begin
+ # repository = wiki? ? project.wiki.repository : project.repository
+ # Gitlab::GitalyClient::NotificationService.new(repository.raw_repository).post_receive
+ # rescue GRPC::Unavailable => e
+ # render_api_error!(e, 500)
+ # end
+ end
+
+ post '/post_receive' do
+ status 200
+
+ response = Gitlab::InternalPostReceive::Response.new
+ user = identify(params[:identifier])
+ project = Gitlab::GlRepository.parse(params[:gl_repository]).first
+ push_options = Gitlab::PushOptions.new(params[:push_options])
+
+ response.reference_counter_decreased = Gitlab::ReferenceCounter.new(params[:gl_repository]).decrease
+
+ PostReceive.perform_async(params[:gl_repository], params[:identifier],
+ params[:changes], push_options.as_json)
+
+ mr_options = push_options.get(:merge_request)
+ if mr_options.present?
+ message = process_mr_push_options(mr_options, project, user, params[:changes])
+ response.add_alert_message(message)
+ end
+
+ broadcast_message = BroadcastMessage.current&.last&.message
+ response.add_alert_message(broadcast_message)
+
+ response.add_merge_request_urls(merge_request_urls)
+
+ # A user is not guaranteed to be returned; an orphaned write deploy
+ # key could be used
+ if user
+ redirect_message = Gitlab::Checks::ProjectMoved.fetch_message(user.id, project.id)
+ project_created_message = Gitlab::Checks::ProjectCreated.fetch_message(user.id, project.id)
+
+ response.add_basic_message(redirect_message)
+ response.add_basic_message(project_created_message)
+ end
+
+ present response, with: Entities::InternalPostReceive::Response
+ end
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal/base_spec.rb
index c94f6d22e74..a56527073c7 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal/base_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe API::Internal do
+describe API::Internal::Base do
set(:user) { create(:user) }
let(:key) { create(:key, user: user) }
set(:project) { create(:project, :repository, :wiki_repo) }