Module: Knowngithub

Defined in:
lib/knowngithub.rb,
lib/knowngithub/version.rb

Constant Summary collapse

VERSION =
'2.0.0'.freeze

Class Method Summary collapse

Class Method Details

.fingerprintsArray<String>

Queries and parses the GitHub help page for the SSH key fingerprints.

Returns:

  • (Array<String>)

    SSH key fingerprints as an array of strings.

Since:

  • 1.0.0



29
30
31
32
33
34
35
36
# File 'lib/knowngithub.rb', line 29

def self.fingerprints
  pattern = /^(sha256:[a-z0-9\+\/]{43})|([0-9a-f\:]{32,47})$/i
  res = safe_call('https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/githubs-ssh-key-fingerprints')

  output = Nokogiri::HTML(res.body)
  fields = output.xpath('//code')
  fields.children.map(&:content).select { |x| pattern =~ x }
end

.hostHash

Composes a hash with the properties required for composing a known host entry

Returns:

  • (Hash)

    Returns a hash object with all of the needed components to compose a ‘known_hosts` file

Raises:

  • (SecurityError)

    If the host keys fail validation or if the https call fails, this will be raised.

Since:

  • 0.1.0



51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/knowngithub.rb', line 51

def self.host
  s = session
  if fingerprints.any? { |f| f == s.host_keys.first.fingerprint }
    base64_key = [Net::SSH::Buffer.from(:key, s.host_keys.first).to_s].pack('m*').gsub(/\s/, '')
    return {
      'host_as_string' => s.host_as_string,
      'ssh_type' => s.host_keys.first.ssh_type,
      'base64_key' => base64_key
    }
  else
    raise SecurityError # while this is inappropriate, it sounds cool
  end
end

.known_hostString

Composes a known_hosts entry for the fqdn only

Returns:

  • (String)

    Returns a ‘known_hosts` entry for the fqdn only with no ip address binding as a string.

Since:

  • 0.1.0



68
69
70
71
# File 'lib/knowngithub.rb', line 68

def self.known_host
  h = host
  [h['host_as_string'], h['ssh_type'], h['base64_key']].join(' ')
end

.known_hostsArray<String>

Calls the ‘/meta` endpoint on GitHub’s API via a safe https call and composes an array of entries ready for appending to a known_hosts file.

Returns:

  • (Array<String>)

    Returns an array of strings enunciating ‘known_hosts` entries for every known IP GitHub may serve SSH on.

Since:

  • 0.1.0



76
77
78
79
80
81
82
83
84
85
86
# File 'lib/knowngithub.rb', line 76

def self.known_hosts
  h = host
  cidr_ranges = JSON.parse(safe_call('https://api.github.com/meta').body)['git']
  known_hosts = []
  cidr_ranges.each do |range|
    IPAddr.new(range).to_range.to_a.map(&:to_s).each do |ip|
      known_hosts << ["github.com,#{ip}", h['ssh_type'], h['base64_key']].join(' ')
    end
  end
  known_hosts
end

.safe_call(url) ⇒ Net::HTTP

Make a call enforcing the strict use of SSL.

Parameters:

Returns:

  • (Net::HTTP)

    Return the full Net::HTTP object of the response.

Since:

  • 0.1.0



15
16
17
18
19
20
21
22
23
24
# File 'lib/knowngithub.rb', line 15

def self.safe_call(url)
  uri = URI.parse(url)
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER

  request = Net::HTTP::Get.new(uri.request_uri)

  http.request(request)
end

.sessionNet:SSH

Instantiates a Net::SSH session with GitHub to get the host key and closes it.

Returns:

  • (Net:SSH)

    Returns a closed Net::SSH session

Since:

  • 0.1.0



41
42
43
44
45
# File 'lib/knowngithub.rb', line 41

def self.session
  s = Net::SSH::Transport::Session.new('github.com', verify_host_key: true)
  s.close
  s
end