class Travis::CLI::Sshkey
def check_access(gh)
def check_access(gh) gh["repos/#{slug}"] rescue GH::Error error "GitHub account has no read access to #{color slug, :bold}" end
def delete_key
def delete_key return if interactive? and not danger_zone? "Remove SSH key for #{color slug, :info}?" say "Removing ssh key for #{color slug, :info}" ssh_key.delete rescue Travis::Client::NotFound warn "no key found to remove" end
def display_key
def display_key say "Current SSH key: #{color(ssh_key.description, :info)}" say "Finger print: #{color(ssh_key.fingerprint, :info)}" rescue Travis::Client::NotFound say "No custom SSH key installed." exit 1 if check? end
def generate_key
def generate_key github.with_basic_auth do |gh| login = gh['user']['login'] check_access(gh) empty_line say "Generating RSA key." private_key = Tools::SSLKey.generate_rsa self.description ||= "key for fetching dependencies for #{slug} via #{login}" say "Uploading public key to GitHub." gh.post("/user/keys", :title => "#{description} (Travis CI)", :key => Tools::SSLKey.rsa_ssh(private_key.public_key)) say "Uploading private key to Travis CI." ssh_key.update(:value => private_key.to_s, :description => description) empty_line say "You can store the private key to reuse it for other repositories (travis sshkey --upload FILE)." if agree("Store private key? ") { |q| q.default = "no" } path = ask("Path: ") { |q| q.default = "id_travis_rsa" } File.write(path, private_key.to_s) end end end
def github
def github @github ||= begin load_gh Tools::Github.new(session.config['github']) do |g| g.note = "token for fetching dependencies for #{slug} (Travis CI)" g.explode = explode? g.ask_login = proc { ask("Username: ") } g.ask_password = proc { |user| ask("Password for #{user}: ") { |q| q.echo = "*" } } g.ask_otp = proc { |user| ask("Two-factor authentication code for #{user}: ") } g.login_header = proc { login_header } g.debug = proc { |log| debug(log) } g.after_tokens = proc { g.explode = true and error("no suitable github token found") } end end end
def login_header
def login_header say "We need the #{color("GitHub login", :important)} for the account you want to add the key to." say "This information will #{color("not be sent to Travis CI", :important)}, only to #{color(github_endpoint.host, :info)}." say "The password will not be displayed." empty_line end
def remove_passphrase(value)
def remove_passphrase(value) return value unless Tools::SSLKey.has_passphrase? value return Tools::SSLKey.remove_passphrase(value, passphrase) || error("wrong pass phrase") if passphrase error "Key is encrypted, but missing --passphrase option" unless interactive? say "The private key is protected by a pass phrase." result = Tools::SSLKey.remove_passphrase(value, ask("Enter pass phrase: ") { |q| q.echo = "*" }) until result empty_line result end
def run
def run error "SSH keys are not available on #{color(session.config['host'], :bold)}" if org? delete_key if delete? update_key File.read(upload), upload if upload? update_key $stdin.read, 'stdin' if stdin? generate_key if generate? display_key end
def update_key(value, file)
def update_key(value, file) error "#{file} does not look like a private key" unless value.lines.first =~ /PRIVATE KEY/ value = remove_passphrase(value) self.description ||= ask("Key description: ") { |q| q.default = "Custom Key" } if interactive? say "Updating ssh key for #{color slug, :info} with key from #{color file, :info}" empty_line ssh_key.update(:value => value, :description => description || file) end