aptible-cli 0.6.7 → 0.6.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7800411b1c246c299e73b915d9352b3f3ba2ce47
4
- data.tar.gz: 84b8ca4a819ba20f99887b10af6fb6921256fe80
3
+ metadata.gz: 1a3f6b5e9a9f9f325832789f7bbac423de2276c8
4
+ data.tar.gz: 328b06f1dcf9cb13c0df4f63f587fb4b79145a57
5
5
  SHA512:
6
- metadata.gz: 6b1d82455c6c2d2eea71366923ce913dc6a2678bc1aaef7222177c643d44088f14273aac3441bad4225044668c06f343aa52379cbb0241f1591f596437dc61cf
7
- data.tar.gz: 0bddfeb029c33710957829594e08635c5e42811c46fd0b45dfd06994eb1a7e13c2c1a50173d4f387fd01f6ab26275aed9508aa21d0e48647abd29fbffb473c94
6
+ metadata.gz: 8618af8eaf81ca409c8dfd680a00744f265a72da22d87767d679b93c6deadc6d8edf2951fcd488521d68a92ffdbb60f2969a995fb5ad0f3c30afc0ee2858ff48
7
+ data.tar.gz: 9da5825e8c2d8e2476ffce6268406f421cc357edd7fc8290801b1b342fe760351082f0f4864e782b113a0a1e8291b3226d815af3b50d23d0438cc0b97106e5d9
@@ -21,6 +21,7 @@ Gem::Specification.new do |spec|
21
21
  spec.require_paths = ['lib']
22
22
 
23
23
  spec.add_dependency 'aptible-api', '>= 0.9.5'
24
+ spec.add_dependency 'aptible-auth', '>= 0.11.3'
24
25
  spec.add_dependency 'thor', '>= 0.19.0'
25
26
  spec.add_dependency 'git'
26
27
  spec.add_dependency 'term-ansicolor'
@@ -21,6 +21,8 @@ require_relative 'subcommands/ssh'
21
21
 
22
22
  module Aptible
23
23
  module CLI
24
+ TOKEN_EXPIRY_WITH_OTP = 12 * 60 * 60 # 12 hours
25
+
24
26
  class Agent < Thor
25
27
  include Thor::Actions
26
28
 
@@ -48,15 +50,30 @@ module Aptible
48
50
  desc 'login', 'Log in to Aptible'
49
51
  option :email
50
52
  option :password
53
+ option :otp_token, desc: 'A token generated by your second-factor app'
51
54
  def login
52
55
  email = options[:email] || ask('Email: ')
53
56
  password = options[:password] || ask('Password: ', echo: false)
54
57
  puts ''
55
58
 
59
+ token_options = { email: email, password: password }
60
+
61
+ otp_token = options[:otp_token]
62
+ token_options[:otp_token] = otp_token if otp_token
63
+
56
64
  begin
57
- token = Aptible::Auth::Token.create(email: email, password: password)
58
- rescue OAuth2::Error
59
- raise Thor::Error, 'Could not authenticate with given credentials'
65
+ token_options[:expires_in] = TOKEN_EXPIRY_WITH_OTP \
66
+ if token_options[:otp_token]
67
+ token = Aptible::Auth::Token.create(token_options)
68
+ rescue OAuth2::Error => e
69
+ if e.code == 'otp_token_required'
70
+ token_options[:otp_token] = options[:otp_token] ||
71
+ ask('2FA Token: ')
72
+ retry
73
+ end
74
+
75
+ raise Thor::Error, 'Could not authenticate with given credentials: ' \
76
+ "#{e.code}"
60
77
  end
61
78
 
62
79
  save_token(token.access_token)
@@ -1,5 +1,5 @@
1
1
  module Aptible
2
2
  module CLI
3
- VERSION = '0.6.7'
3
+ VERSION = '0.6.8'
4
4
  end
5
5
  end
@@ -15,8 +15,12 @@ describe Aptible::CLI::Agent do
15
15
  describe '#login' do
16
16
  let(:token) { double('Aptible::Auth::Token') }
17
17
 
18
- before { OAuth2::Error.send :define_method, :initialize, -> {} }
18
+ before do
19
+ m = -> (code) { @code = code }
20
+ OAuth2::Error.send :define_method, :initialize, m
21
+ end
19
22
  before { token.stub(:access_token) { 'access_token' } }
23
+ before { subject.stub(:puts) {} }
20
24
 
21
25
  it 'should save a token to ~/.aptible/tokens' do
22
26
  Aptible::Auth::Token.stub(:create) { token }
@@ -25,10 +29,10 @@ describe Aptible::CLI::Agent do
25
29
  end
26
30
 
27
31
  it 'should raise an error if authentication fails' do
28
- Aptible::Auth::Token.stub(:create).and_raise OAuth2::Error
32
+ Aptible::Auth::Token.stub(:create).and_raise(OAuth2::Error, 'foo')
29
33
  expect do
30
34
  subject.login
31
- end.to raise_error 'Could not authenticate with given credentials'
35
+ end.to raise_error 'Could not authenticate with given credentials: foo'
32
36
  end
33
37
 
34
38
  it 'should use command line arguments if passed' do
@@ -37,5 +41,70 @@ describe Aptible::CLI::Agent do
37
41
  expect(Aptible::Auth::Token).to receive(:create).with(options) { token }
38
42
  subject.login
39
43
  end
44
+
45
+ context 'with OTP' do
46
+ let(:email) { 'foo@example.org' }
47
+ let(:password) { 'bar' }
48
+ let(:token) { '123456' }
49
+
50
+ context 'with options' do
51
+ before do
52
+ allow(subject).to receive(:options)
53
+ .and_return(email: email, password: password, otp_token: token)
54
+ end
55
+
56
+ it 'should authenticate without otp_token_required feedback' do
57
+ expect(Aptible::Auth::Token).to receive(:create)
58
+ .with(email: email, password: password, otp_token: token,
59
+ expires_in: Aptible::CLI::TOKEN_EXPIRY_WITH_OTP)
60
+ .once
61
+ .and_return(token)
62
+
63
+ subject.login
64
+ end
65
+ end
66
+
67
+ context 'with prompts' do
68
+ before do
69
+ [
70
+ [['Email: '], email],
71
+ [['Password: ', echo: false], password],
72
+ [['2FA Token: '], token]
73
+ ].each do |prompt, val|
74
+ expect(subject).to receive(:ask).with(*prompt).once.and_return(val)
75
+ end
76
+ end
77
+
78
+ it 'should prompt for an OTP token and use it' do
79
+ expect(Aptible::Auth::Token).to receive(:create)
80
+ .with(email: email, password: password)
81
+ .once
82
+ .and_raise(OAuth2::Error, 'otp_token_required')
83
+
84
+ expect(Aptible::Auth::Token).to receive(:create)
85
+ .with(email: email, password: password, otp_token: token,
86
+ expires_in: Aptible::CLI::TOKEN_EXPIRY_WITH_OTP)
87
+ .once
88
+ .and_return(token)
89
+
90
+ subject.login
91
+ end
92
+
93
+ it 'should not retry non-OTP errors.' do
94
+ expect(Aptible::Auth::Token).to receive(:create)
95
+ .with(email: email, password: password)
96
+ .once
97
+ .and_raise(OAuth2::Error, 'otp_token_required')
98
+
99
+ expect(Aptible::Auth::Token).to receive(:create)
100
+ .with(email: email, password: password, otp_token: token,
101
+ expires_in: Aptible::CLI::TOKEN_EXPIRY_WITH_OTP)
102
+ .once
103
+ .and_raise(OAuth2::Error, 'foo')
104
+
105
+ expect { subject.login }.to raise_error(/Could not authenticate/)
106
+ end
107
+ end
108
+ end
40
109
  end
41
110
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aptible-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.7
4
+ version: 0.6.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Frank Macreery
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-16 00:00:00.000000000 Z
11
+ date: 2016-05-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aptible-api
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 0.9.5
27
+ - !ruby/object:Gem::Dependency
28
+ name: aptible-auth
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.11.3
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 0.11.3
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: thor
29
43
  requirement: !ruby/object:Gem::Requirement