diff options
Diffstat (limited to 'lib/gitlab_net.rb')
-rw-r--r-- | lib/gitlab_net.rb | 149 |
1 files changed, 94 insertions, 55 deletions
diff --git a/lib/gitlab_net.rb b/lib/gitlab_net.rb index 9ea18aa..9cb7e56 100644 --- a/lib/gitlab_net.rb +++ b/lib/gitlab_net.rb @@ -1,20 +1,23 @@ +require 'net/http' +require 'openssl' require 'json' -require_relative 'errors' +require_relative 'gitlab_config' 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 +class GitlabNet # rubocop:disable Metrics/ClassLength 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, actor, changes, protocol = GL_PROTOCOL, env: {}) + def check_access(cmd, gl_repository, repo, who, changes, protocol, env: {}) changes = changes.join("\n") unless changes.is_a?(String) params = { @@ -26,27 +29,56 @@ class GitlabNet env: env } - params[actor.identifier_key.to_sym] = actor.id + who_sym, _, who_v = self.class.parse_who(who) + params[who_sym] = who_v - resp = post("#{internal_api_endpoint}/allowed", params) + url = "#{internal_api_endpoint}/allowed" + resp = post(url, params) - determine_action(actor, resp) + 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 end - 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 + 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 end - def lfs_authenticate(actor, repo) - params = { project: sanitize_path(repo) } - params[actor.identifier_key.to_sym] = actor.id + 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 resp = post("#{internal_api_endpoint}/lfs_authenticate", params) - GitlabLfsAuthentication.build_from_json(resp.body) if resp.code == HTTP_SUCCESS + if resp.code == '200' + GitlabLfsAuthentication.build_from_json(resp.body) + end end def broadcast_message @@ -61,7 +93,11 @@ class GitlabNet url += "&gl_repository=#{URI.escape(gl_repository)}" if gl_repository resp = get(url) - resp.code == HTTP_SUCCESS ? JSON.parse(resp.body) : [] + if resp.code == '200' + JSON.parse(resp.body) + else + [] + end rescue [] end @@ -70,17 +106,19 @@ class GitlabNet get("#{internal_api_endpoint}/check", options: { read_timeout: CHECK_TIMEOUT }) end - 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 + def authorized_key(key) + resp = get("#{internal_api_endpoint}/authorized_keys?key=#{URI.escape(key, '+/=')}") + JSON.parse(resp.body) if resp.code == "200" rescue nil end - 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 + 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' rescue {} end @@ -89,50 +127,51 @@ class GitlabNet params = { gl_repository: gl_repository, project: repo_path } resp = post("#{internal_api_endpoint}/notify_post_receive", params) - resp.code == HTTP_SUCCESS + resp.code == '200' rescue false end - def post_receive(gl_repository, actor, changes) - params = { gl_repository: gl_repository, identifier: actor.identifier, changes: changes } + def post_receive(gl_repository, identifier, changes) + params = { + gl_repository: gl_repository, + identifier: identifier, + changes: changes + } resp = post("#{internal_api_endpoint}/post_receive", params) - raise NotFoundError if resp.code == HTTP_NOT_FOUND - JSON.parse(resp.body) if resp.code == HTTP_SUCCESS + raise NotFound if resp.code == '404' + + JSON.parse(resp.body) if resp.code == '200' 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 - JSON.parse(resp.body) if resp.code == HTTP_SUCCESS - end + raise NotFound if resp.code == '404' - private - - def sanitize_path(repo) - repo.delete("'") + JSON.parse(resp.body) if resp.code == '200' 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 + 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 UnknownError, "#{API_INACCESSIBLE_ERROR}: #{message}" + raise ArgumentError, "who='#{who}' is invalid!" end - rescue JSON::ParserError - raise UnknownError, API_INACCESSIBLE_ERROR + end + + protected + + def sanitize_path(repo) + repo.delete("'") end end |