Class: Travis::Tools::Github

Inherits:
Object
  • Object
show all
Defined in:
lib/travis/tools/github.rb

Constant Summary collapse

TOKEN_SIZE =
40
GITHUB_API =
'api.github.com'
GITHUB_HOST =
'github.com'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = nil) {|_self| ... } ⇒ Github

Returns a new instance of Github.

Yields:

  • (_self)

Yield Parameters:



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/travis/tools/github.rb', line 16

def initialize(options = nil)
  @check_token     = true
  @manual_login    = true
  @ask_login       = proc { raise "ask_login callback not set" }
  @after_tokens    = proc { }
  @ask_password    = proc { |_| raise "ask_password callback not set" }
  @ask_otp         = proc { |_| raise "ask_otp callback not set" }
  @debug           = proc { |_| }
  @netrc_path      = '~/.netrc'
  @hub_path        = ENV['HUB_CONFIG'] || '~/.config/hub'
  @oauth_paths     = ['~/.github-oauth-token']
  @composer_path   = "~/.composer/config.json"
  @note            = 'temporary token'
  @git_config_keys = %w[github.token github.oauth-token]
  @scopes          = ['user', 'user:email', 'repo'] # overridden by value from /config
  options.each_pair { |k,v| send("#{k}=", v) if respond_to? "#{k}=" } if options
  yield self if block_given?
end

Instance Attribute Details

#after_tokensObject

Returns the value of attribute after_tokens.



12
13
14
# File 'lib/travis/tools/github.rb', line 12

def after_tokens
  @after_tokens
end

#api_urlObject

Returns the value of attribute api_url.



12
13
14
# File 'lib/travis/tools/github.rb', line 12

def api_url
  @api_url
end

#ask_loginObject

Returns the value of attribute ask_login.



12
13
14
# File 'lib/travis/tools/github.rb', line 12

def 
  @ask_login
end

#ask_otpObject

Returns the value of attribute ask_otp.



12
13
14
# File 'lib/travis/tools/github.rb', line 12

def ask_otp
  @ask_otp
end

#ask_passwordObject

Returns the value of attribute ask_password.



12
13
14
# File 'lib/travis/tools/github.rb', line 12

def ask_password
  @ask_password
end

#auto_passwordObject

Returns the value of attribute auto_password.



12
13
14
# File 'lib/travis/tools/github.rb', line 12

def auto_password
  @auto_password
end

#auto_tokenObject

Returns the value of attribute auto_token.



12
13
14
# File 'lib/travis/tools/github.rb', line 12

def auto_token
  @auto_token
end

#callbackObject

Returns the value of attribute callback.



12
13
14
# File 'lib/travis/tools/github.rb', line 12

def callback
  @callback
end

#check_tokenObject

Returns the value of attribute check_token.



12
13
14
# File 'lib/travis/tools/github.rb', line 12

def check_token
  @check_token
end

#composer_pathObject

Returns the value of attribute composer_path.



12
13
14
# File 'lib/travis/tools/github.rb', line 12

def composer_path
  @composer_path
end

#debug=(value) ⇒ Object

Sets the attribute debug

Parameters:

  • value

    the value to set the attribute debug to.



12
13
14
# File 'lib/travis/tools/github.rb', line 12

def debug=(value)
  @debug = value
end

#drop_tokenObject

Returns the value of attribute drop_token.



12
13
14
# File 'lib/travis/tools/github.rb', line 12

def drop_token
  @drop_token
end

#explodeObject

Returns the value of attribute explode.



12
13
14
# File 'lib/travis/tools/github.rb', line 12

def explode
  @explode
end

#git_config_keysObject

Returns the value of attribute git_config_keys.



12
13
14
# File 'lib/travis/tools/github.rb', line 12

def git_config_keys
  @git_config_keys
end

#github_loginObject

Returns the value of attribute github_login.



12
13
14
# File 'lib/travis/tools/github.rb', line 12

def 
  @github_login
end

#github_tokenObject

Returns the value of attribute github_token.



12
13
14
# File 'lib/travis/tools/github.rb', line 12

def github_token
  @github_token
end

#hub_pathObject

Returns the value of attribute hub_path.



12
13
14
# File 'lib/travis/tools/github.rb', line 12

def hub_path
  @hub_path
end

#login_headerObject

Returns the value of attribute login_header.



12
13
14
# File 'lib/travis/tools/github.rb', line 12

def 
  @login_header
end

#manual_loginObject

Returns the value of attribute manual_login.



12
13
14
# File 'lib/travis/tools/github.rb', line 12

def 
  @manual_login
end

#netrc_pathObject

Returns the value of attribute netrc_path.



12
13
14
# File 'lib/travis/tools/github.rb', line 12

def netrc_path
  @netrc_path
end

#no_tokenObject

Returns the value of attribute no_token.



12
13
14
# File 'lib/travis/tools/github.rb', line 12

def no_token
  @no_token
end

#noteObject

Returns the value of attribute note.



12
13
14
# File 'lib/travis/tools/github.rb', line 12

def note
  @note
end

#oauth_pathsObject

Returns the value of attribute oauth_paths.



12
13
14
# File 'lib/travis/tools/github.rb', line 12

def oauth_paths
  @oauth_paths
end

#scopesObject

Returns the value of attribute scopes.



12
13
14
# File 'lib/travis/tools/github.rb', line 12

def scopes
  @scopes
end

Instance Method Details

#acceptable?(token) ⇒ Boolean

Returns:

  • (Boolean)


242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/travis/tools/github.rb', line 242

def acceptable?(token)
  return true unless check_token
  gh   = GH.with(:token => token)
  user = gh['user']

  if  and  != user['login']
    debug "token is not acceptable: identifies %p instead of %p" % [user['login'], ]
    false
  else
    true
  end
rescue GH::Error => error
  debug "token is not acceptable: #{gh_error(error)}"
  false
end

#api_hostObject



202
203
204
205
# File 'lib/travis/tools/github.rb', line 202

def api_host
  return GITHUB_API unless api_url
  api_url[%r{^(?:https?://)?([^/]+)}, 1]
end

#ask_credentialsObject



86
87
88
89
90
91
# File 'lib/travis/tools/github.rb', line 86

def ask_credentials
  .call if 
  user     =  || .call
  password = ask_password.arity == 0 ? ask_password.call : ask_password.call(user)
  [user, password]
end

#basic_auth(user, password, die = true, otp = nil, &block) ⇒ Object



207
208
209
210
211
212
# File 'lib/travis/tools/github.rb', line 207

def basic_auth(user, password, die = true, otp = nil, &block)
  gh = GH.with(:username => user, :password => password)
  with_otp(gh, user, otp, &block)
rescue GH::Error => error
  raise gh_error(error) if die
end

#composer_tokenObject



120
121
122
123
124
125
# File 'lib/travis/tools/github.rb', line 120

def composer_token
  file(composer_path) do |content|
    token = JSON.parse(content)['config'].fetch('github-oauth', {})[host]
    yield token if token
  end
end

#create_token(gh) ⇒ Object



223
224
225
226
227
228
229
230
231
# File 'lib/travis/tools/github.rb', line 223

def create_token(gh)
  gh.post('/authorizations', :scopes => scopes, :note => note)
rescue GH::Error => error
  # token might already exist due to bug in earlier CLI version, we'll have to delete it first
  raise error unless error.info[:response_status] == 422 and error.info[:response_body].to_s =~ /already_exists/
  raise error unless reply = gh['/authorizations'].detect { |a| a['note'] == note }
  gh.delete(reply['_links']['self']['href'])
  retry
end

#each_tokenObject



47
48
49
50
51
52
53
# File 'lib/travis/tools/github.rb', line 47

def each_token
  require 'gh' unless defined? GH
  possible_tokens { |t| yield(t) if acceptable?(t) }
ensure
  callback, self.callback = self.callback, nil
  callback.call if callback
end

#git_tokensObject



110
111
112
113
114
115
116
117
118
# File 'lib/travis/tools/github.rb', line 110

def git_tokens
  return unless System.has? 'git'
  git_config_keys.each do |key|
    `git config --get-all #{key}`.each_line do |line|
      token = line.strip
      yield token unless token.empty?
    end
  end
end

#github_for_mac_token(&block) ⇒ Object



192
193
194
195
196
# File 'lib/travis/tools/github.rb', line 192

def github_for_mac_token(&block)
  command = '-s "github.com/mac"'
  command << " -a #{}" if 
  security(:internet, :w, command, "GitHub for Mac token", &block) if host == 'github.com'
end

#hostObject



198
199
200
# File 'lib/travis/tools/github.rb', line 198

def host
  api_host == GITHUB_API ? GITHUB_HOST : api_host
end

#hubObject



182
183
184
185
186
# File 'lib/travis/tools/github.rb', line 182

def hub
  file(hub_path, {}) do |contents|
    YAML.load(contents)
  end
end

#hub_loginsObject



151
152
153
154
155
156
# File 'lib/travis/tools/github.rb', line 151

def hub_logins
  hub.fetch(host, []).each do |entry|
    next if  and  != entry["user"]
    yield entry["user"], entry["password"] if entry["user"] and entry["password"]
  end
end

#hub_tokensObject



127
128
129
130
131
132
# File 'lib/travis/tools/github.rb', line 127

def hub_tokens
  hub.fetch(host, []).each do |entry|
    next if  and  != entry["user"]
    yield entry["oauth_token"] if entry["oauth_token"]
  end
end

#issuepost_token(&block) ⇒ Object



188
189
190
# File 'lib/travis/tools/github.rb', line 188

def issuepost_token(&block)
  security(:generic, :w, "-l issuepost.github.access_token",  "issuepost token", &block) if host == 'github.com'
end

#keychain_loginObject



158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/travis/tools/github.rb', line 158

def 
  if 
    security(:internet, :w, "-s #{host} -a #{}", "#{host} password for #{}") do |password|
      yield , password if password and not password.empty?
    end
  else
    security(:internet, :g, "-s #{host}", "#{host} login and password") do |data|
      username = data[/^\s+"acct"<blob>="(.*)"$/, 1].to_s
      password = data[/^password: "(.*)"$/, 1].to_s
      yield username, password unless username.empty? or password.empty?
    end
  end
end

#login(user, password, die = true, otp = nil) ⇒ Object



214
215
216
217
218
219
220
221
# File 'lib/travis/tools/github.rb', line 214

def (user, password, die = true, otp = nil)
  basic_auth(user, password, die, otp) do |gh, new_otp|
    reply         = create_token(gh)
    auth_href     = reply['_links']['self']['href']
    self.callback = proc { with_otp(gh, user, new_otp) { |g| g.delete(auth_href) } } if drop_token
    reply['token']
  end
end

#netrcObject



172
173
174
175
176
177
178
179
180
# File 'lib/travis/tools/github.rb', line 172

def netrc
  file(netrc_path, []) do |contents|
    contents.scan(/^\s*(\S+)\s+(\S+)\s*$/).inject([]) do |mapping, (key, value)|
      mapping << {} if key == "machine"
      mapping.last[key] = value if mapping.last
      mapping
    end
  end
end

#netrc_loginsObject



143
144
145
146
147
148
149
# File 'lib/travis/tools/github.rb', line 143

def netrc_logins
  netrc.each do |entry|
    next unless entry["machine"] == api_host or entry["machine"] == host
    next if  and  != entry["login"]
    yield entry["login"], entry["password"] if entry["login"] and entry["password"]
  end
end

#netrc_tokensObject



99
100
101
102
103
104
105
106
107
108
# File 'lib/travis/tools/github.rb', line 99

def netrc_tokens
  netrc.each do |entry|
    next unless entry["machine"] == api_host or entry["machine"] == host
    entry.values_at("token", "login", "password").each do |entry|
      next if entry.to_s.size != TOKEN_SIZE
      debug "found oauth token in netrc"
      yield entry
    end
  end
end

#oauth_file_tokens(&block) ⇒ Object



134
135
136
137
138
139
140
141
# File 'lib/travis/tools/github.rb', line 134

def oauth_file_tokens(&block)
  oauth_paths.each do |path|
    file(path) do |content|
      token = content.strip
      yield token unless token.empty?
    end
  end
end

#possible_logins(&block) ⇒ Object



93
94
95
96
97
# File 'lib/travis/tools/github.rb', line 93

def possible_logins(&block)
  netrc_logins(&block)
  hub_logins(&block)
  (&block)
end

#possible_tokens(&block) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/travis/tools/github.rb', line 59

def possible_tokens(&block)
  return block[github_token] if github_token

  if auto_token
    netrc_tokens(&block)
    git_tokens(&block)
    hub_tokens(&block)
    oauth_file_tokens(&block)
    github_for_mac_token(&block)
    issuepost_token(&block)
    composer_token(&block)
  end

  if auto_password
    possible_logins do |user, password|
      yield (user, password, false)
    end
  end

  if 
    user, password = ask_credentials
    yield (user, password, true)
  end

  after_tokens.call
end

#with_basic_auth(&block) ⇒ Object



39
40
41
42
43
44
45
# File 'lib/travis/tools/github.rb', line 39

def with_basic_auth(&block)
  user, password = ask_credentials
  basic_auth(user, password, true) do |gh, _|
    gh['user'] # so otp kicks in
    yield gh
  end
end

#with_otp(gh, user, otp, &block) ⇒ Object



233
234
235
236
237
238
239
240
# File 'lib/travis/tools/github.rb', line 233

def with_otp(gh, user, otp, &block)
  gh = GH.with(gh.options.merge(:headers => { "X-GitHub-OTP" => otp })) if otp
  block.call(gh, otp)
rescue GH::Error => error
  raise error unless error.info[:response_status] == 401 and error.info[:response_headers]['x-github-otp'].to_s =~ /required/
  otp = ask_otp.arity == 0 ? ask_otp.call : ask_otp.call(user)
  retry
end

#with_session(&block) ⇒ Object



55
56
57
# File 'lib/travis/tools/github.rb', line 55

def with_session(&block)
  with_token { |t| GH.with(:token => t) { yield(t) } }
end

#with_tokenObject



35
36
37
# File 'lib/travis/tools/github.rb', line 35

def with_token
  each_token { |t| break yield(t) }
end