nexus 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b9afe169e757af4c376e9127b7880a1b8e427ffc
4
- data.tar.gz: ec412e696190f225462c3ab626cd9eaf53f23c8e
3
+ metadata.gz: e11879ab0b9f82568f91c8ce11f044da3956b7ff
4
+ data.tar.gz: bc935338806a858d17b87fc5834984bb10d2e64e
5
5
  SHA512:
6
- metadata.gz: 5faef784a2e11d149e20f731fe6d6ae302ae13471957cb22a81b66b528683c567dc5ca4adad5dc59eb05eb1516429412ad7fb78e99b0c9d061f69ee1c98b8fee
7
- data.tar.gz: 655818bb467f597bb8ea5665c023cfeb15c8196d44e05e30e196b7b3f3ccf78341e3a6020e20f1adce25639d4199153153060d76bba86a957b7e88484334c8ad
6
+ metadata.gz: dd857dc03ad489c39efd1a622868f9600398fc4f2721e581f89448d59b04023dbdf8fe3318894209f0e4a619a51fe960ff1e4923f38183056c9406f3abd2cf63
7
+ data.tar.gz: a0d1607d9297577d23af9b649629c460d176ca7e91b9f903b4d66d3b712cd7ec8abcb793ce34f2c7d0cca76ee9b8593b310ab038e56d44a620c4cf894aa63e3b
@@ -9,29 +9,29 @@ class Gem::AbstractCommand < Gem::Command
9
9
  def initialize( name, summary )
10
10
  super
11
11
 
12
- add_option( '-c', '--nexus-clear',
13
- 'Clears the nexus config' ) do |value, options|
14
- options[ :nexus_clear ] = value
12
+ add_option( '-r', '--repo KEY',
13
+ "pick the configuration under that key.\n can be used in conjuction with --clear-repo and the upload itself." ) do |value, options|
14
+ options[ :nexus_repo ] = value
15
15
  end
16
16
 
17
- add_option( '--nexus-config FILE',
18
- 'File location of nexus config' ) do |value, options|
19
- options[ :nexus_config ] = File.expand_path( value )
17
+ add_option( '-c', '--clear-repo',
18
+ 'Clears the nexus config for the given repo or the default repo' ) do |value, options|
19
+ options[ :nexus_clear ] = value
20
20
  end
21
21
 
22
- add_option( '--repo KEY',
23
- 'pick the config under that key' ) do |value, options|
24
- options[ :nexus_repo ] = value
22
+ # backward compatibility
23
+ add_option( '--nexus-clear', 'DEPRECATED' ) do |value, options|
24
+ options[ :nexus_clear ] = value
25
25
  end
26
26
 
27
- add_option( '--secrets FILE',
28
- 'use and store secrets in the given instead of local config file. file location will be stored in the local config file.' ) do |value, options|
29
- options[ :nexus_secrets ] = File.expand_path( value )
27
+ add_option( '--nexus-config FILE',
28
+ "File location of nexus config to use.\n default #{Nexus::Config.default_file}" ) do |value, options|
29
+ options[ :nexus_config ] = File.expand_path( value )
30
30
  end
31
31
  end
32
32
 
33
33
  def url
34
- url = config[ :url ]
34
+ url = config.url
35
35
  # no leading slash
36
36
  url.sub!(/\/$/,'') if url
37
37
  url
@@ -43,7 +43,7 @@ class Gem::AbstractCommand < Gem::Command
43
43
  url = ask("URL: ")
44
44
 
45
45
  if URI.parse( "#{url}" ).host != nil
46
- config[ :url ] = url
46
+ config.url = url
47
47
 
48
48
  say 'The Nexus URL has been stored in ~/.gem/nexus'
49
49
  else
@@ -52,9 +52,27 @@ class Gem::AbstractCommand < Gem::Command
52
52
  end
53
53
 
54
54
  def setup
55
- configure_url if !config.key?( :url ) || options[:nexus_clear]
55
+ prompt_encryption if config.encrypted?
56
+ configure_url if config.url.nil? || options[ :nexus_clear ]
56
57
  use_proxy!( url ) if http_proxy( url )
57
- sign_in if !config.key?( :authorization ) || options[:nexus_clear]
58
+ if( authorization.nil? ||
59
+ config.always_prompt? ||
60
+ options[:nexus_clear] )
61
+ sign_in
62
+ end
63
+ end
64
+
65
+ def prompt_encryption
66
+ password = ask_for_password( "Enter your Nexus encryption credentials (no prompt)" )
67
+
68
+ # recreate config with password
69
+ config.password = password
70
+
71
+ # if options[ :nexus_encrypt ] && !config.encrypted?
72
+ # config.encrypt_credentials
73
+ # elsif options[ :nexus_encrypt ] == false && config.encrypted?
74
+ # config.decrypt_credentials
75
+ # end
58
76
  end
59
77
 
60
78
  def sign_in
@@ -64,29 +82,32 @@ class Gem::AbstractCommand < Gem::Command
64
82
 
65
83
  # mimic strict_encode64 which is not there on ruby1.8
66
84
  token = "#{username}:#{password}"
67
- if token != ':'
68
- config[ :authorization ] =
69
- "Basic #{Base64.encode64(username + ':' + password).gsub(/\s+/, '')}"
70
- else
71
- config[ :authorization ] = nil
85
+ auth = "Basic #{Base64.encode64(token).gsub(/\s+/, '')}"
86
+ @authorization = token == ':' ? nil : auth
87
+
88
+ unless config.always_prompt?
89
+ config.authorization = @authorization
90
+ if @authorization
91
+ say "Your Nexus credentials has been stored in #{config}"
92
+ else
93
+ say "Your Nexus credentials has been deleted from #{config}"
94
+ end
72
95
  end
73
-
74
- say "Your Nexus credentials has been stored in ~/.gem/nexus"
75
96
  end
76
97
 
77
- def this_config
78
- Nexus::Config.new( options[ :nexus_repo ],
79
- options[ :nexus_config ],
80
- options[ :nexus_secrets ] )
98
+ def this_config( pass = nil )
99
+ Nexus::Config.new( options[ :nexus_config ],
100
+ options[ :nexus_repo ] )
81
101
  end
82
102
  private :this_config
83
103
 
84
- def config
104
+ def config( pass = nil )
105
+ @config = this_config( pass ) if pass
85
106
  @config ||= this_config
86
107
  end
87
108
 
88
109
  def authorization
89
- config[ :authorization ]
110
+ @authorization || config.authorization
90
111
  end
91
112
 
92
113
  def make_request(method, path)
@@ -125,13 +146,15 @@ class Gem::AbstractCommand < Gem::Command
125
146
 
126
147
  if Gem.configuration.verbose.to_s.to_i > 0
127
148
  warn "#{request.method} #{url.to_s}"
128
- if authorization
149
+ if config.authorization
129
150
  warn 'use authorization'
130
151
  else
131
152
  warn 'no authorization'
132
153
  end
133
-
134
- warn "use proxy at #{http.proxy_address}:#{http.proxy_port}" if http.proxy_address
154
+
155
+ if http.proxy_address
156
+ warn "use proxy at #{http.proxy_address}:#{http.proxy_port}"
157
+ end
135
158
  end
136
159
 
137
160
  http.request(request)
@@ -139,7 +162,10 @@ class Gem::AbstractCommand < Gem::Command
139
162
 
140
163
  def use_proxy!( url )
141
164
  proxy_uri = http_proxy( url )
142
- @proxy_class = Net::HTTP::Proxy(proxy_uri.host, proxy_uri.port, proxy_uri.user, proxy_uri.password)
165
+ @proxy_class = Net::HTTP::Proxy( proxy_uri.host,
166
+ proxy_uri.port,
167
+ proxy_uri.user,
168
+ proxy_uri.password )
143
169
  end
144
170
 
145
171
  def proxy_class
@@ -5,23 +5,100 @@ class Gem::Commands::NexusCommand < Gem::AbstractCommand
5
5
  end
6
6
 
7
7
  def arguments
8
- "GEM built gem to upload"
8
+ "GEM built gem to upload. some options do not require it."
9
9
  end
10
10
 
11
11
  def usage
12
12
  "#{program_name} GEM"
13
13
  end
14
14
 
15
+ def list_repos
16
+ puts
17
+ config.repos.each do |k,v|
18
+ puts "#{k}: #{v}"
19
+ end
20
+ puts
21
+ end
22
+ private :list_repos
23
+
15
24
  def initialize
16
25
  super 'nexus', description
17
26
  add_proxy_option
27
+
28
+ add_option( '--all-repos',
29
+ 'list all configured repos with their respective urls.' ) do |value, options|
30
+ options[ :nexus_all_repos ] = value
31
+ end
32
+
33
+ add_option( '--clear-all',
34
+ 'clears all credentials' ) do |value, options|
35
+ options[ :nexus_clear_all ] = value
36
+ end
37
+
38
+
39
+ add_option( '--secrets FILE',
40
+ 'move the credentials to the given secrets file.' ) do |value, options|
41
+ options[ :nexus_secrets ] = File.expand_path( value )
42
+ end
43
+
44
+ add_option( '--no-secrets',
45
+ 'move the credentials to the configuration file and delete the secrets file.' ) do |value, options|
46
+ options[ :nexus_secrets ] = false
47
+ end
48
+
49
+ # backward compatibility
50
+ add_option( '--password', 'DEPRECATED' ) do |value, options|
51
+ options[ :nexus_prompt_all ] = value
52
+ end
53
+
54
+ add_option( '--[no-]prompt',
55
+ 'always prompt for the credentials.' ) do |value, options|
56
+ options[ :nexus_prompt_all ] = value
57
+ end
58
+
59
+ add_option( '--[no-]encrypt',
60
+ 'encrypt/decrypt the credentials with a master password.' ) do |value, options|
61
+ options[ :nexus_encrypt ] = value
62
+ end
63
+
18
64
  end
19
65
 
20
66
  def execute
21
67
  name = get_one_gem_name rescue nil
22
- setup
23
- # if there is no gemname and no clear options then fail with send_gem
24
- if !name.nil? || !options[ :nexus_clear ]
68
+ if( name && ( options[ :nexus_all_repos ] != nil ||
69
+ options[ :nexus_clear_all ] != nil ||
70
+ options[ :nexus_prompt_all ] != nil ||
71
+ options[ :nexus_encrypt ] != nil ||
72
+ options[ :nexus_secrets ] != nil ) )
73
+ warn "given gemfile #{name} get ignored due to the options used"
74
+ end
75
+
76
+ if options[ :nexus_all_repos ]
77
+ list_repos
78
+ elsif options[ :nexus_prompt_all ]
79
+ if ask( "setup nexus to always prompt username/passwords and delete all current credentials ? (y/N)" ) == 'y'
80
+ config.always_prompt
81
+ end
82
+ elsif options[ :nexus_prompt_all ] == false
83
+ say( "setup nexus to store username/passwords" )
84
+ config.clear_always_prompt
85
+ elsif options[ :nexus_clear_all ]
86
+ if ask( "delete all current credentials ? (y/N)" ) == 'y'
87
+ config.clear_credentials
88
+ end
89
+ elsif options[ :nexus_encrypt ]
90
+ prompt_encryption
91
+ config.encrypt_credentials
92
+ elsif options[ :nexus_encrypt ] == false
93
+ prompt_encryption
94
+ config.decrypt_credentials
95
+ elsif options[ :nexus_secrets ] == false
96
+ config.new_secrets( nil )
97
+ elsif options[ :nexus_secrets ]
98
+ config.new_secrets( options[ :nexus_secrets ] )
99
+ else
100
+ setup
101
+ # if there is no gemname and no options which then fail with send_gem
25
102
  send_gem
26
103
  end
27
104
  end
@@ -0,0 +1,52 @@
1
+ require 'openssl'
2
+ require 'base64'
3
+
4
+ module Nexus
5
+ class Cipher
6
+
7
+ def initialize( pass, token = nil )
8
+ @token = Base64.strict_decode64( token ) if token
9
+ @token ||= OpenSSL::Random.random_bytes( 32 )
10
+
11
+ iter = 20000
12
+ key_len = 32
13
+ @key = OpenSSL::PKCS5.pbkdf2_hmac_sha1( pass,
14
+ @token,
15
+ iter,
16
+ key_len )
17
+ end
18
+
19
+ def cipher
20
+ @c ||= OpenSSL::Cipher::AES.new( 256, :CBC )
21
+ end
22
+ private :cipher
23
+
24
+ def token
25
+ Base64.strict_encode64( @token )
26
+ end
27
+
28
+ def iv
29
+ Base64.strict_encode64( @iv ) if @iv
30
+ end
31
+
32
+ def iv=( iv )
33
+ @iv = Base64.strict_decode64( iv )
34
+ end
35
+
36
+ def encrypt( data )
37
+ c = cipher
38
+ c.encrypt
39
+ c.key = @key
40
+ @iv = c.random_iv
41
+ Base64.strict_encode64( c.update( data ) + c.final )
42
+ end
43
+
44
+ def decrypt( data )
45
+ c = cipher
46
+ c.decrypt
47
+ c.key = @key
48
+ c.iv = @iv
49
+ c.update( Base64.strict_decode64( data ) ) + c.final
50
+ end
51
+ end
52
+ end
@@ -1,110 +1,197 @@
1
- require 'rubygems/local_remote_options'
2
- require 'net/http'
3
- require 'base64'
1
+ require 'nexus/cipher'
2
+ require 'nexus/config_file'
4
3
 
5
4
  module Nexus
6
5
  class Config
7
6
 
8
- class File
9
- def initialize( file, repo )
10
- if file.is_a?( String )
11
- @file = file
12
-
13
- if file && ::File.exists?( file )
14
- @all = YAML.load( ::File.read( file ) )
15
- end
16
- elsif file
17
- @file = file.instance_variable_get( '@file'.to_sym )
18
- @all = file.instance_variable_get( '@all'.to_sym )
19
- end
20
- @all ||= {}
7
+ def self.default_file
8
+ File.join( Gem.user_home, '.gem', 'nexus' )
9
+ end
21
10
 
22
- @data = ( @all[ repo ] ||= {} ) if repo
23
- @data ||= @all
24
- end
11
+ def initialize( file = nil, repo = nil )
12
+ @repo = repo
13
+ @conf = ConfigFile.new( file || self.class.default_file )
14
+ @secr = ConfigFile.new( @conf[ :secrets ] ) if @conf.key? :secrets
15
+ end
25
16
 
26
- def key?( key )
27
- @data.key? key
28
- end
17
+ private
29
18
 
30
- def []( key )
31
- @data[ key ]
19
+ def encrypt_or_decrypt_credentials
20
+ map = config.all
21
+ yield map if map[ :authorization ]
22
+ map.each do |k, v|
23
+ yield v if v.is_a?( Hash ) && v[ :authorization ]
32
24
  end
25
+ end
33
26
 
34
- def []=( key, value )
35
- if value
36
- @data[ key ] = value
37
- else
38
- @data.delete( key )
39
- end
40
- end
41
-
42
- def store
43
- if @file
44
- dirname = ::File.dirname( @file )
45
- Dir.mkdir( dirname ) unless ::File.exists?( dirname )
46
- new = !::File.exists?( @file )
47
-
48
- ::File.open( @file, 'w') do |f|
49
- f.write @all.to_yaml
50
- end
51
- if new
52
- ::File.chmod( 0100600, @file ) rescue nil
53
- end
54
- true
55
- else
56
- false
27
+ def move_credentials( from, to )
28
+ keys = [ :secrets, :token, :iv, :authorization ]
29
+ ([ nil ] + from.repos ).each do |repo|
30
+ keys.each do |k|
31
+ to[ k, repo ] = from[ k, repo ]
32
+ from[ k, repo ] = nil
57
33
  end
58
34
  end
59
35
  end
60
36
 
61
- def self.default_file
62
- ::File.join( Gem.user_home, '.gem', 'nexus' )
37
+ def config
38
+ @map ||= @secr ? @secr : @conf
39
+ end
40
+
41
+ def key?( key )
42
+ config.key?( key, @repo )
43
+ end
44
+
45
+ def []( key )
46
+ config[ key, @repo ]
47
+ end
48
+
49
+ def []=( key, value )
50
+ config[ key, @repo ] = value
51
+ end
52
+
53
+ public
54
+
55
+ def encrypted?
56
+ config.key?( :token )
57
+ end
58
+
59
+ def password=( pass )
60
+ @cipher = Cipher.new( pass, config[ :token ] )
61
+ end
62
+
63
+ def always_prompt?
64
+ @conf[ :always_prompt ]
63
65
  end
64
66
 
65
- def initialize( repo = nil, config = nil, secrets = nil )
66
- config ||= self.class.default_file
67
- conf = File.new( config, nil )
68
- if secrets
69
- conf[ :secrets ] = secrets
70
- conf.store
67
+ def clear_always_prompt
68
+ @conf.delete( :always_prompt )
69
+ @conf.store
70
+ end
71
+
72
+ def clear_credentials( store = true )
73
+ secrets = @conf[ :secrets ]
74
+ if secrets && !config.key?( :token )
75
+ FileUtils.rm_f( secrets )
76
+ @map = @conf
77
+ else
78
+ config.delete :iv, :authorization
71
79
  end
72
- @conf = File.new( conf, repo )
73
- @secr = File.new( secrets || conf[ :secrets ], repo )
80
+ @conf.delete( :secrets )
81
+ @conf.store if store
74
82
  end
75
83
 
76
- def key?( key )
77
- @conf.key?( key ) || @secr.key?( key )
84
+ def always_prompt
85
+ @conf[ :always_prompt, nil ] = true
86
+
87
+ config.delete( :token )
88
+
89
+ clear_credentials( false )
90
+
91
+ @conf.store
78
92
  end
79
93
 
80
- def []( key )
81
- if key == :authorization && @conf[ key ]
82
- copy_authorization
94
+ def decrypt_credentials
95
+ unless encrypted?
96
+ warn 'not encrypted - nothing to do'
97
+ return
83
98
  end
84
- @conf[ key ] || @secr[ key ]
99
+ encrypt_or_decrypt_credentials do |c|
100
+ @cipher.iv = c[ :iv ]
101
+ c[ :authorization ] = @cipher.decrypt( c[ :authorization ] )
102
+ c.delete( :iv )
103
+ end
104
+ config.all.delete( :token )
105
+ config.store
106
+ @cipher = nil
107
+ end
108
+
109
+ def encrypt_credentials
110
+ if encrypted?
111
+ warn 'already encrypted - nothing to do'
112
+ return
113
+ end
114
+ encrypt_or_decrypt_credentials do |c|
115
+ c[ :authorization ] = @cipher.encrypt( c[ :authorization ] )
116
+ c[ :iv ] = @cipher.iv
117
+ end
118
+ config.all[ :token ] = @cipher.token
119
+ config.store
85
120
  end
121
+
122
+ def new_secrets( new )
123
+ old = @conf.all[ :secrets ]
124
+ if old and new
125
+ FileUtils.mv( old, new )
126
+ end
127
+ if new
128
+ @secr = ConfigFile.new( new )
129
+ end
130
+
131
+ if new.nil? && old
132
+ @conf.merge!( @secr )
133
+ FileUtils.rm_f( old )
134
+ @secr = nil
135
+ end
136
+
137
+ if old.nil? and new
138
+ move_credentials( @conf, @secr )
86
139
 
87
- def copy_authorization
88
- @secr[ :authorization ] = @conf[ :authorization ]
89
- if @secr.store
90
- @conf[ :authorization ] = nil
91
- @conf.store
140
+ @secr.store
92
141
  end
142
+
143
+ # store the new location
144
+ @conf[ :secrets, nil ] = new
145
+ @conf.store
93
146
  end
94
- private :copy_authorization
95
147
 
96
- def []=( key, value )
97
- stored = false
98
- if key == :authorization
99
- @secr[ key ] = value
100
- stored = @secr.store
148
+ def repos
149
+ result = @conf.section( :url )
150
+ if url = result.delete( :url )
151
+ result[ 'DEFAULT' ] = url
152
+ end
153
+ result.keys.each do |key|
154
+ if key != 'DEFAULT'
155
+ result[ key ] = result[ key ][ :url ]
156
+ end
101
157
  end
158
+ result
159
+ end
102
160
 
103
- unless stored
104
- @conf[ key ] = value
105
- @conf.store
161
+ def authorization
162
+ auth = self[ :authorization ]
163
+ if @cipher && auth && self[ :iv ]
164
+ @cipher.iv = self[ :iv ]
165
+ @cipher.decrypt( auth )
166
+ elsif @cipher && auth
167
+ authorization = auth
168
+ else
169
+ auth
106
170
  end
107
171
  end
108
172
 
173
+ def authorization=( auth )
174
+ if @cipher && auth
175
+ self[ :authorization ] = @cipher.encrypt( auth )
176
+ self[ :iv ] = @cipher.iv
177
+ else
178
+ self[ :authorization ] = auth
179
+ end
180
+ config.store
181
+ auth
182
+ end
183
+
184
+ def url
185
+ @conf[ :url, @repo ]
186
+ end
187
+
188
+ def url=( u )
189
+ @conf[ :url, @repo ] = u
190
+ @conf.store
191
+ end
192
+
193
+ def to_s
194
+ config.file
195
+ end
109
196
  end
110
197
  end