rubygems-update 3.4.10 → 3.4.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -0
  3. data/Manifest.txt +4 -0
  4. data/bundler/CHANGELOG.md +22 -0
  5. data/bundler/lib/bundler/build_metadata.rb +2 -2
  6. data/bundler/lib/bundler/definition.rb +9 -1
  7. data/bundler/lib/bundler/gem_version_promoter.rb +1 -1
  8. data/bundler/lib/bundler/lazy_specification.rb +1 -1
  9. data/bundler/lib/bundler/resolver/base.rb +1 -3
  10. data/bundler/lib/bundler/ruby_version.rb +1 -1
  11. data/bundler/lib/bundler/rubygems_ext.rb +5 -3
  12. data/bundler/lib/bundler/source/rubygems.rb +5 -8
  13. data/bundler/lib/bundler/spec_set.rb +2 -2
  14. data/bundler/lib/bundler/templates/newgem/bin/console.tt +0 -4
  15. data/bundler/lib/bundler/templates/newgem/ext/newgem/extconf-c.rb.tt +5 -0
  16. data/bundler/lib/bundler/templates/newgem/ext/newgem/newgem.c.tt +1 -1
  17. data/bundler/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb +2 -2
  18. data/bundler/lib/bundler/vendor/uri/lib/uri/version.rb +1 -1
  19. data/bundler/lib/bundler/version.rb +1 -1
  20. data/bundler/lib/bundler.rb +2 -2
  21. data/lib/rubygems/command_manager.rb +2 -2
  22. data/lib/rubygems/commands/owner_command.rb +4 -2
  23. data/lib/rubygems/exceptions.rb +10 -0
  24. data/lib/rubygems/gemcutter_utilities.rb +48 -6
  25. data/lib/rubygems/installer.rb +1 -1
  26. data/lib/rubygems/request_set.rb +2 -2
  27. data/lib/rubygems/specification.rb +3 -1
  28. data/lib/rubygems/stub_specification.rb +2 -1
  29. data/lib/rubygems/webauthn_listener/response.rb +161 -0
  30. data/lib/rubygems/webauthn_listener.rb +92 -0
  31. data/lib/rubygems.rb +1 -1
  32. data/rubygems-update.gemspec +1 -1
  33. data/test/rubygems/helper.rb +14 -0
  34. data/test/rubygems/test_bundled_ca.rb +1 -1
  35. data/test/rubygems/test_config.rb +1 -1
  36. data/test/rubygems/test_deprecate.rb +1 -1
  37. data/test/rubygems/test_exit.rb +1 -1
  38. data/test/rubygems/test_gem_commands_owner_command.rb +67 -0
  39. data/test/rubygems/test_gem_commands_push_command.rb +73 -0
  40. data/test/rubygems/test_gem_commands_yank_command.rb +84 -0
  41. data/test/rubygems/test_gem_ext_cargo_builder.rb +1 -0
  42. data/test/rubygems/test_gem_gemcutter_utilities.rb +72 -4
  43. data/test/rubygems/test_kernel.rb +1 -1
  44. data/test/rubygems/test_project_sanity.rb +32 -3
  45. data/test/rubygems/test_remote_fetch_error.rb +1 -1
  46. data/test/rubygems/test_webauthn_listener.rb +120 -0
  47. data/test/rubygems/test_webauthn_listener_response.rb +93 -0
  48. data/test/rubygems/utilities.rb +43 -3
  49. metadata +7 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 46744d5e03cb80dd7f581f3b934f104c88910b8442d3659b6d41d55777ab7f3a
4
- data.tar.gz: d7a2016d3d9af5bc86f92ec7bdb8ec8199d7de024a5fbe4b4a2cd0584bcbcf37
3
+ metadata.gz: 630124afddc18f8f7cb265b5de44eca7014d434e5ea8cd6371aefe67c70ea548
4
+ data.tar.gz: 5d6c95dc48dd7a700c98d000f02fc4fd24a6110ad5b4b584e80eb1d2f6a66d32
5
5
  SHA512:
6
- metadata.gz: 8416a6fc4327c003c86b8f05dcebcb0c073cb098ccf3d08661a121aedfca3d493b7b6440a605b5c1711f57b77ff230124d58492f99a58a4f926dd94992b4355c
7
- data.tar.gz: 67d782b6794632c09340a51b0f46cde1b82f70cc91aed59cb01961ed6ab57ee2c9a9043c08250c0c6889e2bab71faa6b6e6fa71de0e6cf5e85472ffade6ce73c
6
+ metadata.gz: 7b48042d92e123bdd1923b74d3b3453efed7ff69096995605267f0e17d23110c3c33a7e70e288554f5088ab8ea60ffd2264007acffabc19c56b8f1a55304e31a
7
+ data.tar.gz: d5d31837a2e3e200876195b3eb4ce91000ae809a867017fe8264301d045995321adc5f88a8ce30a2a1271fcb26a28d200b51b92359f841a0ed1ad309d506f18c
data/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ # 3.4.12 / 2023-04-11
2
+
3
+ ## Enhancements:
4
+
5
+ * [Experimental] Add WebAuthn Support to the CLI. Pull request
6
+ [#6560](https://github.com/rubygems/rubygems/pull/6560) by jenshenny
7
+ * Installs bundler 2.4.12 as a default gem.
8
+
9
+ # 3.4.11 / 2023-04-10
10
+
11
+ ## Enhancements:
12
+
13
+ * Installs bundler 2.4.11 as a default gem.
14
+
1
15
  # 3.4.10 / 2023-03-27
2
16
 
3
17
  ## Enhancements:
data/Manifest.txt CHANGED
@@ -540,6 +540,8 @@ lib/rubygems/util/list.rb
540
540
  lib/rubygems/validator.rb
541
541
  lib/rubygems/version.rb
542
542
  lib/rubygems/version_option.rb
543
+ lib/rubygems/webauthn_listener.rb
544
+ lib/rubygems/webauthn_listener/response.rb
543
545
  rubygems-update.gemspec
544
546
  setup.rb
545
547
  test/rubygems/alternate_cert.pem
@@ -753,6 +755,8 @@ test/rubygems/test_project_sanity.rb
753
755
  test/rubygems/test_remote_fetch_error.rb
754
756
  test/rubygems/test_require.rb
755
757
  test/rubygems/test_rubygems.rb
758
+ test/rubygems/test_webauthn_listener.rb
759
+ test/rubygems/test_webauthn_listener_response.rb
756
760
  test/rubygems/utilities.rb
757
761
  test/rubygems/wrong_key_cert.pem
758
762
  test/rubygems/wrong_key_cert_32.pem
data/bundler/CHANGELOG.md CHANGED
@@ -1,3 +1,25 @@
1
+ # 2.4.12 (April 11, 2023)
2
+
3
+ ## Enhancements:
4
+
5
+ - Remove reference to `pry` gem from generated `bin/console` file [#6515](https://github.com/rubygems/rubygems/pull/6515)
6
+
7
+ # 2.4.11 (April 10, 2023)
8
+
9
+ ## Security:
10
+
11
+ - Use URI-0.12.1 (safe against CVE-2023-28755 ReDoS vulnerability) [#6558](https://github.com/rubygems/rubygems/pull/6558)
12
+
13
+ ## Enhancements:
14
+
15
+ - Remove one fallback to full indexes on big gemfiles [#6578](https://github.com/rubygems/rubygems/pull/6578)
16
+ - Generate native gems with `-fvisibility=hidden` [#6541](https://github.com/rubygems/rubygems/pull/6541)
17
+
18
+ ## Bug fixes:
19
+
20
+ - Fix resolver hangs when dealing with an incomplete lockfile [#6552](https://github.com/rubygems/rubygems/pull/6552)
21
+ - Fix prereleases not being considered by gem version promoter when there's no lockfile [#6537](https://github.com/rubygems/rubygems/pull/6537)
22
+
1
23
  # 2.4.10 (March 27, 2023)
2
24
 
3
25
  ## Bug fixes:
@@ -4,8 +4,8 @@ module Bundler
4
4
  # Represents metadata from when the Bundler gem was built.
5
5
  module BuildMetadata
6
6
  # begin ivars
7
- @built_at = "2023-03-27".freeze
8
- @git_commit_sha = "7ffdec80d0".freeze
7
+ @built_at = "2023-04-11".freeze
8
+ @git_commit_sha = "e2cf278db1".freeze
9
9
  @release = true
10
10
  # end ivars
11
11
 
@@ -668,9 +668,17 @@ module Bundler
668
668
  def check_missing_lockfile_specs
669
669
  all_locked_specs = @locked_specs.map(&:name) << "bundler"
670
670
 
671
- @locked_specs.any? do |s|
671
+ missing = @locked_specs.select do |s|
672
672
  s.dependencies.any? {|dep| !all_locked_specs.include?(dep.name) }
673
673
  end
674
+
675
+ if missing.any?
676
+ @locked_specs.delete(missing)
677
+
678
+ true
679
+ else
680
+ false
681
+ end
674
682
  end
675
683
 
676
684
  def converge_paths
@@ -93,7 +93,7 @@ module Bundler
93
93
  locked_version = package.locked_version
94
94
 
95
95
  result = specs.sort do |a, b|
96
- unless locked_version && (package.prerelease_specified? || pre?)
96
+ unless package.prerelease_specified? || pre?
97
97
  a_pre = a.prerelease?
98
98
  b_pre = b.prerelease?
99
99
 
@@ -122,7 +122,7 @@ module Bundler
122
122
  end
123
123
 
124
124
  def to_s
125
- @__to_s ||= if platform == Gem::Platform::RUBY
125
+ @to_s ||= if platform == Gem::Platform::RUBY
126
126
  "#{name} (#{version})"
127
127
  else
128
128
  "#{name} (#{version}-#{platform})"
@@ -35,9 +35,7 @@ module Bundler
35
35
  end
36
36
 
37
37
  def delete(specs)
38
- specs.each do |spec|
39
- @base.delete(spec)
40
- end
38
+ @base.delete(specs)
41
39
  end
42
40
 
43
41
  def get_package(name)
@@ -107,7 +107,7 @@ module Bundler
107
107
  ruby_engine_version = RUBY_ENGINE == "ruby" ? ruby_version : RUBY_ENGINE_VERSION.dup
108
108
  patchlevel = RUBY_PATCHLEVEL.to_s
109
109
 
110
- @ruby_version ||= RubyVersion.new(ruby_version, patchlevel, ruby_engine, ruby_engine_version)
110
+ @system ||= RubyVersion.new(ruby_version, patchlevel, ruby_engine, ruby_engine_version)
111
111
  end
112
112
 
113
113
  private
@@ -66,7 +66,9 @@ module Gem
66
66
 
67
67
  alias_method :rg_extension_dir, :extension_dir
68
68
  def extension_dir
69
- @bundler_extension_dir ||= if source.respond_to?(:extension_dir_name)
69
+ # following instance variable is already used in original method
70
+ # and that is the reason to prefix it with bundler_ and add rubocop exception
71
+ @bundler_extension_dir ||= if source.respond_to?(:extension_dir_name) # rubocop:disable Naming/MemoizedInstanceVariableName
70
72
  unique_extension_dir = [source.extension_dir_name, File.basename(full_gem_path)].uniq.join("-")
71
73
  File.expand_path(File.join(extensions_dir, unique_extension_dir))
72
74
  else
@@ -203,9 +205,9 @@ module Gem
203
205
  protected
204
206
 
205
207
  def _requirements_sorted?
206
- return @_are_requirements_sorted if defined?(@_are_requirements_sorted)
208
+ return @_requirements_sorted if defined?(@_requirements_sorted)
207
209
  strings = as_list
208
- @_are_requirements_sorted = strings == strings.sort
210
+ @_requirements_sorted = strings == strings.sort
209
211
  end
210
212
 
211
213
  def _with_sorted_requirements
@@ -7,8 +7,6 @@ module Bundler
7
7
  class Rubygems < Source
8
8
  autoload :Remote, File.expand_path("rubygems/remote", __dir__)
9
9
 
10
- # Use the API when installing less than X gems
11
- API_REQUEST_LIMIT = 500
12
10
  # Ask for X gems per API request
13
11
  API_REQUEST_SIZE = 50
14
12
 
@@ -401,12 +399,11 @@ module Bundler
401
399
  # gather lists from non-api sites
402
400
  fetch_names(index_fetchers, nil, idx, false)
403
401
 
404
- # because ensuring we have all the gems we need involves downloading
405
- # the gemspecs of those gems, if the non-api sites contain more than
406
- # about 500 gems, we treat all sites as non-api for speed.
407
- allow_api = idx.size < API_REQUEST_LIMIT && dependency_names.size < API_REQUEST_LIMIT
408
- Bundler.ui.debug "Need to query more than #{API_REQUEST_LIMIT} gems." \
409
- " Downloading full index instead..." unless allow_api
402
+ # legacy multi-remote sources need special logic to figure out
403
+ # dependency names and that logic can be very costly if one remote
404
+ # uses the dependency API but others don't. So use full indexes
405
+ # consistently in that particular case.
406
+ allow_api = !multiple_remotes?
410
407
 
411
408
  fetch_names(api_fetchers, allow_api && dependency_names, idx, false)
412
409
  end
@@ -63,8 +63,8 @@ module Bundler
63
63
  @sorted = nil
64
64
  end
65
65
 
66
- def delete(spec)
67
- @specs.delete(spec)
66
+ def delete(specs)
67
+ specs.each {|spec| @specs.delete(spec) }
68
68
  @lookup = nil
69
69
  @sorted = nil
70
70
  end
@@ -7,9 +7,5 @@ require "<%= config[:namespaced_path] %>"
7
7
  # You can add fixtures and/or initialization code here to make experimenting
8
8
  # with your gem easier. You can also use a different console, if you like.
9
9
 
10
- # (If you use this, don't forget to add pry to your Gemfile!)
11
- # require "pry"
12
- # Pry.start
13
-
14
10
  require "irb"
15
11
  IRB.start(__FILE__)
@@ -2,4 +2,9 @@
2
2
 
3
3
  require "mkmf"
4
4
 
5
+ # Makes all symbols private by default to avoid unintended conflict
6
+ # with other gems. To explicitly export symbols you can use RUBY_FUNC_EXPORTED
7
+ # selectively, or entirely remove this flag.
8
+ append_cflags("-fvisibility=hidden")
9
+
5
10
  create_makefile(<%= config[:makefile_path].inspect %>)
@@ -2,7 +2,7 @@
2
2
 
3
3
  VALUE rb_m<%= config[:constant_array].join %>;
4
4
 
5
- void
5
+ RUBY_FUNC_EXPORTED void
6
6
  Init_<%= config[:underscored_name] %>(void)
7
7
  {
8
8
  rb_m<%= config[:constant_array].join %> = rb_define_module(<%= config[:constant_name].inspect %>);
@@ -2,8 +2,8 @@
2
2
  module Bundler::URI
3
3
  class RFC3986_Parser # :nodoc:
4
4
  # Bundler::URI defined in RFC3986
5
- RFC3986_URI = /\A(?<Bundler::URI>(?<scheme>[A-Za-z][+\-.0-9A-Za-z]*):(?<hier-part>\/\/(?<authority>(?:(?<userinfo>(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*)@)?(?<host>(?<IP-literal>\[(?:(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{1,4}?::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h+\.[!$&-.0-;=A-Z_a-z~]+))\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])*))(?::(?<port>\d*))?)(?<path-abempty>(?:\/(?<segment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*))*)|(?<path-absolute>\/(?:(?<segment-nz>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+)(?:\/\g<segment>)*)?)|(?<path-rootless>\g<segment-nz>(?:\/\g<segment>)*)|(?<path-empty>))(?:\?(?<query>[^#]*))?(?:\#(?<fragment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*))?)\z/
6
- RFC3986_relative_ref = /\A(?<relative-ref>(?<relative-part>\/\/(?<authority>(?:(?<userinfo>(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*)@)?(?<host>(?<IP-literal>\[(?:(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{1,4}?::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:){,1}\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h+\.[!$&-.0-;=A-Z_a-z~]+))\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])+))?(?::(?<port>\d*))?)(?<path-abempty>(?:\/(?<segment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*))*)|(?<path-absolute>\/(?:(?<segment-nz>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+)(?:\/\g<segment>)*)?)|(?<path-noscheme>(?<segment-nz-nc>(?:%\h\h|[!$&-.0-9;=@-Z_a-z~])+)(?:\/\g<segment>)*)|(?<path-empty>))(?:\?(?<query>[^#]*))?(?:\#(?<fragment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*))?)\z/
5
+ RFC3986_URI = /\A(?<Bundler::URI>(?<scheme>[A-Za-z][+\-.0-9A-Za-z]*+):(?<hier-part>\/\/(?<authority>(?:(?<userinfo>(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*+)@)?(?<host>(?<IP-literal>\[(?:(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{1,4}?::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h++\.[!$&-.0-;=A-Z_a-z~]++))\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])*+))(?::(?<port>\d*+))?)(?<path-abempty>(?:\/(?<segment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*+))*+)|(?<path-absolute>\/(?:(?<segment-nz>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])++)(?:\/\g<segment>)*+)?)|(?<path-rootless>\g<segment-nz>(?:\/\g<segment>)*+)|(?<path-empty>))(?:\?(?<query>[^#]*+))?(?:\#(?<fragment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*+))?)\z/
6
+ RFC3986_relative_ref = /\A(?<relative-ref>(?<relative-part>\/\/(?<authority>(?:(?<userinfo>(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*+)@)?(?<host>(?<IP-literal>\[(?:(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{1,4}?::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:){,1}\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h++\.[!$&-.0-;=A-Z_a-z~]++))\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])++))?(?::(?<port>\d*+))?)(?<path-abempty>(?:\/(?<segment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*+))*+)|(?<path-absolute>\/(?:(?<segment-nz>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])++)(?:\/\g<segment>)*+)?)|(?<path-noscheme>(?<segment-nz-nc>(?:%\h\h|[!$&-.0-9;=@-Z_a-z~])++)(?:\/\g<segment>)*+)|(?<path-empty>))(?:\?(?<query>[^#]*+))?(?:\#(?<fragment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*+))?)\z/
7
7
  attr_reader :regexp
8
8
 
9
9
  def initialize
@@ -1,6 +1,6 @@
1
1
  module Bundler::URI
2
2
  # :stopdoc:
3
- VERSION_CODE = '001200'.freeze
3
+ VERSION_CODE = '001201'.freeze
4
4
  VERSION = VERSION_CODE.scan(/../).collect{|n| n.to_i}.join('.').freeze
5
5
  # :startdoc:
6
6
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: false
2
2
 
3
3
  module Bundler
4
- VERSION = "2.4.10".freeze
4
+ VERSION = "2.4.12".freeze
5
5
 
6
6
  def self.bundler_major_version
7
7
  @bundler_major_version ||= VERSION.split(".").first.to_i
@@ -89,7 +89,7 @@ module Bundler
89
89
 
90
90
  class << self
91
91
  def configure
92
- @configured ||= configure_gem_home_and_path
92
+ @configure ||= configure_gem_home_and_path
93
93
  end
94
94
 
95
95
  def ui
@@ -581,7 +581,7 @@ EOF
581
581
  @bin_path = nil
582
582
  @bundler_major_version = nil
583
583
  @bundle_path = nil
584
- @configured = nil
584
+ @configure = nil
585
585
  @configured_bundle_path = nil
586
586
  @definition = nil
587
587
  @load = nil
@@ -83,7 +83,7 @@ class Gem::CommandManager
83
83
  # Return the authoritative instance of the command manager.
84
84
 
85
85
  def self.instance
86
- @command_manager ||= new
86
+ @instance ||= new
87
87
  end
88
88
 
89
89
  ##
@@ -98,7 +98,7 @@ class Gem::CommandManager
98
98
  # Reset the authoritative instance of the command manager.
99
99
 
100
100
  def self.reset
101
- @command_manager = nil
101
+ @instance = nil
102
102
  end
103
103
 
104
104
  ##
@@ -98,8 +98,10 @@ permission to.
98
98
  action = method == :delete ? "Removing" : "Adding"
99
99
 
100
100
  with_response response, "#{action} #{owner}"
101
- rescue
102
- # ignore
101
+ rescue Gem::WebauthnVerificationError => e
102
+ raise e
103
+ rescue StandardError
104
+ # ignore early exits to allow for completing the iteration of all owners
103
105
  end
104
106
  end
105
107
  end
@@ -213,6 +213,16 @@ class Gem::RubyVersionMismatch < Gem::Exception; end
213
213
 
214
214
  class Gem::VerificationError < Gem::Exception; end
215
215
 
216
+ ##
217
+ # Raised by Gem::WebauthnListener when an error occurs during security
218
+ # device verification.
219
+
220
+ class Gem::WebauthnVerificationError < Gem::Exception
221
+ def initialize(message)
222
+ super "Security device verification failed: #{message}"
223
+ end
224
+ end
225
+
216
226
  ##
217
227
  # Raised to indicate that a system exit should occur with the specified
218
228
  # exit_code
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  require_relative "remote_fetcher"
3
3
  require_relative "text"
4
+ require_relative "webauthn_listener"
4
5
 
5
6
  ##
6
7
  # Utility methods for using the RubyGems API.
@@ -82,7 +83,7 @@ module Gem::GemcutterUtilities
82
83
  #
83
84
  # If +allowed_push_host+ metadata is present, then it will only allow that host.
84
85
 
85
- def rubygems_api_request(method, path, host = nil, allowed_push_host = nil, scope: nil, &block)
86
+ def rubygems_api_request(method, path, host = nil, allowed_push_host = nil, scope: nil, credentials: {}, &block)
86
87
  require "net/http"
87
88
 
88
89
  self.host = host if host
@@ -105,7 +106,7 @@ module Gem::GemcutterUtilities
105
106
  response = request_with_otp(method, uri, &block)
106
107
 
107
108
  if mfa_unauthorized?(response)
108
- ask_otp
109
+ fetch_otp(credentials)
109
110
  response = request_with_otp(method, uri, &block)
110
111
  end
111
112
 
@@ -167,11 +168,12 @@ module Gem::GemcutterUtilities
167
168
  mfa_params = get_mfa_params(profile)
168
169
  all_params = scope_params.merge(mfa_params)
169
170
  warning = profile["warning"]
171
+ credentials = { email: email, password: password }
170
172
 
171
173
  say "#{warning}\n" if warning
172
174
 
173
175
  response = rubygems_api_request(:post, "api/v1/api_key",
174
- sign_in_host, scope: scope) do |request|
176
+ sign_in_host, credentials: credentials, scope: scope) do |request|
175
177
  request.basic_auth email, password
176
178
  request["OTP"] = otp if otp
177
179
  request.body = URI.encode_www_form({ name: key_name }.merge(all_params))
@@ -250,9 +252,49 @@ module Gem::GemcutterUtilities
250
252
  end
251
253
  end
252
254
 
253
- def ask_otp
254
- say "You have enabled multi-factor authentication. Please enter OTP code."
255
- options[:otp] = ask "Code: "
255
+ def fetch_otp(credentials)
256
+ options[:otp] = if webauthn_url = webauthn_verification_url(credentials)
257
+ wait_for_otp(webauthn_url)
258
+ else
259
+ say "You have enabled multi-factor authentication. Please enter OTP code."
260
+ ask "Code: "
261
+ end
262
+ end
263
+
264
+ def wait_for_otp(webauthn_url)
265
+ server = TCPServer.new 0
266
+ port = server.addr[1].to_s
267
+
268
+ thread = Thread.new do
269
+ Thread.current[:otp] = Gem::WebauthnListener.wait_for_otp_code(host, server)
270
+ rescue Gem::WebauthnVerificationError => e
271
+ Thread.current[:error] = e
272
+ end
273
+ thread.abort_on_exception = true
274
+ thread.report_on_exception = false
275
+
276
+ url_with_port = "#{webauthn_url}?port=#{port}"
277
+ say "You have enabled multi-factor authentication. Please visit #{url_with_port} to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin command with the `--otp [your_code]` option."
278
+
279
+ thread.join
280
+ if error = thread[:error]
281
+ alert_error error.message
282
+ terminate_interaction(1)
283
+ end
284
+
285
+ say "You are verified with a security device. You may close the browser window."
286
+ thread[:otp]
287
+ end
288
+
289
+ def webauthn_verification_url(credentials)
290
+ response = rubygems_api_request(:post, "api/v1/webauthn_verification") do |request|
291
+ if credentials.empty?
292
+ request.add_field "Authorization", api_key
293
+ else
294
+ request.basic_auth credentials[:email], credentials[:password]
295
+ end
296
+ end
297
+ response.is_a?(Net::HTTPSuccess) ? response.body : nil
256
298
  end
257
299
 
258
300
  def pretty_host(host)
@@ -388,7 +388,7 @@ class Gem::Installer
388
388
  # we'll be installing into.
389
389
 
390
390
  def installed_specs
391
- @specs ||= begin
391
+ @installed_specs ||= begin
392
392
  specs = []
393
393
 
394
394
  Gem::Util.glob_files_in_dir("*.gemspec", File.join(gem_home, "specifications")).each do |path|
@@ -107,7 +107,7 @@ class Gem::RequestSet
107
107
  @requests = []
108
108
  @sets = []
109
109
  @soft_missing = false
110
- @sorted = nil
110
+ @sorted_requests = nil
111
111
  @specs = nil
112
112
  @vendor_set = nil
113
113
  @source_set = nil
@@ -424,7 +424,7 @@ class Gem::RequestSet
424
424
  end
425
425
 
426
426
  def sorted_requests
427
- @sorted ||= strongly_connected_components.flatten
427
+ @sorted_requests ||= strongly_connected_components.flatten
428
428
  end
429
429
 
430
430
  def specs
@@ -2233,7 +2233,7 @@ class Gem::Specification < Gem::BasicSpecification
2233
2233
  # The platform this gem runs on. See Gem::Platform for details.
2234
2234
 
2235
2235
  def platform
2236
- @new_platform ||= Gem::Platform::RUBY
2236
+ @new_platform ||= Gem::Platform::RUBY # rubocop:disable Naming/MemoizedInstanceVariableName
2237
2237
  end
2238
2238
 
2239
2239
  def pretty_print(q) # :nodoc:
@@ -2712,6 +2712,8 @@ class Gem::Specification < Gem::BasicSpecification
2712
2712
  end
2713
2713
 
2714
2714
  @installed_by_version ||= nil
2715
+
2716
+ nil
2715
2717
  end
2716
2718
 
2717
2719
  def flatten_require_paths # :nodoc:
@@ -183,7 +183,7 @@ class Gem::StubSpecification < Gem::BasicSpecification
183
183
  ##
184
184
  # The full Gem::Specification for this gem, loaded from evalling its gemspec
185
185
 
186
- def to_spec
186
+ def spec
187
187
  @spec ||= if @data
188
188
  loaded = Gem.loaded_specs[name]
189
189
  loaded if loaded && loaded.version == version
@@ -191,6 +191,7 @@ class Gem::StubSpecification < Gem::BasicSpecification
191
191
 
192
192
  @spec ||= Gem::Specification.load(loaded_from)
193
193
  end
194
+ alias_method :to_spec, :spec
194
195
 
195
196
  ##
196
197
  # Is this StubSpecification valid? i.e. have we found a stub line, OR does