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



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

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



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

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



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

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



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

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



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

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



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

def ask_for_password
  echo_off
  password = ask
  puts
  echo_on
  return password
end

.ask_for_password_on_windowsObject



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

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



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

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



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

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

.echo_offObject



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

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

.echo_onObject



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

def echo_on
  with_tty do
    system "stty echo"
  end
end

.get_credentialsObject

:nodoc:



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

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

.has_credentialsObject



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

def has_credentials
  (nil != read_credentials)
end

.loginObject



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

def 
  delete_credentials
  get_credentials
end

.logoutObject



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

def logout
  delete_credentials
end

.netrcObject

:nodoc:



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

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



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

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:



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

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

.polling_intervalObject



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

def polling_interval
  (2.0).to_f
end

.read_credentialsObject



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

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

.reauthorizeObject



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

def reauthorize
  @credentials = ask_for_and_save_credentials
end

.retry_login?Boolean

Returns:

  • (Boolean)


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

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

.retry_set_github_username?Boolean

Returns:

  • (Boolean)


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

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

.save_github_usernameObject



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
295
# File 'lib/mortar/auth.rb', line 257

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:



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

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

.user_s3_safe(local = false) ⇒ Object



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

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

.write_credentialsObject



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

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