nexus-debug 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c5e977b37cb2b84fdff288647f916aaf31d72e330fbb75219732cf40acef41b8
4
+ data.tar.gz: 65c9201977d7d1a661834015c1dd9d24aa125a8d3d5341ea418c5c144ef5dd2c
5
+ SHA512:
6
+ metadata.gz: 5dffd2d02171b34bad106eb0eed21fc4c4990802f91d5d6a67c00176caaf8d0cc418de995a4c65385871d8ec9e72a7d74aa4e24943da0ac775c9ec846cefa3f1
7
+ data.tar.gz: 3a5cfd62ff57b6c97d262b7abe43dab2b5366e71e1c378d6b98a783f06f7fe86e1b516e8eaf0a1c6cc63c6e18eb200a8543bf392230bcf630957411cb4164358
data/MIT-LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2009, Nick Quaranto
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ #-*- mode: ruby -*-
2
+
3
+ require 'rake'
4
+ require 'rake/testtask'
5
+ require 'rubygems/package_task'
6
+
7
+ task :default => [ :test, :package ]
8
+
9
+ Gem::PackageTask.new( Gem::Specification.load( 'nexus.gemspec' ) ) do
10
+ end
11
+
12
+ Rake::TestTask.new(:test) do |t|
13
+ t.libs << "test"
14
+ t.test_files = FileList['test/*_test.rb']
15
+ t.verbose = true
16
+ end
17
+
18
+ # vim: syntax=Ruby
data/bin/nbundle ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'bundler/monkey_patch'
4
+
5
+ load Gem.bin_path('bundler', 'bundle')
@@ -0,0 +1,225 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubygems/local_remote_options'
4
+ require 'net/http'
5
+ require 'base64'
6
+ require 'nexus/config'
7
+
8
+ module Gem
9
+ class AbstractCommand < Gem::Command
10
+ include Gem::LocalRemoteOptions
11
+
12
+ def initialize(name, summary)
13
+ super
14
+
15
+ add_option('-r', '--repo KEY',
16
+ "pick the configuration under that key.\n can be used in conjuction with --clear-repo and the upload itself.") do |value, options|
17
+ options[:nexus_repo] = value
18
+ end
19
+
20
+ add_option('-c', '--clear-repo',
21
+ 'Clears the nexus config for the given repo or the default repo') do |value, options|
22
+ options[:nexus_clear] = value
23
+ end
24
+
25
+ add_option('--url URL',
26
+ 'URL of the rubygems repository on a Nexus server') do |value, options|
27
+ options[:nexus_url] = value
28
+ end
29
+
30
+ add_option('--credential USER:PASS',
31
+ 'Enter your Nexus credentials in "Username:Password" format') do |value, options|
32
+ options[:nexus_credential] = value
33
+ end
34
+
35
+ add_option('--nexus-config FILE',
36
+ "File location of nexus config to use.\n default #{Nexus::Config.default_file}") do |value, options|
37
+ options[:nexus_config] = File.expand_path(value)
38
+ end
39
+
40
+ add_option('--ignore-ssl-errors',
41
+ 'No check certificate.') do |_value, options|
42
+ options[:ssl_verify_mode] = OpenSSL::SSL::VERIFY_NONE
43
+ end
44
+ end
45
+
46
+ def url
47
+ url = config.url
48
+ # no leading slash
49
+ url&.sub!(%r{/$}, '')
50
+ url
51
+ end
52
+
53
+ def configure_url
54
+ url =
55
+ if options[:nexus_url]
56
+ options[:nexus_url]
57
+ else
58
+ say 'Enter the URL of the rubygems repository on a Nexus server'
59
+ ask('URL: ')
60
+ end
61
+
62
+ if !URI.parse(url.to_s).host.nil?
63
+ config.url = url
64
+
65
+ say "The Nexus URL has been stored in #{config}"
66
+ else
67
+ raise 'no URL given'
68
+ end
69
+ end
70
+
71
+ def setup
72
+ prompt_encryption if config.encrypted?
73
+ configure_url if config.url.nil? || options[:nexus_clear]
74
+ use_proxy!(url) if http_proxy(url)
75
+ if authorization.nil? ||
76
+ config.always_prompt? ||
77
+ options[:nexus_clear]
78
+ sign_in
79
+ end
80
+ end
81
+
82
+ def prompt_encryption
83
+ password = ask_for_password('Enter your Nexus encryption credentials (no prompt)')
84
+
85
+ # recreate config with password
86
+ config.password = password
87
+ end
88
+
89
+ def sign_in
90
+ token =
91
+ if options[:nexus_credential]
92
+ options[:nexus_credential]
93
+ else
94
+ say 'Enter your Nexus credentials'
95
+ username = ask('Username: ')
96
+ password = ask_for_password('Password: ')
97
+ "#{username}:#{password}"
98
+ end
99
+
100
+ # mimic strict_encode64 which is not there on ruby1.8
101
+ auth = "Basic #{Base64.encode64(token).gsub(/\s+/, '')}"
102
+ @authorization = token == ':' ? nil : auth
103
+
104
+ return if config.always_prompt?
105
+
106
+ config.authorization = @authorization
107
+ if @authorization
108
+ say "Your Nexus credentials have been stored in #{config}"
109
+ else
110
+ say "Your Nexus credentials have been deleted from #{config}"
111
+ end
112
+ end
113
+
114
+ def this_config(_pass = nil)
115
+ Nexus::Config.new(options[:nexus_config],
116
+ options[:nexus_repo])
117
+ end
118
+
119
+ private :this_config
120
+
121
+ def config(pass = nil)
122
+ @config = this_config(pass) if pass
123
+ @config ||= this_config
124
+ end
125
+
126
+ def authorization
127
+ @authorization || config.authorization
128
+ end
129
+
130
+ def make_request(method, path)
131
+ require 'net/http'
132
+ require 'net/https'
133
+
134
+ url = URI.parse("#{self.url}/#{path}")
135
+
136
+ http = proxy_class.new(url.host, url.port)
137
+
138
+ if url.scheme == 'https'
139
+ http.use_ssl = true
140
+ http.verify_mode =
141
+ options[:ssl_verify_mode] || config.ssl_verify_mode || OpenSSL::SSL::VERIFY_PEER
142
+ end
143
+
144
+ # Because sometimes our gems are huge and our people are on vpns
145
+ http.read_timeout = 300
146
+
147
+ request_method =
148
+ case method
149
+ when :get
150
+ proxy_class::Get
151
+ when :post
152
+ proxy_class::Post
153
+ when :put
154
+ proxy_class::Put
155
+ when :delete
156
+ proxy_class::Delete
157
+ else
158
+ raise ArgumentError
159
+ end
160
+
161
+ request = request_method.new(url.path)
162
+ request.add_field 'User-Agent', 'Ruby' unless RUBY_VERSION =~ /^1.9/
163
+
164
+ yield request if block_given?
165
+
166
+ if Gem.configuration.verbose.to_s.to_i.positive?
167
+ warn "#{request.method} #{url}"
168
+ if config.authorization
169
+ warn 'use authorization'
170
+ else
171
+ warn 'no authorization'
172
+ end
173
+
174
+ warn "use proxy at #{http.proxy_address}:#{http.proxy_port}" if http.proxy_address
175
+ end
176
+
177
+ if Gem.configuration.verbose.to_s.to_i.positive?
178
+ say "http request to #{self.url}/#{path} for #{method}"
179
+ end
180
+ http.request(request)
181
+ end
182
+
183
+ def use_proxy!(url)
184
+ proxy_uri = http_proxy(url)
185
+ @proxy_class = Net::HTTP::Proxy(proxy_uri.host,
186
+ proxy_uri.port,
187
+ proxy_uri.user,
188
+ proxy_uri.password)
189
+ end
190
+
191
+ def proxy_class
192
+ @proxy_class || Net::HTTP
193
+ end
194
+
195
+ # @return [URI, nil] the HTTP-proxy as a URI if set; +nil+ otherwise
196
+ def http_proxy(url)
197
+ uri = begin
198
+ URI.parse(url)
199
+ rescue StandardError
200
+ nil
201
+ end
202
+ return nil if uri.nil?
203
+
204
+ no_proxy = ENV['no_proxy']
205
+ if (no_proxy || ENV['NO_PROXY']) && no_proxy.split(/, */).member?(uri.host)
206
+ # does not look on ip-adress ranges
207
+ return nil
208
+ end
209
+
210
+ key = uri.scheme == 'http' ? 'http_proxy' : 'https_proxy'
211
+ proxy = Gem.configuration[:http_proxy] || ENV[key] || ENV[key.upcase]
212
+ return nil if proxy.nil? || proxy == :no_proxy
213
+
214
+ URI.parse(proxy)
215
+ end
216
+
217
+ def ask_for_password(message)
218
+ system 'stty -echo'
219
+ password = ask(message)
220
+ system 'stty echo'
221
+ ui.say("\n")
222
+ password
223
+ end
224
+ end
225
+ end
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gem
4
+ module Commands
5
+ class NexusCommand < Gem::AbstractCommand
6
+ def description
7
+ 'Upload a gem up to Nexus server'
8
+ end
9
+
10
+ def arguments
11
+ 'GEM built gem to upload. some options do not require it.'
12
+ end
13
+
14
+ def usage
15
+ "#{program_name} GEM [GEM [...]]"
16
+ end
17
+
18
+ def list_repos
19
+ puts
20
+ config.repos.each do |k, v|
21
+ puts "#{k}: #{v}"
22
+ end
23
+ puts
24
+ end
25
+
26
+ private :list_repos
27
+
28
+ def initialize
29
+ super 'nexus', description
30
+ add_proxy_option
31
+
32
+ add_option('--all-repos',
33
+ 'list all configured repos with their respective urls.') do |value, options|
34
+ options[:nexus_all_repos] = value
35
+ end
36
+
37
+ add_option('--clear-all',
38
+ 'clears all credentials') do |value, options|
39
+ options[:nexus_clear_all] = value
40
+ end
41
+
42
+ add_option('--secrets FILE',
43
+ 'move the credentials to the given secrets file.') do |value, options|
44
+ options[:nexus_secrets] = File.expand_path(value)
45
+ end
46
+
47
+ add_option('--no-secrets',
48
+ 'move the credentials to the configuration file and delete the secrets file.') do |_value, options|
49
+ options[:nexus_secrets] = false
50
+ end
51
+
52
+ add_option('--[no-]prompt',
53
+ 'always prompt for the credentials. this is helpful to reset your username/password for a specific host.') do |value, options|
54
+ options[:nexus_prompt_all] = value
55
+ end
56
+
57
+ add_option('--[no-]encrypt',
58
+ 'encrypt/decrypt the credentials with a master password.') do |value, options|
59
+ options[:nexus_encrypt] = value
60
+ end
61
+ end
62
+
63
+ def execute
64
+ names = begin
65
+ get_all_gem_names
66
+ rescue StandardError
67
+ nil
68
+ end
69
+ if names && (!options[:nexus_all_repos].nil? ||
70
+ !options[:nexus_clear_all].nil? ||
71
+ !options[:nexus_prompt_all].nil? ||
72
+ !options[:nexus_encrypt].nil? ||
73
+ !options[:nexus_secrets].nil?)
74
+ warn "given gemfile(s) #{names.join(' ')} get ignored due to the options used"
75
+ end
76
+
77
+ if options[:nexus_all_repos]
78
+ list_repos
79
+ elsif options[:nexus_prompt_all]
80
+ if ask('setup nexus to always prompt username/passwords and delete all current credentials ? (y/N)') == 'y'
81
+ config.always_prompt
82
+ end
83
+ elsif options[:nexus_prompt_all] == false
84
+ say('setup nexus to store username/passwords')
85
+ config.clear_always_prompt
86
+ elsif options[:nexus_clear_all]
87
+ config.clear_credentials if ask('delete all current credentials ? (y/N)') == 'y'
88
+ elsif options[:nexus_encrypt]
89
+ prompt_encryption
90
+ config.encrypt_credentials
91
+ elsif options[:nexus_encrypt] == false
92
+ prompt_encryption
93
+ config.decrypt_credentials
94
+ elsif options[:nexus_secrets] == false
95
+ config.new_secrets(nil)
96
+ elsif options[:nexus_secrets]
97
+ config.new_secrets(options[:nexus_secrets])
98
+ else
99
+ setup
100
+ # if there is no gemname and no options which then fail with send_gem
101
+ send_gem
102
+ end
103
+ end
104
+
105
+ def send_gem
106
+ gems = get_all_gem_names
107
+
108
+ say "Uploading #{gems.size} gem#{'s' if gems.size != 1} to Nexus..."
109
+
110
+ gems.each do |path|
111
+ response = make_request(:put, "gems/#{File.basename(path)}") do |request|
112
+ request.body = Gem.read_binary(path)
113
+ request.add_field('Content-Length', request.body.size)
114
+ request.add_field('Content-Type', 'application/octet-stream')
115
+ request.add_field('Authorization', authorization.strip) if authorization
116
+ end
117
+
118
+ case response.code
119
+ when '400'
120
+ say 'something went wrong - maybe (re)deployment is not allowed'
121
+ when '401'
122
+ say 'Unauthorized'
123
+ when '500'
124
+ say 'something went wrong'
125
+ else
126
+ if Gem.configuration.verbose.to_s.to_i.positive?
127
+ say "body:\n\t`#{response.message}`\n"
128
+ end
129
+ say "#{response.message} #{path.split(%r{/}).last}"
130
+ end
131
+
132
+ exit 1 unless response.is_a? Net::HTTPSuccess
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,53 @@
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 = 20_000
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
+ @cipher ||= OpenSSL::Cipher.new('aes-256-cbc')
21
+ end
22
+
23
+ private :cipher
24
+
25
+ def token
26
+ Base64.strict_encode64(@token)
27
+ end
28
+
29
+ def iv
30
+ Base64.strict_encode64(@iv) if @iv
31
+ end
32
+
33
+ def iv=(iv)
34
+ @iv = Base64.strict_decode64(iv)
35
+ end
36
+
37
+ def encrypt(data)
38
+ c = cipher
39
+ c.encrypt
40
+ c.key = @key
41
+ @iv = c.random_iv
42
+ Base64.strict_encode64(c.update(data) + c.final)
43
+ end
44
+
45
+ def decrypt(data)
46
+ c = cipher
47
+ c.decrypt
48
+ c.key = @key
49
+ c.iv = @iv
50
+ c.update(Base64.strict_decode64(data)) + c.final
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,195 @@
1
+ # frozen_string_literal: true
2
+ require 'nexus/cipher'
3
+ require 'nexus/config_file'
4
+
5
+ module Nexus
6
+ class Config
7
+
8
+ def self.default_file
9
+ File.join(Gem.user_home, '.gem', 'nexus')
10
+ end
11
+
12
+ def initialize(file = nil, repo = nil)
13
+ @repo = repo
14
+ @conf = ConfigFile.new(file || self.class.default_file)
15
+ @secr = ConfigFile.new(@conf[:secrets]) if @conf.key? :secrets
16
+ end
17
+
18
+ private
19
+
20
+ def encrypt_or_decrypt_credentials
21
+ map = config.all
22
+ yield map if map[:authorization]
23
+ map.each do |k, v|
24
+ yield v if v.is_a?(Hash) && v[:authorization]
25
+ end
26
+ end
27
+
28
+ def move_credentials(from, to)
29
+ keys = %i[secrets token iv authorization]
30
+ ([nil] + from.repos).each do |repo|
31
+ keys.each do |k|
32
+ to[k, repo] = from[k, repo]
33
+ from[k, repo] = nil
34
+ end
35
+ end
36
+ end
37
+
38
+ def config
39
+ @config ||= @secr || @conf
40
+ end
41
+
42
+ def key?(key)
43
+ config.key?(key, @repo)
44
+ end
45
+
46
+ def [](key)
47
+ config[key, @repo]
48
+ end
49
+
50
+ def []=(key, value)
51
+ config[key, @repo] = value
52
+ end
53
+
54
+ public
55
+
56
+ def encrypted?
57
+ config.key?(:token)
58
+ end
59
+
60
+ def password=(pass)
61
+ @cipher = Cipher.new(pass, config[:token])
62
+ end
63
+
64
+ def always_prompt?
65
+ @conf[:always_prompt]
66
+ end
67
+
68
+ def clear_always_prompt
69
+ @conf.delete(:always_prompt)
70
+ @conf.store
71
+ end
72
+
73
+ def clear_credentials(store = true)
74
+ secrets = @conf[:secrets]
75
+ if secrets && !config.key?(:token)
76
+ FileUtils.rm_f(secrets)
77
+ @map = @conf
78
+ else
79
+ config.delete :iv, :authorization
80
+ end
81
+ @conf.delete(:secrets)
82
+ @conf.store if store
83
+ end
84
+
85
+ def always_prompt
86
+ @conf[:always_prompt, nil] = true
87
+
88
+ config.delete(:token)
89
+
90
+ clear_credentials(false)
91
+
92
+ @conf.store
93
+ end
94
+
95
+ def decrypt_credentials
96
+ unless encrypted?
97
+ warn 'not encrypted - nothing to do'
98
+ return
99
+ end
100
+ encrypt_or_decrypt_credentials do |c|
101
+ @cipher.iv = c[:iv]
102
+ c[:authorization] = @cipher.decrypt(c[:authorization])
103
+ c.delete(:iv)
104
+ end
105
+ config.all.delete(:token)
106
+ config.store
107
+ @cipher = nil
108
+ end
109
+
110
+ def encrypt_credentials
111
+ if encrypted?
112
+ warn 'already encrypted - nothing to do'
113
+ return
114
+ end
115
+ encrypt_or_decrypt_credentials do |c|
116
+ c[:authorization] = @cipher.encrypt(c[:authorization])
117
+ c[:iv] = @cipher.iv
118
+ end
119
+ config.all[:token] = @cipher.token
120
+ config.store
121
+ end
122
+
123
+ def new_secrets(new)
124
+ old = @conf.all[:secrets]
125
+ FileUtils.mv(old, new) if old && new
126
+ @secr = ConfigFile.new(new) if new
127
+
128
+ if new.nil? && old
129
+ @conf.merge!(@secr)
130
+ FileUtils.rm_f(old)
131
+ @secr = nil
132
+ end
133
+
134
+ if old.nil? && new
135
+ move_credentials(@conf, @secr)
136
+
137
+ @secr.store
138
+ end
139
+
140
+ # store the new location
141
+ @conf[:secrets, nil] = new
142
+ @conf.store
143
+ end
144
+
145
+ def repos
146
+ result = @conf.section(:url)
147
+ url = result.delete(:url)
148
+ result['DEFAULT'] = url if url
149
+ result.each_key do |key|
150
+ result[key] = result[key][:url] if key != 'DEFAULT'
151
+ end
152
+ result
153
+ end
154
+
155
+ def authorization
156
+ auth = self[:authorization]
157
+ if @cipher && auth && self[:iv]
158
+ @cipher.iv = self[:iv]
159
+ @cipher.decrypt(auth)
160
+ elsif @cipher && auth
161
+ _authorization = auth
162
+ else
163
+ auth
164
+ end
165
+ end
166
+
167
+ def authorization=(auth)
168
+ if @cipher && auth
169
+ self[:authorization] = @cipher.encrypt(auth)
170
+ self[:iv] = @cipher.iv
171
+ else
172
+ self[:authorization] = auth
173
+ end
174
+ config.store
175
+ auth
176
+ end
177
+
178
+ def url
179
+ @conf[:url, @repo]
180
+ end
181
+
182
+ def url=(repo_url)
183
+ @conf[:url, @repo] = repo_url
184
+ @conf.store
185
+ end
186
+
187
+ def ssl_verify_mode
188
+ @conf[:ssl_verify_mode, @repo]
189
+ end
190
+
191
+ def to_s
192
+ config.file
193
+ end
194
+ end
195
+ end