class Heroku::Auth
Attributes
credentials[RW]
two_factor_code[RW]
Public Instance Methods
api()
click to toggle source
# File lib/heroku/auth.rb, line 14 def api @api ||= begin require("heroku-api") api = Heroku::API.new(default_params.merge(:api_key => password)) def api.request(params, &block) response = super if response.headers.has_key?('X-Heroku-Warning') Heroku::Command.warnings.concat(response.headers['X-Heroku-Warning'].split("\n")) end response end api end end
api_key(user = get_credentials[0], password = get_credentials[1])
click to toggle source
# File lib/heroku/auth.rb, line 77 def api_key(user = get_credentials[0], password = get_credentials[1]) require("heroku-api") api = Heroku::API.new(default_params) api.post_login(user, password).body["api_key"] rescue Heroku::API::Errors::Unauthorized => e id = json_decode(e.response.body)["id"] raise if id != "invalid_two_factor_code" delete_credentials display "Authentication failed due to an invalid two-factor code." display "Please check your code was typed correctly and that your" display "authenticator's time keeping is accurate." exit 1 rescue Heroku::API::Errors::Forbidden => e if e.response.headers.has_key?("Heroku-Two-Factor-Required") ask_for_second_factor retry end end
ask_for_and_save_credentials()
click to toggle source
# File lib/heroku/auth.rb, line 242 def ask_for_and_save_credentials require("heroku-api") # for the errors begin @credentials = ask_for_credentials write_credentials check rescue Heroku::API::Errors::NotFound, Heroku::API::Errors::Unauthorized => e delete_credentials display "Authentication failed." retry if retry_login? exit 1 rescue Exception => e delete_credentials raise e end check_for_associated_ssh_key unless Heroku::Command.current_command == "keys:add" @credentials end
ask_for_credentials()
click to toggle source
# File lib/heroku/auth.rb, line 193 def ask_for_credentials puts "Enter your Heroku credentials." print "Email: " user = ask print "Password (typing will be hidden): " password = running_on_windows? ? ask_for_password_on_windows : ask_for_password [user, api_key(user, password)] end
ask_for_password()
click to toggle source
# File lib/heroku/auth.rb, line 231 def ask_for_password begin echo_off password = ask puts ensure echo_on end return password end
ask_for_password_on_windows()
click to toggle source
# File lib/heroku/auth.rb, line 213 def ask_for_password_on_windows require "Win32API" char = nil password = '' while char = Win32API.new("crtdll", "_getch", [ ], "L").Call do break if char == 10 || char == 13 # received carriage return or newline if char == 127 || char == 8 # backspace and delete password.slice!(-1, 1) else # windows might throw a -1 at us so make sure to handle RangeError (password << char.chr) rescue RangeError end end puts return password end
ask_for_second_factor()
click to toggle source
# File lib/heroku/auth.rb, line 205 def ask_for_second_factor print "Two-factor code: " @two_factor_code = ask @two_factor_code = nil if @two_factor_code == "" @api = nil # reset it @two_factor_code end
associate_key(key)
click to toggle source
# File lib/heroku/auth.rb, line 311 def associate_key(key) action("Uploading SSH public key #{key}") do if File.exists?(key) api.post_key(File.read(key)) else error("Could not upload SSH public key: key file '" + key + "' does not exist") end end end
associate_or_generate_ssh_key()
click to toggle source
# File lib/heroku/auth.rb, line 267 def associate_or_generate_ssh_key public_keys = Dir.glob("#{home_directory}/.ssh/*.pub").sort case public_keys.length when 0 then display "Could not find an existing public key." display "Would you like to generate one? [Yn] ", false unless ask.strip.downcase == "n" display "Generating new SSH public key." generate_ssh_key("id_rsa") associate_key("#{home_directory}/.ssh/id_rsa.pub") end when 1 then display "Found existing public key: #{public_keys.first}" associate_key(public_keys.first) else display "Found the following SSH public keys:" public_keys.each_with_index do |key, index| display "#{index+1}) #{File.basename(key)}" end display "Which would you like to use with your Heroku account? ", false choice = ask.to_i - 1 chosen = public_keys[choice] if choice == -1 || chosen.nil? error("Invalid choice") end associate_key(chosen) end end
base_host(host)
click to toggle source
# File lib/heroku/auth.rb, line 331 def base_host(host) parts = URI.parse(full_host(host)).host.split(".") return parts.first if parts.size == 1 parts[-2..-1].join(".") end
check()
click to toggle source
just a stub; will raise if not authenticated
# File lib/heroku/auth.rb, line 49 def check api.get_user end
check_for_associated_ssh_key()
click to toggle source
# File lib/heroku/auth.rb, line 261 def check_for_associated_ssh_key if api.get_keys.body.empty? associate_or_generate_ssh_key end end
client()
click to toggle source
# File lib/heroku/auth.rb, line 31 def client @client ||= begin client = Heroku::Client.new(user, password, host) client.on_warning { |msg| self.display("\n#{msg}\n\n") } client end end
default_host()
click to toggle source
# File lib/heroku/auth.rb, line 53 def default_host "heroku.com" end
delete_credentials()
click to toggle source
# File lib/heroku/auth.rb, line 100 def delete_credentials if File.exists?(legacy_credentials_path) FileUtils.rm_f(legacy_credentials_path) end if netrc netrc.delete("api.#{host}") netrc.delete("code.#{host}") netrc.save end @api, @client, @credentials = nil, nil end
echo_off()
click to toggle source
# File lib/heroku/auth.rb, line 181 def echo_off with_tty do system "stty -echo" end end
echo_on()
click to toggle source
# File lib/heroku/auth.rb, line 187 def echo_on with_tty do system "stty echo" end end
full_host(host)
click to toggle source
# File lib/heroku/auth.rb, line 337 def full_host(host) (host =~ /^http/) ? host : "https://api.#{host}" end
generate_ssh_key(keyfile)
click to toggle source
# File lib/heroku/auth.rb, line 297 def generate_ssh_key(keyfile) ssh_dir = File.join(home_directory, ".ssh") unless File.exists?(ssh_dir) FileUtils.mkdir_p ssh_dir unless running_on_windows? File.chmod(0700, ssh_dir) end end output = %xssh-keygen -t rsa -N "" -f \"#{home_directory}/.ssh/#{keyfile}\" 2>&1` if ! $?.success? error("Could not generate key: #{output}") end end
git_host()
click to toggle source
# File lib/heroku/auth.rb, line 57 def git_host ENV['HEROKU_GIT_HOST'] || host end
host()
click to toggle source
# File lib/heroku/auth.rb, line 61 def host ENV['HEROKU_HOST'] || default_host end
legacy_credentials_path()
click to toggle source
# File lib/heroku/auth.rb, line 112 def legacy_credentials_path if host == default_host "#{home_directory}/.heroku/credentials" else "#{home_directory}/.heroku/credentials.#{CGI.escape(host)}" end end
login()
click to toggle source
# File lib/heroku/auth.rb, line 39 def login delete_credentials get_credentials end
logout()
click to toggle source
# File lib/heroku/auth.rb, line 44 def logout delete_credentials end
netrc_path()
click to toggle source
# File lib/heroku/auth.rb, line 120 def netrc_path default = Netrc.default_path encrypted = default + ".gpg" if File.exists?(encrypted) encrypted else default end end
read_credentials()
click to toggle source
# File lib/heroku/auth.rb, line 143 def read_credentials if ENV['HEROKU_API_KEY'] ['', ENV['HEROKU_API_KEY']] else # convert legacy credentials to netrc if File.exists?(legacy_credentials_path) @api, @client = nil @credentials = File.read(legacy_credentials_path).split("\n") write_credentials FileUtils.rm_f(legacy_credentials_path) end # read netrc credentials if they exist if netrc # force migration of long api tokens (80 chars) to short ones (40) # #write_credentials rewrites both api.* and code.* credentials = netrc["api.#{host}"] if credentials && credentials[1].length > 40 @credentials = [ credentials[0], credentials[1][0,40] ] write_credentials end netrc["api.#{host}"] end end end
retry_login?()
click to toggle source
# File lib/heroku/auth.rb, line 321 def retry_login? @login_attempts ||= 0 @login_attempts += 1 @login_attempts < 3 end
verified_hosts()
click to toggle source
# File lib/heroku/auth.rb, line 327 def verified_hosts %w( heroku.com heroku-shadow.com ) end
verify_host?(host)
click to toggle source
# File lib/heroku/auth.rb, line 341 def verify_host?(host) hostname = base_host(host) verified = verified_hosts.include?(hostname) verified = false if ENV["HEROKU_SSL_VERIFY"] == "disable" verified end
write_credentials()
click to toggle source
# File lib/heroku/auth.rb, line 170 def write_credentials FileUtils.mkdir_p(File.dirname(netrc_path)) FileUtils.touch(netrc_path) unless running_on_windows? FileUtils.chmod(0600, netrc_path) end netrc["api.#{host}"] = self.credentials netrc["code.#{host}"] = self.credentials netrc.save end
Protected Instance Methods
default_params()
click to toggle source
# File lib/heroku/auth.rb, line 350 def default_params uri = URI.parse(full_host(host)) headers = { 'User-Agent' => Heroku.user_agent } if two_factor_code headers.merge!("Heroku-Two-Factor-Code" => two_factor_code) end { :headers => headers, :host => uri.host, :port => uri.port.to_s, :scheme => uri.scheme, :ssl_verify_peer => verify_host?(host) } end