Class: Mortar::Auth

Inherits:
Object
  • Object
show all
Extended by:
Helpers
Defined in:
lib/mortar/auth.rb

Class Attribute Summary collapse

Class Method Summary collapse

Methods included from Helpers

action, ask, confirm, copy_if_not_present_at_dest, default_host, deprecate, display, display_header, display_object, display_row, display_table, display_with_indent, download_to_file, ensure_dir_exists, error, error_with_failure, error_with_failure=, extended, extended_into, format_bytes, format_date, format_with_bang, full_host, get_terminal_environment, home_directory, host, hprint, hputs, included, included_into, installed_with_omnibus?, json_decode, json_encode, line_formatter, longest, output_with_bang, pending_github_team_state_message, quantify, redisplay, retry_on_exception, running_on_a_mac?, running_on_windows?, set_buffer, shell, spinner, status, string_distance, styled_array, styled_error, styled_hash, styled_header, suggestion, test_name, ticking, time_ago, truncate, warning, with_tty, write_to_file

Class Attribute Details

.credentialsObject

Returns the value of attribute credentials.



30
31
32
# File 'lib/mortar/auth.rb', line 30

def credentials
  @credentials
end

Class Method Details

.apiObject



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/mortar/auth.rb', line 32

def api
  @api ||= begin
    require("mortar-api-ruby")
    api = Mortar::API.new(default_params.merge(:user => user, :api_key => password))

    def api.request(params, &block)
      response = super
      if response.headers.has_key?('X-Mortar-Warning')
        Mortar::Command.warnings.concat(response.headers['X-Mortar-Warning'].split("\n"))
      end
      response
    end

    api
  end
end

.api_key(user = get_credentials[0], password = get_credentials[1]) ⇒ Object



95
96
97
98
99
# File 'lib/mortar/auth.rb', line 95

def api_key(user = get_credentials[0], password = get_credentials[1])
  require("mortar-api-ruby")
  api = Mortar::API.new(default_params)
  api.(user, password).body["api_key"]
end

.ask_for_and_save_credentialsObject



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
# File 'lib/mortar/auth.rb', line 223

def ask_for_and_save_credentials
  require("mortar-api-ruby") # for the errors
  begin
    @credentials = ask_for_credentials
    write_credentials
    check
  rescue Mortar::API::Errors::NotFound, Mortar::API::Errors::Unauthorized => e
    delete_credentials
    display "Authentication failed."
    retry if retry_login?
    exit 1
  rescue Mortar::CLI::Errors::InvalidGithubUsername => e
    #Too many failures at setting github username
    display "Authentication failed."
    delete_credentials
    exit 1
  rescue Exception => e
    delete_credentials
    raise e
  end
  # TODO: ensure that keys exist
  #check_for_associated_ssh_key unless Mortar::Command.current_command == "keys:add"
  @credentials
end

.ask_for_and_save_github_usernameObject



248
249
250
251
252
253
254
# File 'lib/mortar/auth.rb', line 248

def ask_for_and_save_github_username
  require ("mortar-api-ruby")
  begin
    @github_username = ask_for_github_username
    save_github_username
  end
end

.ask_for_credentialsObject



175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/mortar/auth.rb', line 175

def ask_for_credentials
  puts
  puts "Enter your Mortar credentials (#{host})."

  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_github_usernameObject



188
189
190
191
192
193
194
195
# File 'lib/mortar/auth.rb', line 188

def ask_for_github_username
  puts
  puts "Please enter your GitHub username (not email address)."

  print "GitHub Username: "
  github_username = ask
  github_username
end

.ask_for_passwordObject



215
216
217
218
219
220
221
# File 'lib/mortar/auth.rb', line 215

def ask_for_password
  echo_off
  password = ask
  puts
  echo_on
  return password
end

.ask_for_password_on_windowsObject



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/mortar/auth.rb', line 197

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

.checkObject



57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/mortar/auth.rb', line 57

def check
  @mortar_user = api.get_user.body
  #Need to ensure user has a github_username
  unless @mortar_user.fetch("user_github_username", nil)
    begin
      ask_for_and_save_github_username
    rescue Mortar::CLI::Errors::InvalidGithubUsername => e
      retry if retry_set_github_username?
      raise e
    end
  end
end

.delete_credentialsObject



109
110
111
112
113
114
115
# File 'lib/mortar/auth.rb', line 109

def delete_credentials
  if netrc
    netrc.delete("api.#{host}")
    netrc.save
  end
  @api, @client, @credentials = nil, nil
end

.echo_offObject



163
164
165
166
167
# File 'lib/mortar/auth.rb', line 163

def echo_off
  with_tty do
    system "stty -echo"
  end
end

.echo_onObject



169
170
171
172
173
# File 'lib/mortar/auth.rb', line 169

def echo_on
  with_tty do
    system "stty echo"
  end
end

.get_credentialsObject

:nodoc:



105
106
107
# File 'lib/mortar/auth.rb', line 105

def get_credentials    # :nodoc:
  @credentials ||= (read_credentials || ask_for_and_save_credentials)
end

.has_credentialsObject



101
102
103
# File 'lib/mortar/auth.rb', line 101

def has_credentials
  (nil != read_credentials)
end

.loginObject



49
50
51
# File 'lib/mortar/auth.rb', line 49

def 
  get_credentials
end

.logoutObject



53
54
55
# File 'lib/mortar/auth.rb', line 53

def logout
  delete_credentials
end

.netrcObject

:nodoc:



130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/mortar/auth.rb', line 130

def netrc   # :nodoc:
  @netrc ||= begin
    File.exists?(netrc_path) && Netrc.read(netrc_path)
  rescue => error
    if error.message =~ /^Permission bits for/
      perm = File.stat(netrc_path).mode & 0777
      abort("Permissions #{perm} for '#{netrc_path}' are too open. You should run `chmod 0600 #{netrc_path}` so that your credentials are NOT accessible by others.")
    else
      raise error
    end
  end
end

.netrc_pathObject



117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/mortar/auth.rb', line 117

def netrc_path
  default = Netrc.default_path
  encrypted = default + ".gpg"
  from_env = ENV['MORTAR_LOGIN_FILE']
  if from_env
    from_env
  elsif File.exists?(encrypted)
    encrypted
  else
    default
  end
end

.password(local = false) ⇒ Object

:nodoc:



82
83
84
85
86
87
88
# File 'lib/mortar/auth.rb', line 82

def password(local=false)    # :nodoc:
  if (local && !has_credentials)
    "notloggedin"
  else
    get_credentials[1]
  end
end

.polling_intervalObject



309
310
311
# File 'lib/mortar/auth.rb', line 309

def polling_interval
  (2.0).to_f
end

.read_credentialsObject



143
144
145
146
147
148
149
150
151
# File 'lib/mortar/auth.rb', line 143

def read_credentials
  if ENV['MORTAR_API_KEY']
    ['', ENV['MORTAR_API_KEY']]
  else
    if netrc
      netrc["api.#{host}"]
    end
  end
end

.reauthorizeObject



70
71
72
# File 'lib/mortar/auth.rb', line 70

def reauthorize
  @credentials = ask_for_and_save_credentials
end

.retry_login?Boolean



297
298
299
300
301
# File 'lib/mortar/auth.rb', line 297

def retry_login?
  @login_attempts ||= 0
  @login_attempts += 1
  @login_attempts < 3
end

.retry_set_github_username?Boolean



303
304
305
306
307
# File 'lib/mortar/auth.rb', line 303

def retry_set_github_username?
  @set_github_username_attempts ||= 0
  @set_github_username_attempts += 1
  @set_github_username_attempts < 3
end

.save_github_usernameObject



256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'lib/mortar/auth.rb', line 256

def save_github_username
  task_id = api.update_user(@mortar_user['user_id'], {'user_github_username' => @github_username}).body['task_id']

  task_result = nil
  user_result = nil
  ticking(polling_interval) do |ticks|
    task_result = api.get_task(task_id).body
    is_finished =
      Mortar::API::Task::STATUSES_COMPLETE.include?(task_result["status_code"])
    if is_finished
      user_result = api.get_user().body
    end

    redisplay("Setting github username: %s" %
      [is_finished ? " Done!" : spinner(ticks)],
      is_finished) # only display newline on last message
    if is_finished
      display
      break
    end
  end

  case task_result['status_code']
  when Mortar::API::Task::STATUS_FAILURE
    error_message = "Setting github username failed with #{task_result['error_type'] || 'error'}"
    error_message += ":\n\n#{task_result['error_message']}\n\n"
    output_with_bang error_message
    raise Mortar::CLI::Errors::InvalidGithubUsername.new
  when Mortar::API::Task::STATUS_SUCCESS
    display "Successfully set github username."

    if user_result['github_team_state'] == 'pending'
      display pending_github_team_state_message(user_result['github_accept_invite_url'])
    end
  else
    #Raise error so .netrc file is wiped out.
    raise RuntimeError, "Unknown task status: #{task_result['status_code']}"
  end
end

.user(local = false) ⇒ Object

:nodoc:



74
75
76
77
78
79
80
# File 'lib/mortar/auth.rb', line 74

def user(local=false)    # :nodoc:
  if (local && !has_credentials)
    "[email protected]"
  else
    get_credentials[0]
  end
end

.user_s3_safe(local = false) ⇒ Object



90
91
92
93
# File 'lib/mortar/auth.rb', line 90

def user_s3_safe(local = false)
  user_email = user(local)
  return user_email.gsub(/[^0-9a-zA-Z]/i, '-')
end

.write_credentialsObject



153
154
155
156
157
158
159
160
161
# File 'lib/mortar/auth.rb', line 153

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.save
end