Class: Pebbles::Auth

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

Class Attribute Summary collapse

Class Method Summary collapse

Methods included from Helpers

action, ask, confirm_command, create_git_remote, debug, debugging?, display, error, error_with_failure, error_with_failure=, flatten_hash, format_bytes, format_error, format_with_bang, git, has_git?, has_git_remote?, has_http_git_entry_in_netrc, home_directory, hputs, json_decode, launchy, line_formatter, longest, output_with_bang, running_on_a_mac?, running_on_windows?, styled_array, styled_error, styled_hash, styled_header, update_git_remote, with_tty

Class Attribute Details

.credentialsObject

Returns the value of attribute credentials.



11
12
13
# File 'lib/pebbles/auth.rb', line 11

def credentials
  @credentials
end

Class Method Details

.apiObject



13
14
15
16
17
18
# File 'lib/pebbles/auth.rb', line 13

def api
  @api ||= begin
    debug "Using API with key: #{password[0,6]}..."
    Pebbles::API.new(default_params.merge(:api_key => password))
  end
end

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



66
67
68
69
70
71
# File 'lib/pebbles/auth.rb', line 66

def api_key(user=get_credentials[0], password=get_credentials[1])
  @api ||= Pebbles::API.new(default_params)
  api_key = @api.(user, password).body["api_key"]
  @api = nil
  api_key
end

.ask_for_and_save_credentialsObject



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/pebbles/auth.rb', line 188

def ask_for_and_save_credentials
  @credentials = ask_for_credentials
  debug "Logged in as #{@credentials[0]} with key: #{@credentials[1][0,6]}..."
  write_credentials
  check
  @credentials
rescue Pebbles::API::Errors::Unauthorized => e
  delete_credentials
  display "Authentication failed."
  warn "WARNING: PEBBLES_API_KEY is set to an invalid key." if ENV['PEBBLES_API_KEY']
  retry if retry_login?
  exit 1
rescue => e
  delete_credentials
  raise e
end

.ask_for_credentialsObject



148
149
150
151
152
153
154
155
156
157
# File 'lib/pebbles/auth.rb', line 148

def ask_for_credentials
  puts "Enter your Pebblescape credentials."

  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_passwordObject



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

def ask_for_password
  begin
    echo_off
    password = ask
    puts
  ensure
    echo_on
  end
  return password
end

.ask_for_password_on_windowsObject



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/pebbles/auth.rb', line 159

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

.associate_key(key) ⇒ Object



255
256
257
258
259
260
261
262
263
# File 'lib/pebbles/auth.rb', line 255

def associate_key(key)
  action("Uploading SSH public key #{key}") do
    if File.exists?(key)
      api.post_key(File.read(key))
    else
      error("Could not upload SSH public key: key file '" + key + "' does not exist")
    end
  end
end

.associate_or_generate_ssh_keyObject



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/pebbles/auth.rb', line 205

def associate_or_generate_ssh_key
  unless File.exists?("#{home_directory}/.ssh/id_rsa.pub")
    display "Could not find an existing public key at ~/.ssh/id_rsa.pub"
    display "Would you like to generate one? [Yn] ", false
    unless ask.strip.downcase =~ /^n/
      display "Generating new SSH public key."
      generate_ssh_key("#{home_directory}/.ssh/id_rsa")
      associate_key("#{home_directory}/.ssh/id_rsa.pub")
      return
    end
  end

  chosen = ssh_prompt
  associate_key(chosen) if chosen
end

.base_host(host) ⇒ Object



271
272
273
274
275
# File 'lib/pebbles/auth.rb', line 271

def base_host(host)
  parts = URI.parse(full_host(host)).host.split(".")
  return parts.first if parts.size == 1
  parts[-2..-1].join(".")
end

.checkObject

just a stub; will raise if not authenticated



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

def check
  api.get_user
end

.default_hostObject



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

def default_host
  "pebblesinspace.com"
end

.delete_credentialsObject



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

def delete_credentials
  return 
  if netrc
    subdomains.each do |sub|
      netrc.delete("#{sub}.#{host}")
    end
    netrc.save
  end
  @api, @credentials = nil, nil
end

.echo_offObject



136
137
138
139
140
# File 'lib/pebbles/auth.rb', line 136

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

.echo_onObject



142
143
144
145
146
# File 'lib/pebbles/auth.rb', line 142

def echo_on
  with_tty do
    system "stty echo"
  end
end

.full_host(host) ⇒ Object



277
278
279
280
# File 'lib/pebbles/auth.rb', line 277

def full_host(host)
  scheme = debugging? ? 'http' : 'https'
  (host =~ /^http/) ? host : "#{scheme}://api.#{host}"
end

.generate_ssh_key(keyfile) ⇒ Object



246
247
248
249
250
251
252
253
# File 'lib/pebbles/auth.rb', line 246

def generate_ssh_key(keyfile)
  ssh_dir = File.dirname(keyfile)
  FileUtils.mkdir_p ssh_dir, :mode => 0700
  output = `ssh-keygen -t rsa -N "" -f \"#{keyfile}\" 2>&1`
  if ! $?.success?
    error("Could not generate key: #{output}")
  end
end

.get_credentialsObject

:nodoc:



73
74
75
# File 'lib/pebbles/auth.rb', line 73

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

.git_hostObject



42
43
44
# File 'lib/pebbles/auth.rb', line 42

def git_host
  ENV['PEBBLES_GIT_HOST'] || host
end

.hostObject



46
47
48
# File 'lib/pebbles/auth.rb', line 46

def host
  ENV['PEBBLES_HOST'] || default_host
end

.http_git_hostObject



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

def http_git_host
  ENV['PEBBLES_HTTP_GIT_HOST'] || "git.#{host}"
end

.loginObject



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

def 
  delete_credentials
  get_credentials
end

.logoutObject



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

def logout
  delete_credentials
end

.netrcObject

:nodoc:



98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/pebbles/auth.rb', line 98

def netrc   # :nodoc:
  @netrc ||= begin
    File.exists?(netrc_path) && Netrc.read(netrc_path)
  rescue => error
    case error.message
    when /^Permission bits for/
      abort("#{error.message}.\nYou should run `chmod 0600 #{netrc_path}` so that your credentials are NOT accessible by others.")
    when /EACCES/
      error("Error reading #{netrc_path}\n#{error.message}\nMake sure this user can read/write this file.")
    else
      error("Error reading #{netrc_path}\n#{error.message}\nYou may need to delete this file and run `pebbles login` to recreate it.")
    end
  end
end

.netrc_pathObject



88
89
90
91
92
93
94
95
96
# File 'lib/pebbles/auth.rb', line 88

def netrc_path
  default = Netrc.default_path
  encrypted = default + ".gpg"
  if File.exists?(encrypted)
    encrypted
  else
    default
  end
end

.passwordObject

:nodoc:



62
63
64
# File 'lib/pebbles/auth.rb', line 62

def password    # :nodoc:
  get_credentials[1]
end

.read_credentialsObject



113
114
115
116
117
118
119
120
121
122
# File 'lib/pebbles/auth.rb', line 113

def read_credentials
  if ENV['PEBBLES_API_KEY']
    ['', ENV['PEBBLES_API_KEY']]
  else
    # read netrc credentials if they exist
    if netrc
      netrc["api.#{host}"]
    end
  end
end

.reauthorizeObject



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

def reauthorize
  @credentials = ask_for_and_save_credentials
end

.retry_login?Boolean

Returns:

  • (Boolean)


265
266
267
268
269
# File 'lib/pebbles/auth.rb', line 265

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

.ssh_promptObject



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

def ssh_prompt
  public_keys = Dir.glob("#{home_directory}/.ssh/*.pub").sort
  case public_keys.length
  when 0
    error("No SSH keys found")
    return nil
  when 1
    display "Found an SSH public key at #{public_keys.first}"
    display "Would you like to upload it to Pebblescape? [Yn] ", false
    return ask.strip.downcase =~ /^n/ ? nil : 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 Pebblescape account? ", false
    choice = ask.to_i - 1
    chosen = public_keys[choice]
    if choice == -1 || chosen.nil?
      error("Invalid choice")
    end
    return chosen
  end
end

.subdomainsObject



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

def subdomains
  %w(api git)
end

.userObject

:nodoc:



58
59
60
# File 'lib/pebbles/auth.rb', line 58

def user    # :nodoc:
  get_credentials[0]
end

.verify_host?(host) ⇒ Boolean

Returns:

  • (Boolean)


282
283
284
285
# File 'lib/pebbles/auth.rb', line 282

def verify_host?(host)
  return false if ENV["PEBBLES_SSL_VERIFY"] == "disable"
  base_host(host) == "pebblesinspace.com"
end

.write_credentialsObject



124
125
126
127
128
129
130
131
132
133
134
# File 'lib/pebbles/auth.rb', line 124

def write_credentials
  FileUtils.mkdir_p(File.dirname(netrc_path))
  FileUtils.touch(netrc_path)
  unless running_on_windows?
    FileUtils.chmod(0600, netrc_path)
  end
  subdomains.each do |sub|
    netrc["#{sub}.#{host}"] = self.credentials
  end
  netrc.save
end