nexus 1.1.0 → 1.2.0

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: 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