Class: Nimbu::Auth

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

Class Attribute Summary collapse

Class Method Summary collapse

Methods included from Helpers

action, ask, confirm, confirm_billing, confirm_command, create_git_remote, deprecate, disable_error_capture, display, display_header, display_object, display_row, display_table, enable_error_capture, error, error_with_failure, error_with_failure=, extended, extended_into, fail, format_bytes, format_date, format_error, format_with_bang, get_terminal_environment, git, has_git?, home_directory, hprint, hputs, included, included_into, json_decode, json_encode, launchy, line_formatter, longest, output, output_with_arrow, output_with_bang, quantify, redisplay, retry_on_exception, run_command, running_on_a_mac?, running_on_windows?, set_buffer, shell, spinner, status, string_distance, styled_array, styled_error, styled_hash, styled_header, suggestion, time_ago, truncate, with_tty

Methods included from Helpers::System

#browser_launcher, #command?, #osx?, #tmp_dir, #which, #windows?

Class Attribute Details

.configurationObject

Returns the value of attribute configuration.



10
11
12
# File 'lib/nimbu/auth.rb', line 10

def configuration
  @configuration
end

.credentialsObject

Returns the value of attribute credentials.



10
11
12
# File 'lib/nimbu/auth.rb', line 10

def credentials
  @credentials
end

Class Method Details

.admin_hostObject



55
56
57
# File 'lib/nimbu/auth.rb', line 55

def admin_host
  @admin_host ||= host.gsub(%r{https?://api\.}, '')
end

.api_hostObject



59
60
61
# File 'lib/nimbu/auth.rb', line 59

def api_host
  @api_host ||= host.gsub(%r{https?://}, '')
end

.ask_for_and_save_configurationObject



83
84
85
86
87
# File 'lib/nimbu/auth.rb', line 83

def ask_for_and_save_configuration
  @configuration = ask_for_configuration
  write_configuration
  @configuration
end

.ask_for_and_save_credentialsObject



296
297
298
299
300
301
302
303
304
305
306
307
# File 'lib/nimbu/auth.rb', line 296

def ask_for_and_save_credentials
  display "Please authenticate with #{admin_host}:"
  begin
    @credentials = ask_for_credentials
    write_credentials
    check
  rescue Exception => e
    delete_credentials
    raise e
  end
  @credentials
end

.ask_for_configurationObject



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/nimbu/auth.rb', line 98

def ask_for_configuration
  subdomain = nil
  sites = client.sites.list

  if sites.respond_to?(:any?) && sites.any?
    print_separator
    display "\nLet's first setup the configuration for this directory..."
    display "\nYou have access to following sites:\n"
    sites.each_with_index do |site, i|
      display " #{i + 1}) #{site.name.white.bold} => http://#{site.domain}"
    end
    site_number = 0
    retry_site = false
    while site_number < 1 || site_number > sites.length
      if retry_site
        print "\nPlease enter the number of your site (between 1-#{sites.length}): "
      else
        print "\nOn which site would you like to work? "
      end
      site_number_string = ask
      site_number = begin
        site_number_string.to_i
      rescue StandardError
        0
      end
      retry_site = true
    end
    puts ''
    site = sites[site_number - 1]
    display "Site chosen => #{site.name.white.bold} (http://#{site.domain})"
    subdomain = site.subdomain
    @site = subdomain
  else
    display "You don't have access to any Nimbu sites you can edit yet..."
    exit(1)
  end

  themes = client.themes(subdomain: subdomain).list
  current_theme = if themes.length > 1
                    theme_number = 0
                    retry_theme = false
                    while theme_number < 1 || theme_number > themes.length
                      if retry_theme
                        print "\nPlease enter the number of your theme (between 1-#{themes.length}): "
                      else
                        print "\nOn which theme would you like to work in this directory? "
                      end
                      theme_number_string = ask
                      theme_number = begin
                        theme_number_string.to_i
                      rescue StandardError
                        0
                      end
                      retry_theme = true
                    end
                    puts ''
                    display "Theme chosen => #{themes[theme_number - 1].name}"
                    themes[theme_number - 1]
                  else
                    themes.first
                  end
  @theme = current_theme.short
  print_separator

  { 'site' => subdomain, 'theme' => current_theme.short }
end

.ask_for_credentials(user = nil, password = nil, two_factor_code = nil) ⇒ Object



222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
# File 'lib/nimbu/auth.rb', line 222

def ask_for_credentials(user = nil, password = nil, two_factor_code = nil)
  unless user
    print 'Login: '
    user = ask
  end

  unless password
    print 'Password: '
    password = running_on_windows? ? ask_for_password_on_windows : ask_for_password
  end

  begin
    request_headers = {}
    request_headers['X-Nimbu-Two-Factor'] = two_factor_code.to_s.strip unless two_factor_code.nil?

    basic_client = Nimbu::Client.new(
      basic_auth: "#{user}:#{password}",
      endpoint: host,
      user_agent: user_agent,
      headers: request_headers
    )
    { user: user, token: basic_client.authenticate.token }
  rescue Exception => e
    if e.respond_to?(:http_status_code) && e.http_status_code == 401
      if e.message =~ /two factor authentication/
        print '2FA Token: '
        two_factor_code = ask
        ask_for_credentials(user, password, two_factor_code)
      else
        display " => could not login... please check your username and/or password!\n\n"
        nil
      end
    else
      display " => hmmmm... an error occurred: #{e}. \n\n\nIf this continues to occur, please report \nthe error at https://github.com/nimbu/nimbu/issues.\n\n"
      nil
    end
  end
end

.ask_for_passwordObject



284
285
286
287
288
289
290
291
292
293
294
# File 'lib/nimbu/auth.rb', line 284

def ask_for_password
  echo_off
  trap('INT') do
    echo_on
    exit
  end
  password = ask
  puts
  echo_on
  password
end

.ask_for_password_on_windowsObject



261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
# File 'lib/nimbu/auth.rb', line 261

def ask_for_password_on_windows
  require 'Win32API'
  char = nil
  password = ''

  while char = Win32API.new('msvcrt', '_getch', [], 'L').Call
    break if [10, 13].include?(char) # received carriage return or newline

    if [10, 13, 10, 13, 127, 8].include?(char) # backspace and delete
      password.slice!(-1, 1)
    else
      # windows might throw a -1 at us so make sure to handle RangeError
      begin
        (password << char.chr)
      rescue StandardError
        RangeError
      end
    end
  end
  puts
  password
end

.associate_key(key) ⇒ Object



50
51
52
53
# File 'lib/nimbu/ssh.rb', line 50

def associate_key(key)
  display "Uploading SSH public key #{key}"
  client.add_key(File.read(key).force_encoding('UTF-8'))
end

.associate_or_generate_ssh_keyObject



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/nimbu/ssh.rb', line 15

def associate_or_generate_ssh_key
  public_keys = Dir.glob("#{home_directory}/.ssh/*.pub").sort

  case public_keys.length
  when 0 then
    display "Could not find an existing public key."
    display "Would you like to generate one? [Yn] ", false
    unless ask.strip.downcase == "n"
      display "Generating new SSH public key."
      generate_ssh_key("id_rsa")
      associate_key("#{home_directory}/.ssh/id_rsa.pub")
    end
  when 1 then
    display "Found existing public key: #{public_keys.first}"
    associate_key(public_keys.first)
  else
    display "Found the following SSH public keys:"
    public_keys.each_with_index do |key, index|
      display "#{index+1}) #{File.basename(key)}"
    end
    display "Which would you like to use with your Nimbu account? ", false
    chosen = public_keys[ask.to_i-1] rescue error("Invalid choice")
    associate_key(chosen)
  end
end

.checkObject

just a stub; will raise if not authenticated



43
44
45
# File 'lib/nimbu/auth.rb', line 43

def check
  client.sites.list
end

.check_for_associated_ssh_keyObject



10
11
12
13
# File 'lib/nimbu/ssh.rb', line 10

def check_for_associated_ssh_key
  return unless client.keys.empty?
  associate_or_generate_ssh_key
end

.clientObject



19
20
21
22
23
# File 'lib/nimbu/auth.rb', line 19

def client
  @client ||= begin
    Nimbu::Client.new(oauth_token: token, endpoint: host, user_agent: user_agent, auto_pagination: true)
  end
end

.configuration_fileObject



89
90
91
# File 'lib/nimbu/auth.rb', line 89

def configuration_file
  "#{Nimbu.cli_options[:dir] || Dir.pwd}/nimbu.yml"
end

.default_hostObject



51
52
53
# File 'lib/nimbu/auth.rb', line 51

def default_host
  'https://api.nimbu.io'
end

.delete_configurationObject



93
94
95
96
# File 'lib/nimbu/auth.rb', line 93

def delete_configuration
  FileUtils.rm_f(configuration_file)
  @host = nil
end

.delete_credentialsObject



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

def delete_credentials
  n = Netrc.read
  n.delete(api_host)
  n.save
  @client = nil
  @credentials = nil
end

.echo_offObject



210
211
212
213
214
# File 'lib/nimbu/auth.rb', line 210

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

.echo_onObject



216
217
218
219
220
# File 'lib/nimbu/auth.rb', line 216

def echo_on
  with_tty do
    system 'stty echo'
  end
end

.generate_ssh_key(keyfile) ⇒ Object



41
42
43
44
45
46
47
48
# File 'lib/nimbu/ssh.rb', line 41

def generate_ssh_key(keyfile)
  ssh_dir = File.join(home_directory, ".ssh")
  unless File.exists?(ssh_dir)
    FileUtils.mkdir_p ssh_dir
    File.chmod(0700, ssh_dir)
  end
  `ssh-keygen -t rsa -N "" -f \"#{home_directory}/.ssh/#{keyfile}\" 2>&1`
end

.get_configurationObject



79
80
81
# File 'lib/nimbu/auth.rb', line 79

def get_configuration
  @configuration ||= (read_configuration || ask_for_and_save_configuration)
end

.get_credentialsObject

:nodoc:



185
186
187
188
# File 'lib/nimbu/auth.rb', line 185

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

.get_nimbu_siteObject



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

def get_nimbu_site
  get_configuration['site']
end

.get_nimbu_themeObject



75
76
77
# File 'lib/nimbu/auth.rb', line 75

def get_nimbu_theme
  get_configuration['theme'] || 'default-theme'
end

.hostObject



47
48
49
# File 'lib/nimbu/auth.rb', line 47

def host
  ENV['NIMBU_HOST'] || 'https://api.nimbu.io'
end

.invalid_access!Object



321
322
323
# File 'lib/nimbu/auth.rb', line 321

def invalid_access!
  puts invalid_access_message.bold.red
end

.invalid_access_messageObject



325
326
327
328
# File 'lib/nimbu/auth.rb', line 325

def invalid_access_message
  "Error! You do not have access to #{Nimbu::Auth.site}.#{Nimbu::Auth.admin_host}! " +
    'Please check your site id or request access to your site owner.'
end

.loginObject



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

def 
  delete_credentials
  get_credentials
end

.logoutObject



34
35
36
# File 'lib/nimbu/auth.rb', line 34

def logout
  delete_credentials
end


315
316
317
318
319
# File 'lib/nimbu/auth.rb', line 315

def print_separator
  print "\n"
  60.times { print '#' }
  print "\n"
end

.read_configurationObject



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

def read_configuration
  existing_config = YAML.load(File.open(configuration_file)) if File.exist?(configuration_file)
  existing_config if existing_config && !existing_config['site'].nil?
end

.read_credentialsObject



198
199
200
201
202
# File 'lib/nimbu/auth.rb', line 198

def read_credentials
  n = Netrc.read
  user, token = n[api_host]
  { user: user, token: token } if user && token
end

.reauthorizeObject



177
178
179
# File 'lib/nimbu/auth.rb', line 177

def reauthorize
  @credentials = ask_for_and_save_credentials
end

.retry_login?Boolean

Returns:

  • (Boolean)


309
310
311
312
313
# File 'lib/nimbu/auth.rb', line 309

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

.simulator_idObject



12
13
14
15
16
17
# File 'lib/nimbu/auth.rb', line 12

def simulator_id
  return @simulator_id if defined? @simulator_id

  ranges = [('a'..'z'), ('A'..'Z'), (0..9)].map { |i| i.to_a }.flatten
  @simulator_id ||= (1..40).map { ranges[rand(ranges.length)] }.join
end

.siteObject



63
64
65
# File 'lib/nimbu/auth.rb', line 63

def site
  @site ||= ENV['NIMBU_SITE'] || get_nimbu_site
end

.themeObject



67
68
69
# File 'lib/nimbu/auth.rb', line 67

def theme
  @theme ||= ENV['NIMBU_THEME'] || get_nimbu_theme
end

.tokenObject

:nodoc:



181
182
183
# File 'lib/nimbu/auth.rb', line 181

def token # :nodoc:
  ENV['NIMBU_API_KEY'] || get_credentials
end

.user_agentObject



25
26
27
# File 'lib/nimbu/auth.rb', line 25

def user_agent
  "nimbu-toolbelt/#{Nimbu::VERSION} (#{RUBY_PLATFORM}) ruby/#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}".freeze
end

.whoamiObject



38
39
40
# File 'lib/nimbu/auth.rb', line 38

def whoami
  client.users.me
end

.write_configurationObject



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

def write_configuration
  FileUtils.mkdir_p(File.dirname(configuration_file))
  File.open(configuration_file, 'w') { |credentials| credentials.puts(YAML.dump(configuration)) }
  FileUtils.chmod(0o700, File.dirname(configuration_file))
  FileUtils.chmod(0o600, configuration_file)
end

.write_credentialsObject



204
205
206
207
208
# File 'lib/nimbu/auth.rb', line 204

def write_credentials
  n = Netrc.read
  n[api_host] = @credentials[:user], @credentials[:token]
  n.save
end