diff options
Diffstat (limited to 'lib/gitlab_net.rb')
-rw-r--r-- | lib/gitlab_net.rb | 149 |
1 files changed, 55 insertions, 94 deletions
diff --git a/lib/gitlab_net.rb b/lib/gitlab_net.rb index 9cb7e56..9ea18aa 100644 --- a/lib/gitlab_net.rb +++ b/lib/gitlab_net.rb @@ -1,23 +1,20 @@ -require 'net/http' -require 'openssl' require 'json' -require_relative 'gitlab_config' +require_relative 'errors' require_relative 'gitlab_logger' require_relative 'gitlab_access' require_relative 'gitlab_lfs_authentication' -require_relative 'httpunix' require_relative 'http_helper' +require_relative 'action' -class GitlabNet # rubocop:disable Metrics/ClassLength +class GitlabNet include HTTPHelper - class ApiUnreachableError < StandardError; end - class NotFound < StandardError; end - CHECK_TIMEOUT = 5 + GL_PROTOCOL = 'ssh'.freeze + API_INACCESSIBLE_ERROR = 'API is not accessible'.freeze - def check_access(cmd, gl_repository, repo, who, changes, protocol, env: {}) + def check_access(cmd, gl_repository, repo, actor, changes, protocol = GL_PROTOCOL, env: {}) changes = changes.join("\n") unless changes.is_a?(String) params = { @@ -29,56 +26,27 @@ class GitlabNet # rubocop:disable Metrics/ClassLength env: env } - who_sym, _, who_v = self.class.parse_who(who) - params[who_sym] = who_v + params[actor.identifier_key.to_sym] = actor.id - url = "#{internal_api_endpoint}/allowed" - resp = post(url, params) + resp = post("#{internal_api_endpoint}/allowed", params) - if resp.code == '200' - GitAccessStatus.create_from_json(resp.body) - else - GitAccessStatus.new(false, - 'API is not accessible', - gl_repository: nil, - gl_id: nil, - gl_username: nil, - repository_path: nil, - gitaly: nil, - git_protocol: nil) - end + determine_action(actor, resp) end - def discover(who) - _, who_k, who_v = self.class.parse_who(who) - - resp = get("#{internal_api_endpoint}/discover?#{who_k}=#{who_v}") - - JSON.parse(resp.body) rescue nil + def discover(actor) + resp = get("#{internal_api_endpoint}/discover?#{actor.identifier_key}=#{actor.id}") + JSON.parse(resp.body) if resp.code == HTTP_SUCCESS + rescue JSON::ParserError, ApiUnreachableError + nil end - def lfs_authenticate(gl_id, repo) - id_sym, _, id = self.class.parse_who(gl_id) - - if id_sym == :key_id - params = { - project: sanitize_path(repo), - key_id: id - } - elsif id_sym == :user_id - params = { - project: sanitize_path(repo), - user_id: id - } - else - raise ArgumentError, "lfs_authenticate() got unsupported GL_ID='#{gl_id}'!" - end + def lfs_authenticate(actor, repo) + params = { project: sanitize_path(repo) } + params[actor.identifier_key.to_sym] = actor.id resp = post("#{internal_api_endpoint}/lfs_authenticate", params) - if resp.code == '200' - GitlabLfsAuthentication.build_from_json(resp.body) - end + GitlabLfsAuthentication.build_from_json(resp.body) if resp.code == HTTP_SUCCESS end def broadcast_message @@ -93,11 +61,7 @@ class GitlabNet # rubocop:disable Metrics/ClassLength url += "&gl_repository=#{URI.escape(gl_repository)}" if gl_repository resp = get(url) - if resp.code == '200' - JSON.parse(resp.body) - else - [] - end + resp.code == HTTP_SUCCESS ? JSON.parse(resp.body) : [] rescue [] end @@ -106,19 +70,17 @@ class GitlabNet # rubocop:disable Metrics/ClassLength get("#{internal_api_endpoint}/check", options: { read_timeout: CHECK_TIMEOUT }) end - def authorized_key(key) - resp = get("#{internal_api_endpoint}/authorized_keys?key=#{URI.escape(key, '+/=')}") - JSON.parse(resp.body) if resp.code == "200" + def authorized_key(full_key) + resp = get("#{internal_api_endpoint}/authorized_keys?key=#{URI.escape(full_key, '+/=')}") + JSON.parse(resp.body) if resp.code == HTTP_SUCCESS rescue nil end - def two_factor_recovery_codes(gl_id) - id_sym, _, id = self.class.parse_who(gl_id) - - resp = post("#{internal_api_endpoint}/two_factor_recovery_codes", id_sym => id) - - JSON.parse(resp.body) if resp.code == '200' + def two_factor_recovery_codes(actor) + params = { actor.identifier_key.to_sym => actor.id } + resp = post("#{internal_api_endpoint}/two_factor_recovery_codes", params) + JSON.parse(resp.body) if resp.code == HTTP_SUCCESS rescue {} end @@ -127,51 +89,50 @@ class GitlabNet # rubocop:disable Metrics/ClassLength params = { gl_repository: gl_repository, project: repo_path } resp = post("#{internal_api_endpoint}/notify_post_receive", params) - resp.code == '200' + resp.code == HTTP_SUCCESS rescue false end - def post_receive(gl_repository, identifier, changes) - params = { - gl_repository: gl_repository, - identifier: identifier, - changes: changes - } + def post_receive(gl_repository, actor, changes) + params = { gl_repository: gl_repository, identifier: actor.identifier, changes: changes } resp = post("#{internal_api_endpoint}/post_receive", params) + raise NotFoundError if resp.code == HTTP_NOT_FOUND - raise NotFound if resp.code == '404' - - JSON.parse(resp.body) if resp.code == '200' + JSON.parse(resp.body) if resp.code == HTTP_SUCCESS end def pre_receive(gl_repository) resp = post("#{internal_api_endpoint}/pre_receive", gl_repository: gl_repository) + raise NotFoundError if resp.code == HTTP_NOT_FOUND - raise NotFound if resp.code == '404' - - JSON.parse(resp.body) if resp.code == '200' - end - - def self.parse_who(who) - if who.start_with?("key-") - value = who.gsub("key-", "") - raise ArgumentError, "who='#{who}' is invalid!" unless value =~ /\A[0-9]+\z/ - [:key_id, 'key_id', value] - elsif who.start_with?("user-") - value = who.gsub("user-", "") - raise ArgumentError, "who='#{who}' is invalid!" unless value =~ /\A[0-9]+\z/ - [:user_id, 'user_id', value] - elsif who.start_with?("username-") - [:username, 'username', who.gsub("username-", "")] - else - raise ArgumentError, "who='#{who}' is invalid!" - end + JSON.parse(resp.body) if resp.code == HTTP_SUCCESS end - protected + private def sanitize_path(repo) repo.delete("'") end + + def determine_action(actor, resp) + json = JSON.parse(resp.body) + message = json['message'] + + case resp.code + when HTTP_SUCCESS + # TODO: This raise can be removed once internal API can respond with correct + # HTTP status codes, instead of relying upon parsing the body and + # accessing the 'status' key. + raise AccessDeniedError, message unless json['status'] + + Action::Gitaly.create_from_json(actor, json) + when HTTP_UNAUTHORIZED, HTTP_NOT_FOUND + raise AccessDeniedError, message + else + raise UnknownError, "#{API_INACCESSIBLE_ERROR}: #{message}" + end + rescue JSON::ParserError + raise UnknownError, API_INACCESSIBLE_ERROR + end end |