rubygems-update 3.4.17 → 3.4.19

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.
Files changed (376) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +24 -0
  3. data/Manifest.txt +7 -4
  4. data/POLICIES.md +2 -2
  5. data/bundler/CHANGELOG.md +30 -0
  6. data/bundler/lib/bundler/build_metadata.rb +2 -2
  7. data/bundler/lib/bundler/cli/binstubs.rb +1 -1
  8. data/bundler/lib/bundler/cli/info.rb +1 -1
  9. data/bundler/lib/bundler/cli/install.rb +1 -1
  10. data/bundler/lib/bundler/cli/outdated.rb +1 -1
  11. data/bundler/lib/bundler/cli/platform.rb +7 -5
  12. data/bundler/lib/bundler/definition.rb +25 -20
  13. data/bundler/lib/bundler/dsl.rb +1 -1
  14. data/bundler/lib/bundler/env.rb +1 -1
  15. data/bundler/lib/bundler/fetcher/compact_index.rb +3 -3
  16. data/bundler/lib/bundler/fetcher/downloader.rb +2 -0
  17. data/bundler/lib/bundler/fetcher/index.rb +1 -2
  18. data/bundler/lib/bundler/fetcher.rb +11 -1
  19. data/bundler/lib/bundler/friendly_errors.rb +1 -1
  20. data/bundler/lib/bundler/gem_helper.rb +3 -4
  21. data/bundler/lib/bundler/installer/parallel_installer.rb +1 -1
  22. data/bundler/lib/bundler/man/bundle-add.1 +1 -1
  23. data/bundler/lib/bundler/man/bundle-binstubs.1 +1 -1
  24. data/bundler/lib/bundler/man/bundle-cache.1 +1 -1
  25. data/bundler/lib/bundler/man/bundle-check.1 +1 -1
  26. data/bundler/lib/bundler/man/bundle-clean.1 +1 -1
  27. data/bundler/lib/bundler/man/bundle-config.1 +1 -1
  28. data/bundler/lib/bundler/man/bundle-console.1 +1 -1
  29. data/bundler/lib/bundler/man/bundle-doctor.1 +1 -1
  30. data/bundler/lib/bundler/man/bundle-exec.1 +1 -1
  31. data/bundler/lib/bundler/man/bundle-gem.1 +1 -1
  32. data/bundler/lib/bundler/man/bundle-help.1 +1 -1
  33. data/bundler/lib/bundler/man/bundle-info.1 +3 -3
  34. data/bundler/lib/bundler/man/bundle-info.1.ronn +3 -3
  35. data/bundler/lib/bundler/man/bundle-init.1 +1 -1
  36. data/bundler/lib/bundler/man/bundle-inject.1 +1 -1
  37. data/bundler/lib/bundler/man/bundle-install.1 +1 -1
  38. data/bundler/lib/bundler/man/bundle-list.1 +1 -1
  39. data/bundler/lib/bundler/man/bundle-lock.1 +1 -1
  40. data/bundler/lib/bundler/man/bundle-open.1 +1 -1
  41. data/bundler/lib/bundler/man/bundle-outdated.1 +13 -9
  42. data/bundler/lib/bundler/man/bundle-outdated.1.ronn +12 -9
  43. data/bundler/lib/bundler/man/bundle-platform.1 +1 -1
  44. data/bundler/lib/bundler/man/bundle-plugin.1 +1 -1
  45. data/bundler/lib/bundler/man/bundle-pristine.1 +1 -1
  46. data/bundler/lib/bundler/man/bundle-remove.1 +1 -1
  47. data/bundler/lib/bundler/man/bundle-show.1 +1 -1
  48. data/bundler/lib/bundler/man/bundle-update.1 +1 -1
  49. data/bundler/lib/bundler/man/bundle-version.1 +1 -1
  50. data/bundler/lib/bundler/man/bundle-viz.1 +1 -1
  51. data/bundler/lib/bundler/man/bundle.1 +1 -1
  52. data/bundler/lib/bundler/man/gemfile.5 +14 -1
  53. data/bundler/lib/bundler/man/gemfile.5.ronn +5 -0
  54. data/bundler/lib/bundler/plugin/index.rb +1 -1
  55. data/bundler/lib/bundler/ruby_dsl.rb +6 -0
  56. data/bundler/lib/bundler/ruby_version.rb +2 -2
  57. data/bundler/lib/bundler/rubygems_integration.rb +1 -1
  58. data/bundler/lib/bundler/source/git.rb +7 -0
  59. data/bundler/lib/bundler/source_list.rb +0 -4
  60. data/bundler/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt +1 -1
  61. data/bundler/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt +4 -4
  62. data/bundler/lib/bundler/ui/rg_proxy.rb +1 -1
  63. data/bundler/lib/bundler/vendor/fileutils/lib/fileutils.rb +1 -1
  64. data/bundler/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb +2 -2
  65. data/bundler/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb +1 -1
  66. data/bundler/lib/bundler/vendor/uri/lib/uri/version.rb +1 -1
  67. data/bundler/lib/bundler/version.rb +1 -1
  68. data/bundler/lib/bundler.rb +1 -1
  69. data/{bin → exe}/gem +2 -0
  70. data/{bin → exe}/update_rubygems +7 -5
  71. data/lib/rubygems/available_set.rb +1 -0
  72. data/lib/rubygems/basic_specification.rb +1 -0
  73. data/lib/rubygems/bundler_version_finder.rb +1 -1
  74. data/lib/rubygems/command.rb +1 -0
  75. data/lib/rubygems/command_manager.rb +1 -0
  76. data/lib/rubygems/commands/build_command.rb +1 -0
  77. data/lib/rubygems/commands/cert_command.rb +1 -0
  78. data/lib/rubygems/commands/check_command.rb +1 -0
  79. data/lib/rubygems/commands/cleanup_command.rb +1 -0
  80. data/lib/rubygems/commands/contents_command.rb +1 -0
  81. data/lib/rubygems/commands/dependency_command.rb +1 -0
  82. data/lib/rubygems/commands/environment_command.rb +1 -0
  83. data/lib/rubygems/commands/exec_command.rb +1 -0
  84. data/lib/rubygems/commands/fetch_command.rb +1 -0
  85. data/lib/rubygems/commands/generate_index_command.rb +1 -0
  86. data/lib/rubygems/commands/help_command.rb +1 -0
  87. data/lib/rubygems/commands/install_command.rb +1 -0
  88. data/lib/rubygems/commands/list_command.rb +1 -0
  89. data/lib/rubygems/commands/lock_command.rb +1 -0
  90. data/lib/rubygems/commands/mirror_command.rb +1 -0
  91. data/lib/rubygems/commands/open_command.rb +1 -0
  92. data/lib/rubygems/commands/outdated_command.rb +1 -0
  93. data/lib/rubygems/commands/owner_command.rb +1 -0
  94. data/lib/rubygems/commands/pristine_command.rb +1 -0
  95. data/lib/rubygems/commands/push_command.rb +1 -0
  96. data/lib/rubygems/commands/query_command.rb +1 -0
  97. data/lib/rubygems/commands/rdoc_command.rb +1 -0
  98. data/lib/rubygems/commands/search_command.rb +1 -0
  99. data/lib/rubygems/commands/server_command.rb +1 -0
  100. data/lib/rubygems/commands/setup_command.rb +2 -1
  101. data/lib/rubygems/commands/signin_command.rb +1 -0
  102. data/lib/rubygems/commands/signout_command.rb +1 -0
  103. data/lib/rubygems/commands/sources_command.rb +1 -0
  104. data/lib/rubygems/commands/specification_command.rb +1 -0
  105. data/lib/rubygems/commands/stale_command.rb +1 -0
  106. data/lib/rubygems/commands/uninstall_command.rb +1 -0
  107. data/lib/rubygems/commands/unpack_command.rb +1 -0
  108. data/lib/rubygems/commands/update_command.rb +1 -0
  109. data/lib/rubygems/commands/which_command.rb +1 -0
  110. data/lib/rubygems/commands/yank_command.rb +1 -0
  111. data/lib/rubygems/config_file.rb +1 -0
  112. data/lib/rubygems/core_ext/kernel_require.rb +1 -0
  113. data/lib/rubygems/core_ext/tcpsocket_init.rb +2 -0
  114. data/lib/rubygems/defaults.rb +1 -0
  115. data/lib/rubygems/dependency.rb +1 -0
  116. data/lib/rubygems/dependency_installer.rb +1 -0
  117. data/lib/rubygems/dependency_list.rb +1 -0
  118. data/lib/rubygems/deprecate.rb +1 -0
  119. data/lib/rubygems/doctor.rb +1 -0
  120. data/lib/rubygems/errors.rb +1 -0
  121. data/lib/rubygems/ext/build_error.rb +1 -0
  122. data/lib/rubygems/ext/builder.rb +1 -0
  123. data/lib/rubygems/ext/configure_builder.rb +1 -0
  124. data/lib/rubygems/ext/ext_conf_builder.rb +1 -0
  125. data/lib/rubygems/ext.rb +1 -0
  126. data/lib/rubygems/gem_runner.rb +1 -0
  127. data/lib/rubygems/gemcutter_utilities/webauthn_listener/response.rb +163 -0
  128. data/lib/rubygems/gemcutter_utilities/webauthn_listener.rb +105 -0
  129. data/lib/rubygems/gemcutter_utilities/webauthn_poller.rb +78 -0
  130. data/lib/rubygems/gemcutter_utilities.rb +30 -26
  131. data/lib/rubygems/indexer.rb +1 -0
  132. data/lib/rubygems/install_default_message.rb +1 -0
  133. data/lib/rubygems/install_message.rb +1 -0
  134. data/lib/rubygems/install_update_options.rb +1 -0
  135. data/lib/rubygems/installer.rb +1 -0
  136. data/lib/rubygems/local_remote_options.rb +1 -0
  137. data/lib/rubygems/mock_gem_ui.rb +1 -0
  138. data/lib/rubygems/name_tuple.rb +1 -0
  139. data/lib/rubygems/package/digest_io.rb +1 -0
  140. data/lib/rubygems/package/file_source.rb +1 -0
  141. data/lib/rubygems/package/io_source.rb +1 -0
  142. data/lib/rubygems/package/old.rb +1 -0
  143. data/lib/rubygems/package/source.rb +1 -0
  144. data/lib/rubygems/package/tar_header.rb +1 -0
  145. data/lib/rubygems/package/tar_reader/entry.rb +1 -0
  146. data/lib/rubygems/package/tar_reader.rb +1 -0
  147. data/lib/rubygems/package/tar_writer.rb +1 -0
  148. data/lib/rubygems/package.rb +2 -2
  149. data/lib/rubygems/package_task.rb +1 -0
  150. data/lib/rubygems/path_support.rb +1 -0
  151. data/lib/rubygems/platform.rb +1 -0
  152. data/lib/rubygems/psych_tree.rb +1 -0
  153. data/lib/rubygems/rdoc.rb +1 -0
  154. data/lib/rubygems/remote_fetcher.rb +1 -0
  155. data/lib/rubygems/request/http_pool.rb +1 -0
  156. data/lib/rubygems/request/https_pool.rb +1 -0
  157. data/lib/rubygems/request.rb +1 -0
  158. data/lib/rubygems/request_set/gem_dependency_api.rb +1 -0
  159. data/lib/rubygems/request_set/lockfile/parser.rb +2 -1
  160. data/lib/rubygems/request_set/lockfile/tokenizer.rb +2 -0
  161. data/lib/rubygems/request_set/lockfile.rb +1 -0
  162. data/lib/rubygems/request_set.rb +1 -0
  163. data/lib/rubygems/requirement.rb +1 -0
  164. data/lib/rubygems/resolver/activation_request.rb +1 -0
  165. data/lib/rubygems/resolver/api_set.rb +1 -0
  166. data/lib/rubygems/resolver/api_specification.rb +1 -0
  167. data/lib/rubygems/resolver/best_set.rb +1 -0
  168. data/lib/rubygems/resolver/composed_set.rb +1 -0
  169. data/lib/rubygems/resolver/conflict.rb +1 -0
  170. data/lib/rubygems/resolver/current_set.rb +1 -0
  171. data/lib/rubygems/resolver/dependency_request.rb +1 -0
  172. data/lib/rubygems/resolver/git_set.rb +1 -0
  173. data/lib/rubygems/resolver/git_specification.rb +1 -0
  174. data/lib/rubygems/resolver/index_set.rb +1 -0
  175. data/lib/rubygems/resolver/index_specification.rb +1 -0
  176. data/lib/rubygems/resolver/installed_specification.rb +1 -0
  177. data/lib/rubygems/resolver/installer_set.rb +1 -0
  178. data/lib/rubygems/resolver/local_specification.rb +1 -0
  179. data/lib/rubygems/resolver/lock_set.rb +1 -0
  180. data/lib/rubygems/resolver/lock_specification.rb +1 -0
  181. data/lib/rubygems/resolver/molinillo.rb +1 -0
  182. data/lib/rubygems/resolver/requirement_list.rb +1 -0
  183. data/lib/rubygems/resolver/set.rb +1 -0
  184. data/lib/rubygems/resolver/source_set.rb +2 -0
  185. data/lib/rubygems/resolver/spec_specification.rb +1 -0
  186. data/lib/rubygems/resolver/specification.rb +1 -0
  187. data/lib/rubygems/resolver/stats.rb +1 -0
  188. data/lib/rubygems/resolver/vendor_set.rb +1 -0
  189. data/lib/rubygems/resolver/vendor_specification.rb +1 -0
  190. data/lib/rubygems/resolver.rb +1 -0
  191. data/lib/rubygems/s3_uri_signer.rb +4 -2
  192. data/lib/rubygems/safe_yaml.rb +2 -0
  193. data/lib/rubygems/security/policies.rb +1 -0
  194. data/lib/rubygems/security/policy.rb +1 -0
  195. data/lib/rubygems/security/signer.rb +1 -0
  196. data/lib/rubygems/security/trust_dir.rb +1 -0
  197. data/lib/rubygems/security.rb +1 -0
  198. data/lib/rubygems/security_option.rb +1 -0
  199. data/lib/rubygems/source/installed.rb +1 -0
  200. data/lib/rubygems/source/local.rb +1 -0
  201. data/lib/rubygems/source/lock.rb +1 -0
  202. data/lib/rubygems/source/specific_file.rb +1 -0
  203. data/lib/rubygems/source/vendor.rb +1 -0
  204. data/lib/rubygems/spec_fetcher.rb +1 -0
  205. data/lib/rubygems/specification.rb +11 -3
  206. data/lib/rubygems/specification_policy.rb +2 -0
  207. data/lib/rubygems/stub_specification.rb +1 -0
  208. data/lib/rubygems/uninstaller.rb +1 -0
  209. data/lib/rubygems/user_interaction.rb +4 -2
  210. data/lib/rubygems/util/licenses.rb +1 -0
  211. data/lib/rubygems/util/list.rb +1 -0
  212. data/lib/rubygems/util.rb +1 -0
  213. data/lib/rubygems/validator.rb +1 -0
  214. data/lib/rubygems/version_option.rb +1 -0
  215. data/lib/rubygems.rb +3 -3
  216. data/rubygems-update.gemspec +5 -4
  217. data/setup.rb +1 -0
  218. data/test/rubygems/bad_rake.rb +1 -0
  219. data/test/rubygems/bundler_test_gem.rb +3 -1
  220. data/test/rubygems/fake_certlib/openssl.rb +1 -0
  221. data/test/rubygems/good_rake.rb +1 -0
  222. data/test/rubygems/helper.rb +1 -1
  223. data/test/rubygems/installer_test_case.rb +1 -0
  224. data/test/rubygems/multifactor_auth_utilities.rb +111 -0
  225. data/test/rubygems/package/tar_test_case.rb +1 -0
  226. data/test/rubygems/plugin/exception/rubygems_plugin.rb +1 -0
  227. data/test/rubygems/plugin/load/rubygems_plugin.rb +1 -0
  228. data/test/rubygems/plugin/standarderror/rubygems_plugin.rb +1 -0
  229. data/test/rubygems/rubygems/commands/crash_command.rb +1 -0
  230. data/test/rubygems/rubygems_plugin.rb +1 -0
  231. data/test/rubygems/simple_gem.rb +1 -0
  232. data/test/rubygems/specifications/bar-0.0.2.gemspec +2 -0
  233. data/test/rubygems/specifications/rubyforge-0.0.1.gemspec +2 -0
  234. data/test/rubygems/test_bundled_ca.rb +1 -0
  235. data/test/rubygems/test_config.rb +1 -0
  236. data/test/rubygems/test_deprecate.rb +1 -0
  237. data/test/rubygems/test_gem.rb +1 -0
  238. data/test/rubygems/test_gem_available_set.rb +1 -0
  239. data/test/rubygems/test_gem_bundler_version_finder.rb +1 -0
  240. data/test/rubygems/test_gem_command.rb +1 -0
  241. data/test/rubygems/test_gem_command_manager.rb +1 -0
  242. data/test/rubygems/test_gem_commands_build_command.rb +1 -0
  243. data/test/rubygems/test_gem_commands_cert_command.rb +1 -0
  244. data/test/rubygems/test_gem_commands_check_command.rb +1 -0
  245. data/test/rubygems/test_gem_commands_cleanup_command.rb +1 -0
  246. data/test/rubygems/test_gem_commands_contents_command.rb +1 -0
  247. data/test/rubygems/test_gem_commands_dependency_command.rb +1 -0
  248. data/test/rubygems/test_gem_commands_environment_command.rb +1 -0
  249. data/test/rubygems/test_gem_commands_exec_command.rb +2 -0
  250. data/test/rubygems/test_gem_commands_fetch_command.rb +1 -0
  251. data/test/rubygems/test_gem_commands_generate_index_command.rb +1 -0
  252. data/test/rubygems/test_gem_commands_help_command.rb +1 -0
  253. data/test/rubygems/test_gem_commands_info_command.rb +1 -0
  254. data/test/rubygems/test_gem_commands_install_command.rb +1 -0
  255. data/test/rubygems/test_gem_commands_list_command.rb +1 -0
  256. data/test/rubygems/test_gem_commands_lock_command.rb +1 -0
  257. data/test/rubygems/test_gem_commands_mirror.rb +1 -0
  258. data/test/rubygems/test_gem_commands_open_command.rb +1 -0
  259. data/test/rubygems/test_gem_commands_outdated_command.rb +1 -0
  260. data/test/rubygems/test_gem_commands_owner_command.rb +68 -39
  261. data/test/rubygems/test_gem_commands_pristine_command.rb +1 -0
  262. data/test/rubygems/test_gem_commands_push_command.rb +68 -37
  263. data/test/rubygems/test_gem_commands_query_command.rb +1 -0
  264. data/test/rubygems/test_gem_commands_search_command.rb +1 -0
  265. data/test/rubygems/test_gem_commands_server_command.rb +1 -0
  266. data/test/rubygems/test_gem_commands_setup_command.rb +1 -1
  267. data/test/rubygems/test_gem_commands_signin_command.rb +1 -0
  268. data/test/rubygems/test_gem_commands_sources_command.rb +1 -0
  269. data/test/rubygems/test_gem_commands_specification_command.rb +1 -0
  270. data/test/rubygems/test_gem_commands_stale_command.rb +1 -0
  271. data/test/rubygems/test_gem_commands_uninstall_command.rb +1 -0
  272. data/test/rubygems/test_gem_commands_unpack_command.rb +1 -0
  273. data/test/rubygems/test_gem_commands_update_command.rb +1 -0
  274. data/test/rubygems/test_gem_commands_which_command.rb +1 -0
  275. data/test/rubygems/test_gem_commands_yank_command.rb +76 -41
  276. data/test/rubygems/test_gem_config_file.rb +1 -0
  277. data/test/rubygems/test_gem_dependency.rb +1 -0
  278. data/test/rubygems/test_gem_dependency_installer.rb +1 -0
  279. data/test/rubygems/test_gem_dependency_list.rb +1 -0
  280. data/test/rubygems/test_gem_dependency_resolution_error.rb +1 -0
  281. data/test/rubygems/test_gem_doctor.rb +1 -0
  282. data/test/rubygems/test_gem_ext_builder.rb +4 -3
  283. data/test/rubygems/test_gem_ext_cargo_builder/custom_name/custom_name.gemspec +2 -0
  284. data/test/rubygems/test_gem_ext_cargo_builder/custom_name/lib/custom_name.rb +2 -0
  285. data/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/rust_ruby_example.gemspec +2 -0
  286. data/test/rubygems/test_gem_ext_cargo_builder.rb +2 -2
  287. data/test/rubygems/test_gem_ext_cargo_builder_link_flag_converter.rb +1 -0
  288. data/test/rubygems/test_gem_ext_cmake_builder.rb +1 -0
  289. data/test/rubygems/test_gem_ext_configure_builder.rb +1 -0
  290. data/test/rubygems/test_gem_ext_rake_builder.rb +1 -0
  291. data/test/rubygems/test_gem_gem_runner.rb +1 -0
  292. data/test/rubygems/test_gem_gemcutter_utilities.rb +106 -92
  293. data/test/rubygems/test_gem_impossible_dependencies_error.rb +1 -0
  294. data/test/rubygems/test_gem_indexer.rb +1 -0
  295. data/test/rubygems/test_gem_install_update_options.rb +1 -0
  296. data/test/rubygems/test_gem_installer.rb +2 -1
  297. data/test/rubygems/test_gem_local_remote_options.rb +1 -0
  298. data/test/rubygems/test_gem_name_tuple.rb +1 -0
  299. data/test/rubygems/test_gem_package_old.rb +1 -0
  300. data/test/rubygems/test_gem_package_tar_header.rb +1 -0
  301. data/test/rubygems/test_gem_package_tar_reader.rb +1 -0
  302. data/test/rubygems/test_gem_package_tar_reader_entry.rb +1 -0
  303. data/test/rubygems/test_gem_package_tar_writer.rb +1 -0
  304. data/test/rubygems/test_gem_package_task.rb +1 -0
  305. data/test/rubygems/test_gem_path_support.rb +1 -0
  306. data/test/rubygems/test_gem_platform.rb +1 -0
  307. data/test/rubygems/test_gem_rdoc.rb +1 -0
  308. data/test/rubygems/test_gem_remote_fetcher.rb +1 -0
  309. data/test/rubygems/test_gem_request.rb +1 -0
  310. data/test/rubygems/test_gem_request_connection_pools.rb +1 -0
  311. data/test/rubygems/test_gem_request_set.rb +1 -0
  312. data/test/rubygems/test_gem_request_set_gem_dependency_api.rb +1 -0
  313. data/test/rubygems/test_gem_request_set_lockfile.rb +1 -0
  314. data/test/rubygems/test_gem_request_set_lockfile_parser.rb +1 -0
  315. data/test/rubygems/test_gem_request_set_lockfile_tokenizer.rb +1 -0
  316. data/test/rubygems/test_gem_requirement.rb +1 -0
  317. data/test/rubygems/test_gem_resolver.rb +1 -0
  318. data/test/rubygems/test_gem_resolver_activation_request.rb +1 -0
  319. data/test/rubygems/test_gem_resolver_api_set.rb +1 -0
  320. data/test/rubygems/test_gem_resolver_api_specification.rb +1 -0
  321. data/test/rubygems/test_gem_resolver_best_set.rb +1 -0
  322. data/test/rubygems/test_gem_resolver_composed_set.rb +1 -0
  323. data/test/rubygems/test_gem_resolver_conflict.rb +1 -0
  324. data/test/rubygems/test_gem_resolver_dependency_request.rb +1 -0
  325. data/test/rubygems/test_gem_resolver_git_set.rb +1 -0
  326. data/test/rubygems/test_gem_resolver_git_specification.rb +2 -1
  327. data/test/rubygems/test_gem_resolver_index_set.rb +1 -0
  328. data/test/rubygems/test_gem_resolver_index_specification.rb +1 -0
  329. data/test/rubygems/test_gem_resolver_installed_specification.rb +1 -0
  330. data/test/rubygems/test_gem_resolver_installer_set.rb +1 -0
  331. data/test/rubygems/test_gem_resolver_local_specification.rb +1 -0
  332. data/test/rubygems/test_gem_resolver_lock_set.rb +1 -0
  333. data/test/rubygems/test_gem_resolver_lock_specification.rb +1 -0
  334. data/test/rubygems/test_gem_resolver_requirement_list.rb +1 -0
  335. data/test/rubygems/test_gem_resolver_specification.rb +1 -0
  336. data/test/rubygems/test_gem_resolver_vendor_set.rb +1 -0
  337. data/test/rubygems/test_gem_resolver_vendor_specification.rb +1 -0
  338. data/test/rubygems/test_gem_security.rb +1 -0
  339. data/test/rubygems/test_gem_security_signer.rb +1 -0
  340. data/test/rubygems/test_gem_security_trust_dir.rb +1 -0
  341. data/test/rubygems/test_gem_silent_ui.rb +1 -0
  342. data/test/rubygems/test_gem_source.rb +1 -0
  343. data/test/rubygems/test_gem_source_fetch_problem.rb +1 -0
  344. data/test/rubygems/test_gem_source_git.rb +1 -0
  345. data/test/rubygems/test_gem_source_installed.rb +1 -0
  346. data/test/rubygems/test_gem_source_list.rb +1 -0
  347. data/test/rubygems/test_gem_source_local.rb +1 -0
  348. data/test/rubygems/test_gem_source_lock.rb +1 -0
  349. data/test/rubygems/test_gem_source_specific_file.rb +1 -0
  350. data/test/rubygems/test_gem_source_subpath_problem.rb +1 -0
  351. data/test/rubygems/test_gem_source_vendor.rb +1 -0
  352. data/test/rubygems/test_gem_spec_fetcher.rb +1 -0
  353. data/test/rubygems/test_gem_specification.rb +9 -0
  354. data/test/rubygems/test_gem_stream_ui.rb +34 -3
  355. data/test/rubygems/test_gem_stub_specification.rb +1 -0
  356. data/test/rubygems/test_gem_text.rb +1 -0
  357. data/test/rubygems/test_gem_uninstaller.rb +1 -0
  358. data/test/rubygems/test_gem_unsatisfiable_dependency_error.rb +1 -0
  359. data/test/rubygems/test_gem_update_suggestion.rb +1 -0
  360. data/test/rubygems/test_gem_uri.rb +2 -0
  361. data/test/rubygems/test_gem_uri_formatter.rb +1 -0
  362. data/test/rubygems/test_gem_util.rb +1 -0
  363. data/test/rubygems/test_gem_version.rb +1 -0
  364. data/test/rubygems/test_gem_version_option.rb +1 -0
  365. data/test/rubygems/test_kernel.rb +1 -0
  366. data/test/rubygems/test_remote_fetch_error.rb +1 -0
  367. data/test/rubygems/test_require.rb +1 -0
  368. data/test/rubygems/test_rubygems.rb +2 -0
  369. data/test/rubygems/test_webauthn_listener.rb +29 -6
  370. data/test/rubygems/test_webauthn_listener_response.rb +8 -8
  371. data/test/rubygems/test_webauthn_poller.rb +124 -0
  372. data/test/rubygems/utilities.rb +1 -0
  373. data/test/test_changelog_generator.rb +1 -1
  374. metadata +39 -10
  375. data/lib/rubygems/webauthn_listener/response.rb +0 -161
  376. data/lib/rubygems/webauthn_listener.rb +0 -92
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "helper"
4
+ require_relative "multifactor_auth_utilities"
3
5
  require "rubygems/commands/owner_command"
4
6
 
5
7
  class TestGemCommandsOwnerCommand < Gem::TestCase
@@ -10,7 +12,7 @@ class TestGemCommandsOwnerCommand < Gem::TestCase
10
12
 
11
13
  ENV["RUBYGEMS_HOST"] = nil
12
14
  @stub_ui = Gem::MockGemUi.new
13
- @stub_fetcher = Gem::FakeFetcher.new
15
+ @stub_fetcher = Gem::MultifactorAuthFetcher.new
14
16
  Gem::RemoteFetcher.fetcher = @stub_fetcher
15
17
  Gem.configuration = nil
16
18
  Gem.configuration.rubygems_api_key = "ed244fbf2b1a52e012da8616c512fa47f9aa5250"
@@ -323,15 +325,8 @@ EOF
323
325
  end
324
326
 
325
327
  def test_otp_verified_success
326
- response_fail = "You have enabled multifactor authentication but your request doesn't have the correct OTP code. Please check it and retry."
327
328
  response_success = "Owner added successfully."
328
-
329
- @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners"] = [
330
- HTTPResponseFactory.create(body: response_fail, code: 401, msg: "Unauthorized"),
331
- HTTPResponseFactory.create(body: response_success, code: 200, msg: "OK"),
332
- ]
333
- @stub_fetcher.data["#{Gem.host}/api/v1/webauthn_verification"] =
334
- HTTPResponseFactory.create(body: "You don't have any security devices", code: 422, msg: "Unprocessable Entity")
329
+ @stub_fetcher.respond_with_require_otp("#{Gem.host}/api/v1/gems/freewill/owners", response_success)
335
330
 
336
331
  @otp_ui = Gem::MockGemUi.new "111111\n"
337
332
  use_ui @otp_ui do
@@ -362,68 +357,102 @@ EOF
362
357
  end
363
358
 
364
359
  def test_with_webauthn_enabled_success
365
- webauthn_verification_url = "rubygems.org/api/v1/webauthn_verification/odow34b93t6aPCdY"
366
- response_fail = "You have enabled multifactor authentication but your request doesn't have the correct OTP code. Please check it and retry."
367
360
  response_success = "Owner added successfully."
368
- port = 5678
369
- server = TCPServer.new(port)
361
+ server = Gem::MockTCPServer.new
370
362
 
371
- @stub_fetcher.data["#{Gem.host}/api/v1/webauthn_verification"] = HTTPResponseFactory.create(body: webauthn_verification_url, code: 200, msg: "OK")
372
- @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners"] = [
373
- HTTPResponseFactory.create(body: response_fail, code: 401, msg: "Unauthorized"),
374
- HTTPResponseFactory.create(body: response_success, code: 200, msg: "OK"),
375
- ]
363
+ @stub_fetcher.respond_with_require_otp("#{Gem.host}/api/v1/gems/freewill/owners", response_success)
364
+ @stub_fetcher.respond_with_webauthn_url
376
365
 
377
366
  TCPServer.stub(:new, server) do
378
- Gem::WebauthnListener.stub(:wait_for_otp_code, "Uvh6T57tkWuUnWYo") do
367
+ Gem::GemcutterUtilities::WebauthnListener.stub(:listener_thread, Thread.new { Thread.current[:otp] = "Uvh6T57tkWuUnWYo" }) do
379
368
  use_ui @stub_ui do
380
369
  @cmd.add_owners("freewill", ["user-new1@example.com"])
381
370
  end
382
371
  end
383
- ensure
384
- server.close
385
372
  end
386
373
 
387
- url_with_port = "#{webauthn_verification_url}?port=#{port}"
388
- assert_match "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.", @stub_ui.output
374
+ assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(server.port)} " \
375
+ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
376
+ "you can re-run the gem signin command with the `--otp [your_code]` option.", @stub_ui.output
389
377
  assert_match "You are verified with a security device. You may close the browser window.", @stub_ui.output
390
378
  assert_equal "Uvh6T57tkWuUnWYo", @stub_fetcher.last_request["OTP"]
391
379
  assert_match response_success, @stub_ui.output
392
380
  end
393
381
 
394
382
  def test_with_webauthn_enabled_failure
395
- webauthn_verification_url = "rubygems.org/api/v1/webauthn_verification/odow34b93t6aPCdY"
396
- response_fail = "You have enabled multifactor authentication but your request doesn't have the correct OTP code. Please check it and retry."
397
383
  response_success = "Owner added successfully."
398
- port = 5678
399
- server = TCPServer.new(port)
400
- raise_error = ->(*_args) { raise Gem::WebauthnVerificationError, "Something went wrong" }
384
+ server = Gem::MockTCPServer.new
385
+ error = Gem::WebauthnVerificationError.new("Something went wrong")
401
386
 
402
- @stub_fetcher.data["#{Gem.host}/api/v1/webauthn_verification"] = HTTPResponseFactory.create(body: webauthn_verification_url, code: 200, msg: "OK")
403
- @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners"] = [
404
- HTTPResponseFactory.create(body: response_fail, code: 401, msg: "Unauthorized"),
405
- HTTPResponseFactory.create(body: response_success, code: 200, msg: "OK"),
406
- ]
387
+ @stub_fetcher.respond_with_require_otp("#{Gem.host}/api/v1/gems/freewill/owners", response_success)
388
+ @stub_fetcher.respond_with_webauthn_url
407
389
 
408
390
  TCPServer.stub(:new, server) do
409
- Gem::WebauthnListener.stub(:wait_for_otp_code, raise_error) do
391
+ Gem::GemcutterUtilities::WebauthnListener.stub(:listener_thread, Thread.new { Thread.current[:error] = error }) do
410
392
  use_ui @stub_ui do
411
393
  @cmd.add_owners("freewill", ["user-new1@example.com"])
412
394
  end
413
395
  end
414
- ensure
415
- server.close
416
396
  end
417
397
 
418
- url_with_port = "#{webauthn_verification_url}?port=#{port}"
419
-
420
398
  assert_match @stub_fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
421
- assert_match "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.", @stub_ui.output
399
+ assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(server.port)} " \
400
+ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
401
+ "you can re-run the gem signin command with the `--otp [your_code]` option.", @stub_ui.output
422
402
  assert_match "ERROR: Security device verification failed: Something went wrong", @stub_ui.error
423
403
  refute_match "You are verified with a security device. You may close the browser window.", @stub_ui.output
424
404
  refute_match response_success, @stub_ui.output
425
405
  end
426
406
 
407
+ def test_with_webauthn_enabled_success_with_polling
408
+ response_success = "Owner added successfully."
409
+ server = Gem::MockTCPServer.new
410
+
411
+ @stub_fetcher.respond_with_require_otp("#{Gem.host}/api/v1/gems/freewill/owners", response_success)
412
+ @stub_fetcher.respond_with_webauthn_url
413
+ @stub_fetcher.respond_with_webauthn_polling("Uvh6T57tkWuUnWYo")
414
+
415
+ TCPServer.stub(:new, server) do
416
+ use_ui @stub_ui do
417
+ @cmd.add_owners("freewill", ["user-new1@example.com"])
418
+ end
419
+ end
420
+
421
+ assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(server.port)} " \
422
+ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin " \
423
+ "command with the `--otp [your_code]` option.", @stub_ui.output
424
+ assert_match "You are verified with a security device. You may close the browser window.", @stub_ui.output
425
+ assert_equal "Uvh6T57tkWuUnWYo", @stub_fetcher.last_request["OTP"]
426
+ assert_match response_success, @stub_ui.output
427
+ end
428
+
429
+ def test_with_webauthn_enabled_failure_with_polling
430
+ response_success = "Owner added successfully."
431
+ server = Gem::MockTCPServer.new
432
+
433
+ @stub_fetcher.respond_with_require_otp(
434
+ "#{Gem.host}/api/v1/gems/freewill/owners",
435
+ response_success
436
+ )
437
+ @stub_fetcher.respond_with_webauthn_url
438
+ @stub_fetcher.respond_with_webauthn_polling_failure
439
+
440
+ TCPServer.stub(:new, server) do
441
+ use_ui @stub_ui do
442
+ @cmd.add_owners("freewill", ["user-new1@example.com"])
443
+ end
444
+ end
445
+
446
+ assert_match @stub_fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
447
+ assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(server.port)} " \
448
+ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin " \
449
+ "command with the `--otp [your_code]` option.", @stub_ui.output
450
+ assert_match "ERROR: Security device verification failed: The token in the link you used has either expired " \
451
+ "or been used already.", @stub_ui.error
452
+ refute_match "You are verified with a security device. You may close the browser window.", @stub_ui.output
453
+ refute_match response_success, @stub_ui.output
454
+ end
455
+
427
456
  def test_remove_owners_unathorized_api_key
428
457
  response_forbidden = "The API key doesn't have access"
429
458
  response_success = "Owner removed successfully."
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "helper"
3
4
  require "rubygems/commands/pristine_command"
4
5
 
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "helper"
4
+ require_relative "multifactor_auth_utilities"
3
5
  require "rubygems/commands/push_command"
4
6
 
5
7
  class TestGemCommandsPushCommand < Gem::TestCase
@@ -24,7 +26,7 @@ class TestGemCommandsPushCommand < Gem::TestCase
24
26
  @host = "https://rubygems.example"
25
27
  @api_key = Gem.configuration.rubygems_api_key
26
28
 
27
- @fetcher = Gem::FakeFetcher.new
29
+ @fetcher = Gem::MultifactorAuthFetcher.new
28
30
  Gem::RemoteFetcher.fetcher = @fetcher
29
31
 
30
32
  @cmd = Gem::Commands::PushCommand.new
@@ -384,15 +386,9 @@ class TestGemCommandsPushCommand < Gem::TestCase
384
386
  end
385
387
 
386
388
  def test_otp_verified_success
387
- response_fail = "You have enabled multifactor authentication but your request doesn't have the correct OTP code. Please check it and retry."
388
389
  response_success = "Successfully registered gem: freewill (1.0.0)"
389
390
 
390
- @fetcher.data["#{Gem.host}/api/v1/gems"] = [
391
- HTTPResponseFactory.create(body: response_fail, code: 401, msg: "Unauthorized"),
392
- HTTPResponseFactory.create(body: response_success, code: 200, msg: "OK"),
393
- ]
394
- @fetcher.data["#{Gem.host}/api/v1/webauthn_verification"] =
395
- HTTPResponseFactory.create(body: "You don't have any security devices", code: 422, msg: "Unprocessable Entity")
391
+ @fetcher.respond_with_require_otp("#{Gem.host}/api/v1/gems", response_success)
396
392
 
397
393
  @otp_ui = Gem::MockGemUi.new "111111\n"
398
394
  use_ui @otp_ui do
@@ -425,70 +421,105 @@ class TestGemCommandsPushCommand < Gem::TestCase
425
421
  end
426
422
 
427
423
  def test_with_webauthn_enabled_success
428
- webauthn_verification_url = "rubygems.org/api/v1/webauthn_verification/odow34b93t6aPCdY"
429
- response_fail = "You have enabled multifactor authentication but your request doesn't have the correct OTP code. Please check it and retry."
430
424
  response_success = "Successfully registered gem: freewill (1.0.0)"
431
- port = 5678
432
- server = TCPServer.new(port)
425
+ server = Gem::MockTCPServer.new
433
426
 
434
- @fetcher.data["#{Gem.host}/api/v1/gems"] = [
435
- HTTPResponseFactory.create(body: response_fail, code: 401, msg: "Unauthorized"),
436
- HTTPResponseFactory.create(body: response_success, code: 200, msg: "OK"),
437
- ]
438
- @fetcher.data["#{Gem.host}/api/v1/webauthn_verification"] = HTTPResponseFactory.create(body: webauthn_verification_url, code: 200, msg: "OK")
427
+ @fetcher.respond_with_require_otp("#{Gem.host}/api/v1/gems", response_success)
428
+ @fetcher.respond_with_webauthn_url
439
429
 
440
430
  TCPServer.stub(:new, server) do
441
- Gem::WebauthnListener.stub(:wait_for_otp_code, "Uvh6T57tkWuUnWYo") do
431
+ Gem::GemcutterUtilities::WebauthnListener.stub(:listener_thread, Thread.new { Thread.current[:otp] = "Uvh6T57tkWuUnWYo" }) do
442
432
  use_ui @ui do
443
433
  @cmd.send_gem(@path)
444
434
  end
445
435
  end
446
- ensure
447
- server.close
448
436
  end
449
437
 
450
- url_with_port = "#{webauthn_verification_url}?port=#{port}"
451
- assert_match "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.", @ui.output
438
+ assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
439
+ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
440
+ "you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
452
441
  assert_match "You are verified with a security device. You may close the browser window.", @ui.output
453
442
  assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"]
454
443
  assert_match response_success, @ui.output
455
444
  end
456
445
 
457
446
  def test_with_webauthn_enabled_failure
458
- webauthn_verification_url = "rubygems.org/api/v1/webauthn_verification/odow34b93t6aPCdY"
459
- response_fail = "You have enabled multifactor authentication but your request doesn't have the correct OTP code. Please check it and retry."
460
447
  response_success = "Successfully registered gem: freewill (1.0.0)"
461
- port = 5678
462
- server = TCPServer.new(port)
463
- raise_error = ->(*_args) { raise Gem::WebauthnVerificationError, "Something went wrong" }
448
+ server = Gem::MockTCPServer.new
449
+ error = Gem::WebauthnVerificationError.new("Something went wrong")
464
450
 
465
- @fetcher.data["#{Gem.host}/api/v1/gems"] = [
466
- HTTPResponseFactory.create(body: response_fail, code: 401, msg: "Unauthorized"),
467
- HTTPResponseFactory.create(body: response_success, code: 200, msg: "OK"),
468
- ]
469
- @fetcher.data["#{Gem.host}/api/v1/webauthn_verification"] = HTTPResponseFactory.create(body: webauthn_verification_url, code: 200, msg: "OK")
451
+ @fetcher.respond_with_require_otp("#{Gem.host}/api/v1/gems", response_success)
452
+ @fetcher.respond_with_webauthn_url
470
453
 
471
454
  error = assert_raise Gem::MockGemUi::TermError do
472
455
  TCPServer.stub(:new, server) do
473
- Gem::WebauthnListener.stub(:wait_for_otp_code, raise_error) do
456
+ Gem::GemcutterUtilities::WebauthnListener.stub(:listener_thread, Thread.new { Thread.current[:error] = error }) do
474
457
  use_ui @ui do
475
458
  @cmd.send_gem(@path)
476
459
  end
477
460
  end
478
- ensure
479
- server.close
480
461
  end
481
462
  end
482
463
  assert_equal 1, error.exit_code
483
464
 
484
465
  assert_match @fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
485
- url_with_port = "#{webauthn_verification_url}?port=#{port}"
486
- assert_match "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.", @ui.output
466
+ assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
467
+ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
468
+ "you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
487
469
  assert_match "ERROR: Security device verification failed: Something went wrong", @ui.error
488
470
  refute_match "You are verified with a security device. You may close the browser window.", @ui.output
489
471
  refute_match response_success, @ui.output
490
472
  end
491
473
 
474
+ def test_with_webauthn_enabled_success_with_polling
475
+ response_success = "Successfully registered gem: freewill (1.0.0)"
476
+ server = Gem::MockTCPServer.new
477
+
478
+ @fetcher.respond_with_require_otp("#{Gem.host}/api/v1/gems", response_success)
479
+ @fetcher.respond_with_webauthn_url
480
+ @fetcher.respond_with_webauthn_polling("Uvh6T57tkWuUnWYo")
481
+
482
+ TCPServer.stub(:new, server) do
483
+ use_ui @ui do
484
+ @cmd.send_gem(@path)
485
+ end
486
+ end
487
+
488
+ assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
489
+ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
490
+ "you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
491
+ assert_match "You are verified with a security device. You may close the browser window.", @ui.output
492
+ assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"]
493
+ assert_match response_success, @ui.output
494
+ end
495
+
496
+ def test_with_webauthn_enabled_failure_with_polling
497
+ response_success = "Successfully registered gem: freewill (1.0.0)"
498
+ server = Gem::MockTCPServer.new
499
+
500
+ @fetcher.respond_with_require_otp("#{Gem.host}/api/v1/gems", response_success)
501
+ @fetcher.respond_with_webauthn_url
502
+ @fetcher.respond_with_webauthn_polling_failure
503
+
504
+ error = assert_raise Gem::MockGemUi::TermError do
505
+ TCPServer.stub(:new, server) do
506
+ use_ui @ui do
507
+ @cmd.send_gem(@path)
508
+ end
509
+ end
510
+ end
511
+ assert_equal 1, error.exit_code
512
+
513
+ assert_match @fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
514
+ assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
515
+ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin " \
516
+ "command with the `--otp [your_code]` option.", @ui.output
517
+ assert_match "ERROR: Security device verification failed: The token in the link you used has either expired " \
518
+ "or been used already.", @ui.error
519
+ refute_match "You are verified with a security device. You may close the browser window.", @ui.output
520
+ refute_match response_success, @ui.output
521
+ end
522
+
492
523
  def test_sending_gem_unathorized_api_key_with_mfa_enabled
493
524
  response_mfa_enabled = "You have enabled multifactor authentication but your request doesn't have the correct OTP code. Please check it and retry."
494
525
  response_forbidden = "The API key doesn't have access"
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "helper"
3
4
  require "rubygems/commands/query_command"
4
5
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "helper"
3
4
  require "rubygems/commands/search_command"
4
5
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "helper"
3
4
  require "rubygems/commands/server_command"
4
5
 
@@ -18,7 +18,7 @@ class TestGemCommandsSetupCommand < Gem::TestCase
18
18
  @cmd.options[:document] = []
19
19
 
20
20
  filelist = %w[
21
- bin/gem
21
+ exe/gem
22
22
  lib/rubygems.rb
23
23
  lib/rubygems/requirement.rb
24
24
  lib/rubygems/ssl_certs/rubygems.org/foo.pem
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "helper"
3
4
  require "rubygems/commands/signin_command"
4
5
  require "rubygems/installer"
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "helper"
3
4
  require "rubygems/commands/sources_command"
4
5
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "helper"
3
4
  require "rubygems/commands/specification_command"
4
5
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "helper"
3
4
  require "rubygems/commands/stale_command"
4
5
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "installer_test_case"
3
4
  require "rubygems/commands/uninstall_command"
4
5
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "helper"
3
4
  require "rubygems/commands/unpack_command"
4
5
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "helper"
3
4
  require "rubygems/commands/update_command"
4
5
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "helper"
3
4
  require "rubygems/commands/which_command"
4
5
 
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "helper"
4
+ require_relative "multifactor_auth_utilities"
3
5
  require "rubygems/commands/yank_command"
4
6
 
5
7
  class TestGemCommandsYankCommand < Gem::TestCase
@@ -11,7 +13,8 @@ class TestGemCommandsYankCommand < Gem::TestCase
11
13
  @cmd = Gem::Commands::YankCommand.new
12
14
  @cmd.options[:host] = "http://example"
13
15
 
14
- @fetcher = Gem::RemoteFetcher.fetcher
16
+ @fetcher = Gem::MultifactorAuthFetcher.new(host: "http://example")
17
+ Gem::RemoteFetcher.fetcher = @fetcher
15
18
 
16
19
  Gem.configuration.rubygems_api_key = "key"
17
20
  Gem.configuration.api_keys[:KEY] = "other"
@@ -72,9 +75,6 @@ class TestGemCommandsYankCommand < Gem::TestCase
72
75
  HTTPResponseFactory.create(body: response_fail, code: 401, msg: "Unauthorized"),
73
76
  HTTPResponseFactory.create(body: "Successfully yanked", code: 200, msg: "OK"),
74
77
  ]
75
- webauthn_uri = "http://example/api/v1/webauthn_verification"
76
- @fetcher.data[webauthn_uri] =
77
- HTTPResponseFactory.create(body: "You don't have any security devices", code: 422, msg: "Unprocessable Entity")
78
78
 
79
79
  @cmd.options[:args] = %w[a]
80
80
  @cmd.options[:added_platform] = true
@@ -96,9 +96,6 @@ class TestGemCommandsYankCommand < Gem::TestCase
96
96
  response = "You have enabled multifactor authentication but your request doesn't have the correct OTP code. Please check it and retry."
97
97
  yank_uri = "http://example/api/v1/gems/yank"
98
98
  @fetcher.data[yank_uri] = HTTPResponseFactory.create(body: response, code: 401, msg: "Unauthorized")
99
- webauthn_uri = "http://example/api/v1/webauthn_verification"
100
- @fetcher.data[webauthn_uri] =
101
- HTTPResponseFactory.create(body: "You don't have any security devices", code: 422, msg: "Unprocessable Entity")
102
99
 
103
100
  @cmd.options[:args] = %w[a]
104
101
  @cmd.options[:added_platform] = true
@@ -116,55 +113,38 @@ class TestGemCommandsYankCommand < Gem::TestCase
116
113
  end
117
114
 
118
115
  def test_with_webauthn_enabled_success
119
- webauthn_verification_url = "http://example/api/v1/webauthn_verification/odow34b93t6aPCdY"
120
- response_fail = "You have enabled multifactor authentication but your request doesn't have the correct OTP code. Please check it and retry."
121
- yank_uri = "http://example/api/v1/gems/yank"
122
- webauthn_uri = "http://example/api/v1/webauthn_verification"
123
- port = 5678
124
- server = TCPServer.new(port)
116
+ server = Gem::MockTCPServer.new
125
117
 
126
- @fetcher.data[webauthn_uri] = HTTPResponseFactory.create(body: webauthn_verification_url, code: 200, msg: "OK")
127
- @fetcher.data[yank_uri] = [
128
- HTTPResponseFactory.create(body: response_fail, code: 401, msg: "Unauthorized"),
129
- HTTPResponseFactory.create(body: "Successfully yanked", code: 200, msg: "OK"),
130
- ]
118
+ @fetcher.respond_with_require_otp("http://example/api/v1/gems/yank", "Successfully yanked")
119
+ @fetcher.respond_with_webauthn_url
131
120
 
132
121
  @cmd.options[:args] = %w[a]
133
122
  @cmd.options[:added_platform] = true
134
123
  @cmd.options[:version] = req("= 1.0")
135
124
 
136
125
  TCPServer.stub(:new, server) do
137
- Gem::WebauthnListener.stub(:wait_for_otp_code, "Uvh6T57tkWuUnWYo") do
126
+ Gem::GemcutterUtilities::WebauthnListener.stub(:listener_thread, Thread.new { Thread.current[:otp] = "Uvh6T57tkWuUnWYo" }) do
138
127
  use_ui @ui do
139
128
  @cmd.execute
140
129
  end
141
130
  end
142
- ensure
143
- server.close
144
131
  end
145
132
 
146
- url_with_port = "#{webauthn_verification_url}?port=#{port}"
147
133
  assert_match %r{Yanking gem from http://example}, @ui.output
148
- assert_match "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.", @ui.output
134
+ assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
135
+ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
136
+ "you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
149
137
  assert_match "You are verified with a security device. You may close the browser window.", @ui.output
150
138
  assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"]
151
139
  assert_match "Successfully yanked", @ui.output
152
140
  end
153
141
 
154
142
  def test_with_webauthn_enabled_failure
155
- webauthn_verification_url = "http://example/api/v1/webauthn_verification/odow34b93t6aPCdY"
156
- response_fail = "You have enabled multifactor authentication but your request doesn't have the correct OTP code. Please check it and retry."
157
- yank_uri = "http://example/api/v1/gems/yank"
158
- webauthn_uri = "http://example/api/v1/webauthn_verification"
159
- port = 5678
160
- server = TCPServer.new(port)
161
- raise_error = ->(*_args) { raise Gem::WebauthnVerificationError, "Something went wrong" }
143
+ server = Gem::MockTCPServer.new
144
+ error = Gem::WebauthnVerificationError.new("Something went wrong")
162
145
 
163
- @fetcher.data[webauthn_uri] = HTTPResponseFactory.create(body: webauthn_verification_url, code: 200, msg: "OK")
164
- @fetcher.data[yank_uri] = [
165
- HTTPResponseFactory.create(body: response_fail, code: 401, msg: "Unauthorized"),
166
- HTTPResponseFactory.create(body: "Successfully yanked", code: 200, msg: "OK"),
167
- ]
146
+ @fetcher.respond_with_require_otp("http://example/api/v1/gems/yank", "Successfully yanked")
147
+ @fetcher.respond_with_webauthn_url
168
148
 
169
149
  @cmd.options[:args] = %w[a]
170
150
  @cmd.options[:added_platform] = true
@@ -172,27 +152,82 @@ class TestGemCommandsYankCommand < Gem::TestCase
172
152
 
173
153
  error = assert_raise Gem::MockGemUi::TermError do
174
154
  TCPServer.stub(:new, server) do
175
- Gem::WebauthnListener.stub(:wait_for_otp_code, raise_error) do
155
+ Gem::GemcutterUtilities::WebauthnListener.stub(:listener_thread, Thread.new { Thread.current[:error] = error }) do
176
156
  use_ui @ui do
177
157
  @cmd.execute
178
158
  end
179
159
  end
180
- ensure
181
- server.close
182
160
  end
183
161
  end
184
162
  assert_equal 1, error.exit_code
185
163
 
186
- url_with_port = "#{webauthn_verification_url}?port=#{port}"
187
-
188
164
  assert_match @fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
189
165
  assert_match %r{Yanking gem from http://example}, @ui.output
190
- assert_match "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.", @ui.output
166
+ assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
167
+ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
168
+ "you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
191
169
  assert_match "ERROR: Security device verification failed: Something went wrong", @ui.error
192
170
  refute_match "You are verified with a security device. You may close the browser window.", @ui.output
193
171
  refute_match "Successfully yanked", @ui.output
194
172
  end
195
173
 
174
+ def test_with_webauthn_enabled_success_with_polling
175
+ server = Gem::MockTCPServer.new
176
+
177
+ @fetcher.respond_with_require_otp("http://example/api/v1/gems/yank", "Successfully yanked")
178
+ @fetcher.respond_with_webauthn_url
179
+ @fetcher.respond_with_webauthn_polling("Uvh6T57tkWuUnWYo")
180
+
181
+ @cmd.options[:args] = %w[a]
182
+ @cmd.options[:added_platform] = true
183
+ @cmd.options[:version] = req("= 1.0")
184
+
185
+ TCPServer.stub(:new, server) do
186
+ use_ui @ui do
187
+ @cmd.execute
188
+ end
189
+ end
190
+
191
+ assert_match %r{Yanking gem from http://example}, @ui.output
192
+ assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
193
+ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
194
+ "you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
195
+ assert_match "You are verified with a security device. You may close the browser window.", @ui.output
196
+ assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"]
197
+ assert_match "Successfully yanked", @ui.output
198
+ end
199
+
200
+ def test_with_webauthn_enabled_failure_with_polling
201
+ server = Gem::MockTCPServer.new
202
+
203
+ @fetcher.respond_with_require_otp("http://example/api/v1/gems/yank", "Successfully yanked")
204
+ @fetcher.respond_with_webauthn_url
205
+ @fetcher.respond_with_webauthn_polling_failure
206
+
207
+ @cmd.options[:args] = %w[a]
208
+ @cmd.options[:added_platform] = true
209
+ @cmd.options[:version] = req("= 1.0")
210
+
211
+ error = assert_raise Gem::MockGemUi::TermError do
212
+ TCPServer.stub(:new, server) do
213
+ use_ui @ui do
214
+ @cmd.execute
215
+ end
216
+ end
217
+ end
218
+ assert_equal 1, error.exit_code
219
+
220
+ assert_match @fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
221
+ assert_match %r{Yanking gem from http://example}, @ui.output
222
+ assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
223
+ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
224
+ "you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
225
+ assert_match "ERROR: Security device verification failed: The token in the link you used has either expired " \
226
+ "or been used already.", @ui.error
227
+ refute_match "You are verified with a security device. You may close the browser window.", @ui.output
228
+ refute_match "Successfully yanked", @ui.output
229
+ end
230
+
196
231
  def test_execute_key
197
232
  yank_uri = "http://example/api/v1/gems/yank"
198
233
  @fetcher.data[yank_uri] = HTTPResponseFactory.create(body: "Successfully yanked", code: 200, msg: "OK")
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "helper"
3
4
  require "rubygems/config_file"
4
5
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "helper"
3
4
  require "rubygems/dependency"
4
5
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative "helper"
3
4
  require "rubygems/dependency_installer"
4
5
  require "rubygems/security"