utils, gist-logs: improve/fix credential handling.
The API used (`Net::HTTP::Post`) does not handle basic authentication credentials in the same way as `open` so fix both cases so they work. Also, do some general usability tweaks to point out to people what could be wrong with their tokens or credentials to help them debug. Closes Homebrew/homebrew#50410. Signed-off-by: Mike McQuaid <mike@mikemcquaid.com>
This commit is contained in:
parent
ca2abb2be6
commit
6135da800e
@ -37,12 +37,12 @@ module Homebrew
|
|||||||
if ARGV.include?("--new-issue") || ARGV.switch?("n")
|
if ARGV.include?("--new-issue") || ARGV.switch?("n")
|
||||||
auth = :AUTH_TOKEN
|
auth = :AUTH_TOKEN
|
||||||
|
|
||||||
unless GitHub.api_credentials
|
if GitHub.api_credentials_type == :none
|
||||||
puts "You can create a personal access token: https://github.com/settings/tokens"
|
puts "You can create a personal access token: https://github.com/settings/tokens"
|
||||||
puts "and then set HOMEBREW_GITHUB_API_TOKEN as authentication method."
|
puts "and then set HOMEBREW_GITHUB_API_TOKEN as authentication method."
|
||||||
puts
|
puts
|
||||||
|
|
||||||
auth = :AUTH_BASIC
|
auth = :AUTH_USER_LOGIN
|
||||||
end
|
end
|
||||||
|
|
||||||
url = new_issue(f.tap, "#{f.name} failed to build on #{MacOS.full_version}", url, auth)
|
url = new_issue(f.tap, "#{f.name} failed to build on #{MacOS.full_version}", url, auth)
|
||||||
@ -118,9 +118,21 @@ module Homebrew
|
|||||||
headers = GitHub.api_headers
|
headers = GitHub.api_headers
|
||||||
headers["Content-Type"] = "application/json"
|
headers["Content-Type"] = "application/json"
|
||||||
|
|
||||||
request = Net::HTTP::Post.new(path, headers)
|
basic_auth_credentials = nil
|
||||||
|
if auth != :AUTH_USER_LOGIN
|
||||||
|
token, username = GitHub.api_credentials
|
||||||
|
case GitHub.api_credentials_type
|
||||||
|
when :keychain
|
||||||
|
basic_auth_credentials = [username, token]
|
||||||
|
when :environment
|
||||||
|
headers["Authorization"] = "token #{token}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
login(request) if auth == :AUTH_BASIC
|
request = Net::HTTP::Post.new(path, headers)
|
||||||
|
request.basic_auth(*basic_auth_credentials) if basic_auth_credentials
|
||||||
|
|
||||||
|
login(request) if auth == :AUTH_USER_LOGIN
|
||||||
|
|
||||||
request.body = Utils::JSON.dump(data)
|
request.body = Utils::JSON.dump(data)
|
||||||
request
|
request
|
||||||
@ -133,6 +145,7 @@ module Homebrew
|
|||||||
when Net::HTTPCreated
|
when Net::HTTPCreated
|
||||||
Utils::JSON.load get_body(response)
|
Utils::JSON.load get_body(response)
|
||||||
else
|
else
|
||||||
|
GitHub.api_credentials_error_message(response)
|
||||||
raise "HTTP #{response.code} #{response.message} (expected 201)"
|
raise "HTTP #{response.code} #{response.message} (expected 201)"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -484,7 +484,7 @@ module GitHub
|
|||||||
class RateLimitExceededError < Error
|
class RateLimitExceededError < Error
|
||||||
def initialize(reset, error)
|
def initialize(reset, error)
|
||||||
super <<-EOS.undent
|
super <<-EOS.undent
|
||||||
GitHub #{error}
|
GitHub API Error: #{error}
|
||||||
Try again in #{pretty_ratelimit_reset(reset)}, or create a personal access token:
|
Try again in #{pretty_ratelimit_reset(reset)}, or create a personal access token:
|
||||||
#{Tty.em}https://github.com/settings/tokens/new?scopes=&description=Homebrew#{Tty.reset}
|
#{Tty.em}https://github.com/settings/tokens/new?scopes=&description=Homebrew#{Tty.reset}
|
||||||
and then set the token as: export HOMEBREW_GITHUB_API_TOKEN="your_new_token"
|
and then set the token as: export HOMEBREW_GITHUB_API_TOKEN="your_new_token"
|
||||||
@ -506,9 +506,12 @@ module GitHub
|
|||||||
EOS
|
EOS
|
||||||
else
|
else
|
||||||
message << <<-EOS.undent
|
message << <<-EOS.undent
|
||||||
The GitHub credentials in the OS X keychain are invalid.
|
The GitHub credentials in the OS X keychain may be invalid.
|
||||||
Clear them with:
|
Clear them with:
|
||||||
printf "protocol=https\\nhost=github.com\\n" | git credential-osxkeychain erase
|
printf "protocol=https\\nhost=github.com\\n" | git credential-osxkeychain erase
|
||||||
|
Or create a personal access token:
|
||||||
|
#{Tty.em}https://github.com/settings/tokens/new?scopes=&description=Homebrew#{Tty.reset}
|
||||||
|
and then set the token as: export HOMEBREW_GITHUB_API_TOKEN="your_new_token"
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
super message
|
super message
|
||||||
@ -536,32 +539,71 @@ module GitHub
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def api_headers
|
def api_credentials_type
|
||||||
@api_headers ||= begin
|
token, username = api_credentials
|
||||||
headers = {
|
if token && !token.empty?
|
||||||
"User-Agent" => HOMEBREW_USER_AGENT,
|
if username && !username.empty?
|
||||||
"Accept" => "application/vnd.github.v3+json"
|
:keychain
|
||||||
}
|
else
|
||||||
token, username = api_credentials
|
:environment
|
||||||
if token && !token.empty?
|
end
|
||||||
if username && !username.empty?
|
else
|
||||||
headers[:http_basic_authentication] = [username, token]
|
:none
|
||||||
else
|
end
|
||||||
headers["Authorization"] = "token #{token}"
|
end
|
||||||
|
|
||||||
|
def api_credentials_error_message(response_headers)
|
||||||
|
@api_credentials_error_message_printed ||= begin
|
||||||
|
unauthorized = (response_headers["status"] == "401 Unauthorized")
|
||||||
|
scopes = response_headers["x-accepted-oauth-scopes"].to_s.split(", ")
|
||||||
|
if !unauthorized && scopes.empty?
|
||||||
|
credentials_scopes = response_headers["x-oauth-scopes"].to_s.split(", ")
|
||||||
|
|
||||||
|
case GitHub.api_credentials_type
|
||||||
|
when :keychain
|
||||||
|
onoe <<-EOS.undent
|
||||||
|
Your OS X keychain GitHub credentials do not have sufficient scope!
|
||||||
|
Scopes they have: #{credentials_scopes}
|
||||||
|
Create a personal access token: https://github.com/settings/tokens
|
||||||
|
and then set HOMEBREW_GITHUB_API_TOKEN as the authentication method instead.
|
||||||
|
EOS
|
||||||
|
when :environment
|
||||||
|
onoe <<-EOS.undent
|
||||||
|
Your HOMEBREW_GITHUB_API_TOKEN does not have sufficient scope!
|
||||||
|
Scopes it has: #{credentials_scopes}
|
||||||
|
Create a new personal access token: https://github.com/settings/tokens
|
||||||
|
and then set the new HOMEBREW_GITHUB_API_TOKEN as the authentication method instead.
|
||||||
|
EOS
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
headers
|
true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def api_headers
|
||||||
|
{
|
||||||
|
"User-Agent" => HOMEBREW_USER_AGENT,
|
||||||
|
"Accept" => "application/vnd.github.v3+json"
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
def open(url, &_block)
|
def open(url, &_block)
|
||||||
# This is a no-op if the user is opting out of using the GitHub API.
|
# This is a no-op if the user is opting out of using the GitHub API.
|
||||||
return if ENV["HOMEBREW_NO_GITHUB_API"]
|
return if ENV["HOMEBREW_NO_GITHUB_API"]
|
||||||
|
|
||||||
require "net/https"
|
require "net/https"
|
||||||
|
|
||||||
|
headers = api_headers
|
||||||
|
token, username = api_credentials
|
||||||
|
case api_credentials_type
|
||||||
|
when :keychain
|
||||||
|
headers[:http_basic_authentication] = [username, token]
|
||||||
|
when :environment
|
||||||
|
headers["Authorization"] = "token #{token}"
|
||||||
|
end
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Kernel.open(url, api_headers) { |f| yield Utils::JSON.load(f.read) }
|
Kernel.open(url, headers) { |f| yield Utils::JSON.load(f.read) }
|
||||||
rescue OpenURI::HTTPError => e
|
rescue OpenURI::HTTPError => e
|
||||||
handle_api_error(e)
|
handle_api_error(e)
|
||||||
rescue EOFError, SocketError, OpenSSL::SSL::SSLError => e
|
rescue EOFError, SocketError, OpenSSL::SSL::SSLError => e
|
||||||
@ -578,6 +620,8 @@ module GitHub
|
|||||||
raise RateLimitExceededError.new(reset, error)
|
raise RateLimitExceededError.new(reset, error)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
GitHub.api_credentials_error_message(e.io.meta)
|
||||||
|
|
||||||
case e.io.status.first
|
case e.io.status.first
|
||||||
when "401", "403"
|
when "401", "403"
|
||||||
raise AuthenticationFailedError.new(e.message)
|
raise AuthenticationFailedError.new(e.message)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user