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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +24 -0
- data/Manifest.txt +7 -4
- data/POLICIES.md +2 -2
- data/bundler/CHANGELOG.md +30 -0
- data/bundler/lib/bundler/build_metadata.rb +2 -2
- data/bundler/lib/bundler/cli/binstubs.rb +1 -1
- data/bundler/lib/bundler/cli/info.rb +1 -1
- data/bundler/lib/bundler/cli/install.rb +1 -1
- data/bundler/lib/bundler/cli/outdated.rb +1 -1
- data/bundler/lib/bundler/cli/platform.rb +7 -5
- data/bundler/lib/bundler/definition.rb +25 -20
- data/bundler/lib/bundler/dsl.rb +1 -1
- data/bundler/lib/bundler/env.rb +1 -1
- data/bundler/lib/bundler/fetcher/compact_index.rb +3 -3
- data/bundler/lib/bundler/fetcher/downloader.rb +2 -0
- data/bundler/lib/bundler/fetcher/index.rb +1 -2
- data/bundler/lib/bundler/fetcher.rb +11 -1
- data/bundler/lib/bundler/friendly_errors.rb +1 -1
- data/bundler/lib/bundler/gem_helper.rb +3 -4
- data/bundler/lib/bundler/installer/parallel_installer.rb +1 -1
- data/bundler/lib/bundler/man/bundle-add.1 +1 -1
- data/bundler/lib/bundler/man/bundle-binstubs.1 +1 -1
- data/bundler/lib/bundler/man/bundle-cache.1 +1 -1
- data/bundler/lib/bundler/man/bundle-check.1 +1 -1
- data/bundler/lib/bundler/man/bundle-clean.1 +1 -1
- data/bundler/lib/bundler/man/bundle-config.1 +1 -1
- data/bundler/lib/bundler/man/bundle-console.1 +1 -1
- data/bundler/lib/bundler/man/bundle-doctor.1 +1 -1
- data/bundler/lib/bundler/man/bundle-exec.1 +1 -1
- data/bundler/lib/bundler/man/bundle-gem.1 +1 -1
- data/bundler/lib/bundler/man/bundle-help.1 +1 -1
- data/bundler/lib/bundler/man/bundle-info.1 +3 -3
- data/bundler/lib/bundler/man/bundle-info.1.ronn +3 -3
- data/bundler/lib/bundler/man/bundle-init.1 +1 -1
- data/bundler/lib/bundler/man/bundle-inject.1 +1 -1
- data/bundler/lib/bundler/man/bundle-install.1 +1 -1
- data/bundler/lib/bundler/man/bundle-list.1 +1 -1
- data/bundler/lib/bundler/man/bundle-lock.1 +1 -1
- data/bundler/lib/bundler/man/bundle-open.1 +1 -1
- data/bundler/lib/bundler/man/bundle-outdated.1 +13 -9
- data/bundler/lib/bundler/man/bundle-outdated.1.ronn +12 -9
- data/bundler/lib/bundler/man/bundle-platform.1 +1 -1
- data/bundler/lib/bundler/man/bundle-plugin.1 +1 -1
- data/bundler/lib/bundler/man/bundle-pristine.1 +1 -1
- data/bundler/lib/bundler/man/bundle-remove.1 +1 -1
- data/bundler/lib/bundler/man/bundle-show.1 +1 -1
- data/bundler/lib/bundler/man/bundle-update.1 +1 -1
- data/bundler/lib/bundler/man/bundle-version.1 +1 -1
- data/bundler/lib/bundler/man/bundle-viz.1 +1 -1
- data/bundler/lib/bundler/man/bundle.1 +1 -1
- data/bundler/lib/bundler/man/gemfile.5 +14 -1
- data/bundler/lib/bundler/man/gemfile.5.ronn +5 -0
- data/bundler/lib/bundler/plugin/index.rb +1 -1
- data/bundler/lib/bundler/ruby_dsl.rb +6 -0
- data/bundler/lib/bundler/ruby_version.rb +2 -2
- data/bundler/lib/bundler/rubygems_integration.rb +1 -1
- data/bundler/lib/bundler/source/git.rb +7 -0
- data/bundler/lib/bundler/source_list.rb +0 -4
- data/bundler/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt +1 -1
- data/bundler/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt +4 -4
- data/bundler/lib/bundler/ui/rg_proxy.rb +1 -1
- data/bundler/lib/bundler/vendor/fileutils/lib/fileutils.rb +1 -1
- data/bundler/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb +2 -2
- data/bundler/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb +1 -1
- data/bundler/lib/bundler/vendor/uri/lib/uri/version.rb +1 -1
- data/bundler/lib/bundler/version.rb +1 -1
- data/bundler/lib/bundler.rb +1 -1
- data/{bin → exe}/gem +2 -0
- data/{bin → exe}/update_rubygems +7 -5
- data/lib/rubygems/available_set.rb +1 -0
- data/lib/rubygems/basic_specification.rb +1 -0
- data/lib/rubygems/bundler_version_finder.rb +1 -1
- data/lib/rubygems/command.rb +1 -0
- data/lib/rubygems/command_manager.rb +1 -0
- data/lib/rubygems/commands/build_command.rb +1 -0
- data/lib/rubygems/commands/cert_command.rb +1 -0
- data/lib/rubygems/commands/check_command.rb +1 -0
- data/lib/rubygems/commands/cleanup_command.rb +1 -0
- data/lib/rubygems/commands/contents_command.rb +1 -0
- data/lib/rubygems/commands/dependency_command.rb +1 -0
- data/lib/rubygems/commands/environment_command.rb +1 -0
- data/lib/rubygems/commands/exec_command.rb +1 -0
- data/lib/rubygems/commands/fetch_command.rb +1 -0
- data/lib/rubygems/commands/generate_index_command.rb +1 -0
- data/lib/rubygems/commands/help_command.rb +1 -0
- data/lib/rubygems/commands/install_command.rb +1 -0
- data/lib/rubygems/commands/list_command.rb +1 -0
- data/lib/rubygems/commands/lock_command.rb +1 -0
- data/lib/rubygems/commands/mirror_command.rb +1 -0
- data/lib/rubygems/commands/open_command.rb +1 -0
- data/lib/rubygems/commands/outdated_command.rb +1 -0
- data/lib/rubygems/commands/owner_command.rb +1 -0
- data/lib/rubygems/commands/pristine_command.rb +1 -0
- data/lib/rubygems/commands/push_command.rb +1 -0
- data/lib/rubygems/commands/query_command.rb +1 -0
- data/lib/rubygems/commands/rdoc_command.rb +1 -0
- data/lib/rubygems/commands/search_command.rb +1 -0
- data/lib/rubygems/commands/server_command.rb +1 -0
- data/lib/rubygems/commands/setup_command.rb +2 -1
- data/lib/rubygems/commands/signin_command.rb +1 -0
- data/lib/rubygems/commands/signout_command.rb +1 -0
- data/lib/rubygems/commands/sources_command.rb +1 -0
- data/lib/rubygems/commands/specification_command.rb +1 -0
- data/lib/rubygems/commands/stale_command.rb +1 -0
- data/lib/rubygems/commands/uninstall_command.rb +1 -0
- data/lib/rubygems/commands/unpack_command.rb +1 -0
- data/lib/rubygems/commands/update_command.rb +1 -0
- data/lib/rubygems/commands/which_command.rb +1 -0
- data/lib/rubygems/commands/yank_command.rb +1 -0
- data/lib/rubygems/config_file.rb +1 -0
- data/lib/rubygems/core_ext/kernel_require.rb +1 -0
- data/lib/rubygems/core_ext/tcpsocket_init.rb +2 -0
- data/lib/rubygems/defaults.rb +1 -0
- data/lib/rubygems/dependency.rb +1 -0
- data/lib/rubygems/dependency_installer.rb +1 -0
- data/lib/rubygems/dependency_list.rb +1 -0
- data/lib/rubygems/deprecate.rb +1 -0
- data/lib/rubygems/doctor.rb +1 -0
- data/lib/rubygems/errors.rb +1 -0
- data/lib/rubygems/ext/build_error.rb +1 -0
- data/lib/rubygems/ext/builder.rb +1 -0
- data/lib/rubygems/ext/configure_builder.rb +1 -0
- data/lib/rubygems/ext/ext_conf_builder.rb +1 -0
- data/lib/rubygems/ext.rb +1 -0
- data/lib/rubygems/gem_runner.rb +1 -0
- data/lib/rubygems/gemcutter_utilities/webauthn_listener/response.rb +163 -0
- data/lib/rubygems/gemcutter_utilities/webauthn_listener.rb +105 -0
- data/lib/rubygems/gemcutter_utilities/webauthn_poller.rb +78 -0
- data/lib/rubygems/gemcutter_utilities.rb +30 -26
- data/lib/rubygems/indexer.rb +1 -0
- data/lib/rubygems/install_default_message.rb +1 -0
- data/lib/rubygems/install_message.rb +1 -0
- data/lib/rubygems/install_update_options.rb +1 -0
- data/lib/rubygems/installer.rb +1 -0
- data/lib/rubygems/local_remote_options.rb +1 -0
- data/lib/rubygems/mock_gem_ui.rb +1 -0
- data/lib/rubygems/name_tuple.rb +1 -0
- data/lib/rubygems/package/digest_io.rb +1 -0
- data/lib/rubygems/package/file_source.rb +1 -0
- data/lib/rubygems/package/io_source.rb +1 -0
- data/lib/rubygems/package/old.rb +1 -0
- data/lib/rubygems/package/source.rb +1 -0
- data/lib/rubygems/package/tar_header.rb +1 -0
- data/lib/rubygems/package/tar_reader/entry.rb +1 -0
- data/lib/rubygems/package/tar_reader.rb +1 -0
- data/lib/rubygems/package/tar_writer.rb +1 -0
- data/lib/rubygems/package.rb +2 -2
- data/lib/rubygems/package_task.rb +1 -0
- data/lib/rubygems/path_support.rb +1 -0
- data/lib/rubygems/platform.rb +1 -0
- data/lib/rubygems/psych_tree.rb +1 -0
- data/lib/rubygems/rdoc.rb +1 -0
- data/lib/rubygems/remote_fetcher.rb +1 -0
- data/lib/rubygems/request/http_pool.rb +1 -0
- data/lib/rubygems/request/https_pool.rb +1 -0
- data/lib/rubygems/request.rb +1 -0
- data/lib/rubygems/request_set/gem_dependency_api.rb +1 -0
- data/lib/rubygems/request_set/lockfile/parser.rb +2 -1
- data/lib/rubygems/request_set/lockfile/tokenizer.rb +2 -0
- data/lib/rubygems/request_set/lockfile.rb +1 -0
- data/lib/rubygems/request_set.rb +1 -0
- data/lib/rubygems/requirement.rb +1 -0
- data/lib/rubygems/resolver/activation_request.rb +1 -0
- data/lib/rubygems/resolver/api_set.rb +1 -0
- data/lib/rubygems/resolver/api_specification.rb +1 -0
- data/lib/rubygems/resolver/best_set.rb +1 -0
- data/lib/rubygems/resolver/composed_set.rb +1 -0
- data/lib/rubygems/resolver/conflict.rb +1 -0
- data/lib/rubygems/resolver/current_set.rb +1 -0
- data/lib/rubygems/resolver/dependency_request.rb +1 -0
- data/lib/rubygems/resolver/git_set.rb +1 -0
- data/lib/rubygems/resolver/git_specification.rb +1 -0
- data/lib/rubygems/resolver/index_set.rb +1 -0
- data/lib/rubygems/resolver/index_specification.rb +1 -0
- data/lib/rubygems/resolver/installed_specification.rb +1 -0
- data/lib/rubygems/resolver/installer_set.rb +1 -0
- data/lib/rubygems/resolver/local_specification.rb +1 -0
- data/lib/rubygems/resolver/lock_set.rb +1 -0
- data/lib/rubygems/resolver/lock_specification.rb +1 -0
- data/lib/rubygems/resolver/molinillo.rb +1 -0
- data/lib/rubygems/resolver/requirement_list.rb +1 -0
- data/lib/rubygems/resolver/set.rb +1 -0
- data/lib/rubygems/resolver/source_set.rb +2 -0
- data/lib/rubygems/resolver/spec_specification.rb +1 -0
- data/lib/rubygems/resolver/specification.rb +1 -0
- data/lib/rubygems/resolver/stats.rb +1 -0
- data/lib/rubygems/resolver/vendor_set.rb +1 -0
- data/lib/rubygems/resolver/vendor_specification.rb +1 -0
- data/lib/rubygems/resolver.rb +1 -0
- data/lib/rubygems/s3_uri_signer.rb +4 -2
- data/lib/rubygems/safe_yaml.rb +2 -0
- data/lib/rubygems/security/policies.rb +1 -0
- data/lib/rubygems/security/policy.rb +1 -0
- data/lib/rubygems/security/signer.rb +1 -0
- data/lib/rubygems/security/trust_dir.rb +1 -0
- data/lib/rubygems/security.rb +1 -0
- data/lib/rubygems/security_option.rb +1 -0
- data/lib/rubygems/source/installed.rb +1 -0
- data/lib/rubygems/source/local.rb +1 -0
- data/lib/rubygems/source/lock.rb +1 -0
- data/lib/rubygems/source/specific_file.rb +1 -0
- data/lib/rubygems/source/vendor.rb +1 -0
- data/lib/rubygems/spec_fetcher.rb +1 -0
- data/lib/rubygems/specification.rb +11 -3
- data/lib/rubygems/specification_policy.rb +2 -0
- data/lib/rubygems/stub_specification.rb +1 -0
- data/lib/rubygems/uninstaller.rb +1 -0
- data/lib/rubygems/user_interaction.rb +4 -2
- data/lib/rubygems/util/licenses.rb +1 -0
- data/lib/rubygems/util/list.rb +1 -0
- data/lib/rubygems/util.rb +1 -0
- data/lib/rubygems/validator.rb +1 -0
- data/lib/rubygems/version_option.rb +1 -0
- data/lib/rubygems.rb +3 -3
- data/rubygems-update.gemspec +5 -4
- data/setup.rb +1 -0
- data/test/rubygems/bad_rake.rb +1 -0
- data/test/rubygems/bundler_test_gem.rb +3 -1
- data/test/rubygems/fake_certlib/openssl.rb +1 -0
- data/test/rubygems/good_rake.rb +1 -0
- data/test/rubygems/helper.rb +1 -1
- data/test/rubygems/installer_test_case.rb +1 -0
- data/test/rubygems/multifactor_auth_utilities.rb +111 -0
- data/test/rubygems/package/tar_test_case.rb +1 -0
- data/test/rubygems/plugin/exception/rubygems_plugin.rb +1 -0
- data/test/rubygems/plugin/load/rubygems_plugin.rb +1 -0
- data/test/rubygems/plugin/standarderror/rubygems_plugin.rb +1 -0
- data/test/rubygems/rubygems/commands/crash_command.rb +1 -0
- data/test/rubygems/rubygems_plugin.rb +1 -0
- data/test/rubygems/simple_gem.rb +1 -0
- data/test/rubygems/specifications/bar-0.0.2.gemspec +2 -0
- data/test/rubygems/specifications/rubyforge-0.0.1.gemspec +2 -0
- data/test/rubygems/test_bundled_ca.rb +1 -0
- data/test/rubygems/test_config.rb +1 -0
- data/test/rubygems/test_deprecate.rb +1 -0
- data/test/rubygems/test_gem.rb +1 -0
- data/test/rubygems/test_gem_available_set.rb +1 -0
- data/test/rubygems/test_gem_bundler_version_finder.rb +1 -0
- data/test/rubygems/test_gem_command.rb +1 -0
- data/test/rubygems/test_gem_command_manager.rb +1 -0
- data/test/rubygems/test_gem_commands_build_command.rb +1 -0
- data/test/rubygems/test_gem_commands_cert_command.rb +1 -0
- data/test/rubygems/test_gem_commands_check_command.rb +1 -0
- data/test/rubygems/test_gem_commands_cleanup_command.rb +1 -0
- data/test/rubygems/test_gem_commands_contents_command.rb +1 -0
- data/test/rubygems/test_gem_commands_dependency_command.rb +1 -0
- data/test/rubygems/test_gem_commands_environment_command.rb +1 -0
- data/test/rubygems/test_gem_commands_exec_command.rb +2 -0
- data/test/rubygems/test_gem_commands_fetch_command.rb +1 -0
- data/test/rubygems/test_gem_commands_generate_index_command.rb +1 -0
- data/test/rubygems/test_gem_commands_help_command.rb +1 -0
- data/test/rubygems/test_gem_commands_info_command.rb +1 -0
- data/test/rubygems/test_gem_commands_install_command.rb +1 -0
- data/test/rubygems/test_gem_commands_list_command.rb +1 -0
- data/test/rubygems/test_gem_commands_lock_command.rb +1 -0
- data/test/rubygems/test_gem_commands_mirror.rb +1 -0
- data/test/rubygems/test_gem_commands_open_command.rb +1 -0
- data/test/rubygems/test_gem_commands_outdated_command.rb +1 -0
- data/test/rubygems/test_gem_commands_owner_command.rb +68 -39
- data/test/rubygems/test_gem_commands_pristine_command.rb +1 -0
- data/test/rubygems/test_gem_commands_push_command.rb +68 -37
- data/test/rubygems/test_gem_commands_query_command.rb +1 -0
- data/test/rubygems/test_gem_commands_search_command.rb +1 -0
- data/test/rubygems/test_gem_commands_server_command.rb +1 -0
- data/test/rubygems/test_gem_commands_setup_command.rb +1 -1
- data/test/rubygems/test_gem_commands_signin_command.rb +1 -0
- data/test/rubygems/test_gem_commands_sources_command.rb +1 -0
- data/test/rubygems/test_gem_commands_specification_command.rb +1 -0
- data/test/rubygems/test_gem_commands_stale_command.rb +1 -0
- data/test/rubygems/test_gem_commands_uninstall_command.rb +1 -0
- data/test/rubygems/test_gem_commands_unpack_command.rb +1 -0
- data/test/rubygems/test_gem_commands_update_command.rb +1 -0
- data/test/rubygems/test_gem_commands_which_command.rb +1 -0
- data/test/rubygems/test_gem_commands_yank_command.rb +76 -41
- data/test/rubygems/test_gem_config_file.rb +1 -0
- data/test/rubygems/test_gem_dependency.rb +1 -0
- data/test/rubygems/test_gem_dependency_installer.rb +1 -0
- data/test/rubygems/test_gem_dependency_list.rb +1 -0
- data/test/rubygems/test_gem_dependency_resolution_error.rb +1 -0
- data/test/rubygems/test_gem_doctor.rb +1 -0
- data/test/rubygems/test_gem_ext_builder.rb +4 -3
- data/test/rubygems/test_gem_ext_cargo_builder/custom_name/custom_name.gemspec +2 -0
- data/test/rubygems/test_gem_ext_cargo_builder/custom_name/lib/custom_name.rb +2 -0
- data/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/rust_ruby_example.gemspec +2 -0
- data/test/rubygems/test_gem_ext_cargo_builder.rb +2 -2
- data/test/rubygems/test_gem_ext_cargo_builder_link_flag_converter.rb +1 -0
- data/test/rubygems/test_gem_ext_cmake_builder.rb +1 -0
- data/test/rubygems/test_gem_ext_configure_builder.rb +1 -0
- data/test/rubygems/test_gem_ext_rake_builder.rb +1 -0
- data/test/rubygems/test_gem_gem_runner.rb +1 -0
- data/test/rubygems/test_gem_gemcutter_utilities.rb +106 -92
- data/test/rubygems/test_gem_impossible_dependencies_error.rb +1 -0
- data/test/rubygems/test_gem_indexer.rb +1 -0
- data/test/rubygems/test_gem_install_update_options.rb +1 -0
- data/test/rubygems/test_gem_installer.rb +2 -1
- data/test/rubygems/test_gem_local_remote_options.rb +1 -0
- data/test/rubygems/test_gem_name_tuple.rb +1 -0
- data/test/rubygems/test_gem_package_old.rb +1 -0
- data/test/rubygems/test_gem_package_tar_header.rb +1 -0
- data/test/rubygems/test_gem_package_tar_reader.rb +1 -0
- data/test/rubygems/test_gem_package_tar_reader_entry.rb +1 -0
- data/test/rubygems/test_gem_package_tar_writer.rb +1 -0
- data/test/rubygems/test_gem_package_task.rb +1 -0
- data/test/rubygems/test_gem_path_support.rb +1 -0
- data/test/rubygems/test_gem_platform.rb +1 -0
- data/test/rubygems/test_gem_rdoc.rb +1 -0
- data/test/rubygems/test_gem_remote_fetcher.rb +1 -0
- data/test/rubygems/test_gem_request.rb +1 -0
- data/test/rubygems/test_gem_request_connection_pools.rb +1 -0
- data/test/rubygems/test_gem_request_set.rb +1 -0
- data/test/rubygems/test_gem_request_set_gem_dependency_api.rb +1 -0
- data/test/rubygems/test_gem_request_set_lockfile.rb +1 -0
- data/test/rubygems/test_gem_request_set_lockfile_parser.rb +1 -0
- data/test/rubygems/test_gem_request_set_lockfile_tokenizer.rb +1 -0
- data/test/rubygems/test_gem_requirement.rb +1 -0
- data/test/rubygems/test_gem_resolver.rb +1 -0
- data/test/rubygems/test_gem_resolver_activation_request.rb +1 -0
- data/test/rubygems/test_gem_resolver_api_set.rb +1 -0
- data/test/rubygems/test_gem_resolver_api_specification.rb +1 -0
- data/test/rubygems/test_gem_resolver_best_set.rb +1 -0
- data/test/rubygems/test_gem_resolver_composed_set.rb +1 -0
- data/test/rubygems/test_gem_resolver_conflict.rb +1 -0
- data/test/rubygems/test_gem_resolver_dependency_request.rb +1 -0
- data/test/rubygems/test_gem_resolver_git_set.rb +1 -0
- data/test/rubygems/test_gem_resolver_git_specification.rb +2 -1
- data/test/rubygems/test_gem_resolver_index_set.rb +1 -0
- data/test/rubygems/test_gem_resolver_index_specification.rb +1 -0
- data/test/rubygems/test_gem_resolver_installed_specification.rb +1 -0
- data/test/rubygems/test_gem_resolver_installer_set.rb +1 -0
- data/test/rubygems/test_gem_resolver_local_specification.rb +1 -0
- data/test/rubygems/test_gem_resolver_lock_set.rb +1 -0
- data/test/rubygems/test_gem_resolver_lock_specification.rb +1 -0
- data/test/rubygems/test_gem_resolver_requirement_list.rb +1 -0
- data/test/rubygems/test_gem_resolver_specification.rb +1 -0
- data/test/rubygems/test_gem_resolver_vendor_set.rb +1 -0
- data/test/rubygems/test_gem_resolver_vendor_specification.rb +1 -0
- data/test/rubygems/test_gem_security.rb +1 -0
- data/test/rubygems/test_gem_security_signer.rb +1 -0
- data/test/rubygems/test_gem_security_trust_dir.rb +1 -0
- data/test/rubygems/test_gem_silent_ui.rb +1 -0
- data/test/rubygems/test_gem_source.rb +1 -0
- data/test/rubygems/test_gem_source_fetch_problem.rb +1 -0
- data/test/rubygems/test_gem_source_git.rb +1 -0
- data/test/rubygems/test_gem_source_installed.rb +1 -0
- data/test/rubygems/test_gem_source_list.rb +1 -0
- data/test/rubygems/test_gem_source_local.rb +1 -0
- data/test/rubygems/test_gem_source_lock.rb +1 -0
- data/test/rubygems/test_gem_source_specific_file.rb +1 -0
- data/test/rubygems/test_gem_source_subpath_problem.rb +1 -0
- data/test/rubygems/test_gem_source_vendor.rb +1 -0
- data/test/rubygems/test_gem_spec_fetcher.rb +1 -0
- data/test/rubygems/test_gem_specification.rb +9 -0
- data/test/rubygems/test_gem_stream_ui.rb +34 -3
- data/test/rubygems/test_gem_stub_specification.rb +1 -0
- data/test/rubygems/test_gem_text.rb +1 -0
- data/test/rubygems/test_gem_uninstaller.rb +1 -0
- data/test/rubygems/test_gem_unsatisfiable_dependency_error.rb +1 -0
- data/test/rubygems/test_gem_update_suggestion.rb +1 -0
- data/test/rubygems/test_gem_uri.rb +2 -0
- data/test/rubygems/test_gem_uri_formatter.rb +1 -0
- data/test/rubygems/test_gem_util.rb +1 -0
- data/test/rubygems/test_gem_version.rb +1 -0
- data/test/rubygems/test_gem_version_option.rb +1 -0
- data/test/rubygems/test_kernel.rb +1 -0
- data/test/rubygems/test_remote_fetch_error.rb +1 -0
- data/test/rubygems/test_require.rb +1 -0
- data/test/rubygems/test_rubygems.rb +2 -0
- data/test/rubygems/test_webauthn_listener.rb +29 -6
- data/test/rubygems/test_webauthn_listener_response.rb +8 -8
- data/test/rubygems/test_webauthn_poller.rb +124 -0
- data/test/rubygems/utilities.rb +1 -0
- data/test/test_changelog_generator.rb +1 -1
- metadata +39 -10
- data/lib/rubygems/webauthn_listener/response.rb +0 -161
- data/lib/rubygems/webauthn_listener.rb +0 -92
@@ -0,0 +1,124 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "helper"
|
4
|
+
require "rubygems/gemcutter_utilities/webauthn_poller"
|
5
|
+
require "rubygems/gemcutter_utilities"
|
6
|
+
|
7
|
+
class WebauthnPollerTest < Gem::TestCase
|
8
|
+
def setup
|
9
|
+
super
|
10
|
+
|
11
|
+
@host = Gem.host
|
12
|
+
@webauthn_url = "#{@host}/api/v1/webauthn_verification/odow34b93t6aPCdY"
|
13
|
+
@fetcher = Gem::FakeFetcher.new
|
14
|
+
Gem::RemoteFetcher.fetcher = @fetcher
|
15
|
+
@credentials = {
|
16
|
+
email: "email@example.com",
|
17
|
+
password: "password",
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_poll_thread_success
|
22
|
+
@fetcher.data["#{@webauthn_url}/status.json"] = Gem::HTTPResponseFactory.create(
|
23
|
+
body: "{\"status\":\"success\",\"code\":\"Uvh6T57tkWuUnWYo\"}",
|
24
|
+
code: 200,
|
25
|
+
msg: "OK"
|
26
|
+
)
|
27
|
+
|
28
|
+
thread = Gem::GemcutterUtilities::WebauthnPoller.poll_thread({}, @host, @webauthn_url, @credentials)
|
29
|
+
thread.join
|
30
|
+
|
31
|
+
assert_equal thread[:otp], "Uvh6T57tkWuUnWYo"
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_poll_thread_webauthn_verification_error
|
35
|
+
@fetcher.data["#{@webauthn_url}/status.json"] = Gem::HTTPResponseFactory.create(
|
36
|
+
body: "HTTP Basic: Access denied.",
|
37
|
+
code: 401,
|
38
|
+
msg: "Unauthorized"
|
39
|
+
)
|
40
|
+
|
41
|
+
thread = Gem::GemcutterUtilities::WebauthnPoller.poll_thread({}, @host, @webauthn_url, @credentials)
|
42
|
+
thread.join
|
43
|
+
|
44
|
+
assert_equal thread[:error].message, "Security device verification failed: Unauthorized"
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_poll_thread_timeout_error
|
48
|
+
raise_error = ->(*_args) { raise Timeout::Error, "execution expired" }
|
49
|
+
Timeout.stub(:timeout, raise_error) do
|
50
|
+
thread = Gem::GemcutterUtilities::WebauthnPoller.poll_thread({}, @host, @webauthn_url, @credentials)
|
51
|
+
thread.join
|
52
|
+
assert_equal thread[:error].message, "execution expired"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_poll_for_otp_success
|
57
|
+
@fetcher.data["#{@webauthn_url}/status.json"] = Gem::HTTPResponseFactory.create(
|
58
|
+
body: "{\"status\":\"success\",\"code\":\"Uvh6T57tkWuUnWYo\"}",
|
59
|
+
code: 200,
|
60
|
+
msg: "OK"
|
61
|
+
)
|
62
|
+
|
63
|
+
otp = Gem::GemcutterUtilities::WebauthnPoller.new({}, @host).poll_for_otp(@webauthn_url, @credentials)
|
64
|
+
|
65
|
+
assert_equal otp, "Uvh6T57tkWuUnWYo"
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_poll_for_otp_pending_sleeps
|
69
|
+
@fetcher.data["#{@webauthn_url}/status.json"] = Gem::HTTPResponseFactory.create(
|
70
|
+
body: "{\"status\":\"pending\",\"message\":\"Security device authentication is still pending.\"}",
|
71
|
+
code: 200,
|
72
|
+
msg: "OK"
|
73
|
+
)
|
74
|
+
|
75
|
+
assert_raise Timeout::Error do
|
76
|
+
Timeout.timeout(0.1) do
|
77
|
+
Gem::GemcutterUtilities::WebauthnPoller.new({}, @host).poll_for_otp(@webauthn_url, @credentials)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_poll_for_otp_not_http_success
|
83
|
+
@fetcher.data["#{@webauthn_url}/status.json"] = Gem::HTTPResponseFactory.create(
|
84
|
+
body: "HTTP Basic: Access denied.",
|
85
|
+
code: 401,
|
86
|
+
msg: "Unauthorized"
|
87
|
+
)
|
88
|
+
|
89
|
+
error = assert_raise Gem::WebauthnVerificationError do
|
90
|
+
Gem::GemcutterUtilities::WebauthnPoller.new({}, @host).poll_for_otp(@webauthn_url, @credentials)
|
91
|
+
end
|
92
|
+
|
93
|
+
assert_equal error.message, "Security device verification failed: Unauthorized"
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_poll_for_otp_invalid_format
|
97
|
+
@fetcher.data["#{@webauthn_url}/status.json"] = Gem::HTTPResponseFactory.create(
|
98
|
+
body: "{}",
|
99
|
+
code: 200,
|
100
|
+
msg: "OK"
|
101
|
+
)
|
102
|
+
|
103
|
+
error = assert_raise Gem::WebauthnVerificationError do
|
104
|
+
Gem::GemcutterUtilities::WebauthnPoller.new({}, @host).poll_for_otp(@webauthn_url, @credentials)
|
105
|
+
end
|
106
|
+
|
107
|
+
assert_equal error.message, "Security device verification failed: Invalid response from server"
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_poll_for_otp_invalid_status
|
111
|
+
@fetcher.data["#{@webauthn_url}/status.json"] = Gem::HTTPResponseFactory.create(
|
112
|
+
body: "{\"status\":\"expired\",\"message\":\"The token in the link you used has either expired or been used already.\"}",
|
113
|
+
code: 200,
|
114
|
+
msg: "OK"
|
115
|
+
)
|
116
|
+
|
117
|
+
error = assert_raise Gem::WebauthnVerificationError do
|
118
|
+
Gem::GemcutterUtilities::WebauthnPoller.new({}, @host).poll_for_otp(@webauthn_url, @credentials)
|
119
|
+
end
|
120
|
+
|
121
|
+
assert_equal error.message,
|
122
|
+
"Security device verification failed: The token in the link you used has either expired or been used already."
|
123
|
+
end
|
124
|
+
end
|
data/test/rubygems/utilities.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubygems-update
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.4.
|
4
|
+
version: 3.4.19
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jim Weirich
|
@@ -14,9 +14,9 @@ authors:
|
|
14
14
|
- Evan Phoenix
|
15
15
|
- Hiroshi SHIBATA
|
16
16
|
autorequire:
|
17
|
-
bindir:
|
17
|
+
bindir: exe
|
18
18
|
cert_chain: []
|
19
|
-
date: 2023-
|
19
|
+
date: 2023-08-17 00:00:00.000000000 Z
|
20
20
|
dependencies: []
|
21
21
|
description: |-
|
22
22
|
A package (also known as a library) contains a set of functionality
|
@@ -39,7 +39,6 @@ executables:
|
|
39
39
|
- update_rubygems
|
40
40
|
extensions: []
|
41
41
|
extra_rdoc_files:
|
42
|
-
- CHANGELOG.md
|
43
42
|
- LICENSE.txt
|
44
43
|
- MAINTAINERS.txt
|
45
44
|
- MIT.txt
|
@@ -49,10 +48,37 @@ extra_rdoc_files:
|
|
49
48
|
- POLICIES.md
|
50
49
|
- CODE_OF_CONDUCT.md
|
51
50
|
- CONTRIBUTING.md
|
52
|
-
- bundler/CHANGELOG.md
|
53
51
|
- bundler/LICENSE.md
|
54
52
|
- bundler/README.md
|
55
53
|
- hide_lib_for_update/note.txt
|
54
|
+
- bundler/lib/bundler/man/bundle-add.1
|
55
|
+
- bundler/lib/bundler/man/bundle-binstubs.1
|
56
|
+
- bundler/lib/bundler/man/bundle-cache.1
|
57
|
+
- bundler/lib/bundler/man/bundle-check.1
|
58
|
+
- bundler/lib/bundler/man/bundle-clean.1
|
59
|
+
- bundler/lib/bundler/man/bundle-config.1
|
60
|
+
- bundler/lib/bundler/man/bundle-console.1
|
61
|
+
- bundler/lib/bundler/man/bundle-doctor.1
|
62
|
+
- bundler/lib/bundler/man/bundle-exec.1
|
63
|
+
- bundler/lib/bundler/man/bundle-gem.1
|
64
|
+
- bundler/lib/bundler/man/bundle-help.1
|
65
|
+
- bundler/lib/bundler/man/bundle-info.1
|
66
|
+
- bundler/lib/bundler/man/bundle-init.1
|
67
|
+
- bundler/lib/bundler/man/bundle-inject.1
|
68
|
+
- bundler/lib/bundler/man/bundle-install.1
|
69
|
+
- bundler/lib/bundler/man/bundle-list.1
|
70
|
+
- bundler/lib/bundler/man/bundle-lock.1
|
71
|
+
- bundler/lib/bundler/man/bundle-open.1
|
72
|
+
- bundler/lib/bundler/man/bundle-outdated.1
|
73
|
+
- bundler/lib/bundler/man/bundle-platform.1
|
74
|
+
- bundler/lib/bundler/man/bundle-plugin.1
|
75
|
+
- bundler/lib/bundler/man/bundle-pristine.1
|
76
|
+
- bundler/lib/bundler/man/bundle-remove.1
|
77
|
+
- bundler/lib/bundler/man/bundle-show.1
|
78
|
+
- bundler/lib/bundler/man/bundle-update.1
|
79
|
+
- bundler/lib/bundler/man/bundle-version.1
|
80
|
+
- bundler/lib/bundler/man/bundle-viz.1
|
81
|
+
- bundler/lib/bundler/man/bundle.1
|
56
82
|
files:
|
57
83
|
- CHANGELOG.md
|
58
84
|
- CODE_OF_CONDUCT.md
|
@@ -64,8 +90,6 @@ files:
|
|
64
90
|
- POLICIES.md
|
65
91
|
- README.md
|
66
92
|
- UPGRADING.md
|
67
|
-
- bin/gem
|
68
|
-
- bin/update_rubygems
|
69
93
|
- bundler/CHANGELOG.md
|
70
94
|
- bundler/LICENSE.md
|
71
95
|
- bundler/README.md
|
@@ -391,6 +415,8 @@ files:
|
|
391
415
|
- bundler/lib/bundler/vlad.rb
|
392
416
|
- bundler/lib/bundler/worker.rb
|
393
417
|
- bundler/lib/bundler/yaml_serializer.rb
|
418
|
+
- exe/gem
|
419
|
+
- exe/update_rubygems
|
394
420
|
- hide_lib_for_update/note.txt
|
395
421
|
- lib/rubygems.rb
|
396
422
|
- lib/rubygems/available_set.rb
|
@@ -459,6 +485,9 @@ files:
|
|
459
485
|
- lib/rubygems/ext/rake_builder.rb
|
460
486
|
- lib/rubygems/gem_runner.rb
|
461
487
|
- lib/rubygems/gemcutter_utilities.rb
|
488
|
+
- lib/rubygems/gemcutter_utilities/webauthn_listener.rb
|
489
|
+
- lib/rubygems/gemcutter_utilities/webauthn_listener/response.rb
|
490
|
+
- lib/rubygems/gemcutter_utilities/webauthn_poller.rb
|
462
491
|
- lib/rubygems/indexer.rb
|
463
492
|
- lib/rubygems/install_default_message.rb
|
464
493
|
- lib/rubygems/install_message.rb
|
@@ -598,8 +627,6 @@ files:
|
|
598
627
|
- lib/rubygems/validator.rb
|
599
628
|
- lib/rubygems/version.rb
|
600
629
|
- lib/rubygems/version_option.rb
|
601
|
-
- lib/rubygems/webauthn_listener.rb
|
602
|
-
- lib/rubygems/webauthn_listener/response.rb
|
603
630
|
- rubygems-update.gemspec
|
604
631
|
- setup.rb
|
605
632
|
- test/rubygems/alternate_cert.pem
|
@@ -639,6 +666,7 @@ files:
|
|
639
666
|
- test/rubygems/invalidchild_cert.pem
|
640
667
|
- test/rubygems/invalidchild_cert_32.pem
|
641
668
|
- test/rubygems/invalidchild_key.pem
|
669
|
+
- test/rubygems/multifactor_auth_utilities.rb
|
642
670
|
- test/rubygems/package/tar_test_case.rb
|
643
671
|
- test/rubygems/packages/Bluebie-legs-0.6.2.gem
|
644
672
|
- test/rubygems/packages/ascii_binder-0.1.10.1.gem
|
@@ -815,6 +843,7 @@ files:
|
|
815
843
|
- test/rubygems/test_rubygems.rb
|
816
844
|
- test/rubygems/test_webauthn_listener.rb
|
817
845
|
- test/rubygems/test_webauthn_listener_response.rb
|
846
|
+
- test/rubygems/test_webauthn_poller.rb
|
818
847
|
- test/rubygems/utilities.rb
|
819
848
|
- test/rubygems/wrong_key_cert.pem
|
820
849
|
- test/rubygems/wrong_key_cert_32.pem
|
@@ -843,7 +872,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
843
872
|
- !ruby/object:Gem::Version
|
844
873
|
version: '0'
|
845
874
|
requirements: []
|
846
|
-
rubygems_version: 3.4.
|
875
|
+
rubygems_version: 3.4.19
|
847
876
|
signing_key:
|
848
877
|
specification_version: 4
|
849
878
|
summary: RubyGems is a package management framework for Ruby. This gem is downloaded
|
@@ -1,161 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
##
|
4
|
-
# The WebauthnListener Response class is used by the WebauthnListener to create
|
5
|
-
# responses to be sent to the Gem host. It creates a Net::HTTPResponse instance
|
6
|
-
# when initialized and can be converted to the appropriate format to be sent by a socket using `to_s`.
|
7
|
-
# Net::HTTPResponse instances cannot be directly sent over a socket.
|
8
|
-
#
|
9
|
-
# Types of response classes:
|
10
|
-
# - OkResponse
|
11
|
-
# - NoContentResponse
|
12
|
-
# - BadRequestResponse
|
13
|
-
# - NotFoundResponse
|
14
|
-
# - MethodNotAllowedResponse
|
15
|
-
#
|
16
|
-
# Example usage:
|
17
|
-
#
|
18
|
-
# server = TCPServer.new(0)
|
19
|
-
# socket = server.accept
|
20
|
-
#
|
21
|
-
# response = OkResponse.for("https://rubygems.example")
|
22
|
-
# socket.print response.to_s
|
23
|
-
# socket.close
|
24
|
-
#
|
25
|
-
|
26
|
-
class Gem::WebauthnListener
|
27
|
-
class Response
|
28
|
-
attr_reader :http_response
|
29
|
-
|
30
|
-
def self.for(host)
|
31
|
-
new(host)
|
32
|
-
end
|
33
|
-
|
34
|
-
def initialize(host)
|
35
|
-
@host = host
|
36
|
-
|
37
|
-
build_http_response
|
38
|
-
end
|
39
|
-
|
40
|
-
def to_s
|
41
|
-
status_line = "HTTP/#{@http_response.http_version} #{@http_response.code} #{@http_response.message}\r\n"
|
42
|
-
headers = @http_response.to_hash.map {|header, value| "#{header}: #{value.join(", ")}\r\n" }.join + "\r\n"
|
43
|
-
body = @http_response.body ? "#{@http_response.body}\n" : ""
|
44
|
-
|
45
|
-
status_line + headers + body
|
46
|
-
end
|
47
|
-
|
48
|
-
private
|
49
|
-
|
50
|
-
# Must be implemented in subclasses
|
51
|
-
def code
|
52
|
-
raise NotImplementedError
|
53
|
-
end
|
54
|
-
|
55
|
-
def reason_phrase
|
56
|
-
raise NotImplementedError
|
57
|
-
end
|
58
|
-
|
59
|
-
def body; end
|
60
|
-
|
61
|
-
def build_http_response
|
62
|
-
response_class = Net::HTTPResponse::CODE_TO_OBJ[code.to_s]
|
63
|
-
@http_response = response_class.new("1.1", code, reason_phrase)
|
64
|
-
@http_response.instance_variable_set(:@read, true)
|
65
|
-
|
66
|
-
add_connection_header
|
67
|
-
add_access_control_headers
|
68
|
-
add_body
|
69
|
-
end
|
70
|
-
|
71
|
-
def add_connection_header
|
72
|
-
@http_response["connection"] = "close"
|
73
|
-
end
|
74
|
-
|
75
|
-
def add_access_control_headers
|
76
|
-
@http_response["access-control-allow-origin"] = @host
|
77
|
-
@http_response["access-control-allow-methods"] = "POST"
|
78
|
-
@http_response["access-control-allow-headers"] = %w[Content-Type Authorization x-csrf-token]
|
79
|
-
end
|
80
|
-
|
81
|
-
def add_body
|
82
|
-
return unless body
|
83
|
-
@http_response["content-type"] = "text/plain"
|
84
|
-
@http_response["content-length"] = body.bytesize
|
85
|
-
@http_response.instance_variable_set(:@body, body)
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
class OkResponse < Response
|
90
|
-
private
|
91
|
-
|
92
|
-
def code
|
93
|
-
200
|
94
|
-
end
|
95
|
-
|
96
|
-
def reason_phrase
|
97
|
-
"OK"
|
98
|
-
end
|
99
|
-
|
100
|
-
def body
|
101
|
-
"success"
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
class NoContentResponse < Response
|
106
|
-
private
|
107
|
-
|
108
|
-
def code
|
109
|
-
204
|
110
|
-
end
|
111
|
-
|
112
|
-
def reason_phrase
|
113
|
-
"No Content"
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
class BadRequestResponse < Response
|
118
|
-
private
|
119
|
-
|
120
|
-
def code
|
121
|
-
400
|
122
|
-
end
|
123
|
-
|
124
|
-
def reason_phrase
|
125
|
-
"Bad Request"
|
126
|
-
end
|
127
|
-
|
128
|
-
def body
|
129
|
-
"missing code parameter"
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
class NotFoundResponse < Response
|
134
|
-
private
|
135
|
-
|
136
|
-
def code
|
137
|
-
404
|
138
|
-
end
|
139
|
-
|
140
|
-
def reason_phrase
|
141
|
-
"Not Found"
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
class MethodNotAllowedResponse < Response
|
146
|
-
private
|
147
|
-
|
148
|
-
def code
|
149
|
-
405
|
150
|
-
end
|
151
|
-
|
152
|
-
def reason_phrase
|
153
|
-
"Method Not Allowed"
|
154
|
-
end
|
155
|
-
|
156
|
-
def add_access_control_headers
|
157
|
-
super
|
158
|
-
@http_response["allow"] = %w[GET OPTIONS]
|
159
|
-
end
|
160
|
-
end
|
161
|
-
end
|
@@ -1,92 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "webauthn_listener/response"
|
4
|
-
|
5
|
-
##
|
6
|
-
# The WebauthnListener class retrieves an OTP after a user successfully WebAuthns with the Gem host.
|
7
|
-
# An instance opens a socket using the TCPServer instance given and listens for a request from the Gem host.
|
8
|
-
# The request should be a GET request to the root path and contains the OTP code in the form
|
9
|
-
# of a query parameter `code`. The listener will return the code which will be used as the OTP for
|
10
|
-
# API requests.
|
11
|
-
#
|
12
|
-
# Types of responses sent by the listener after receiving a request:
|
13
|
-
# - 200 OK: OTP code was successfully retrieved
|
14
|
-
# - 204 No Content: If the request was an OPTIONS request
|
15
|
-
# - 400 Bad Request: If the request did not contain a query parameter `code`
|
16
|
-
# - 404 Not Found: The request was not to the root path
|
17
|
-
# - 405 Method Not Allowed: OTP code was not retrieved because the request was not a GET/OPTIONS request
|
18
|
-
#
|
19
|
-
# Example usage:
|
20
|
-
#
|
21
|
-
# server = TCPServer.new(0)
|
22
|
-
# otp = Gem::WebauthnListener.wait_for_otp_code("https://rubygems.example", server)
|
23
|
-
#
|
24
|
-
|
25
|
-
class Gem::WebauthnListener
|
26
|
-
attr_reader :host
|
27
|
-
|
28
|
-
def initialize(host)
|
29
|
-
@host = host
|
30
|
-
end
|
31
|
-
|
32
|
-
def self.wait_for_otp_code(host, server)
|
33
|
-
new(host).fetch_otp_from_connection(server)
|
34
|
-
end
|
35
|
-
|
36
|
-
def fetch_otp_from_connection(server)
|
37
|
-
loop do
|
38
|
-
socket = server.accept
|
39
|
-
request_line = socket.gets
|
40
|
-
|
41
|
-
method, req_uri, _protocol = request_line.split(" ")
|
42
|
-
req_uri = URI.parse(req_uri)
|
43
|
-
|
44
|
-
responder = SocketResponder.new(socket)
|
45
|
-
|
46
|
-
unless root_path?(req_uri)
|
47
|
-
responder.send(NotFoundResponse.for(host))
|
48
|
-
raise Gem::WebauthnVerificationError, "Page at #{req_uri.path} not found."
|
49
|
-
end
|
50
|
-
|
51
|
-
case method.upcase
|
52
|
-
when "OPTIONS"
|
53
|
-
responder.send(NoContentResponse.for(host))
|
54
|
-
next # will be GET
|
55
|
-
when "GET"
|
56
|
-
if otp = parse_otp_from_uri(req_uri)
|
57
|
-
responder.send(OkResponse.for(host))
|
58
|
-
return otp
|
59
|
-
end
|
60
|
-
responder.send(BadRequestResponse.for(host))
|
61
|
-
raise Gem::WebauthnVerificationError, "Did not receive OTP from #{host}."
|
62
|
-
else
|
63
|
-
responder.send(MethodNotAllowedResponse.for(host))
|
64
|
-
raise Gem::WebauthnVerificationError, "Invalid HTTP method #{method.upcase} received."
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
private
|
70
|
-
|
71
|
-
def root_path?(uri)
|
72
|
-
uri.path == "/"
|
73
|
-
end
|
74
|
-
|
75
|
-
def parse_otp_from_uri(uri)
|
76
|
-
require "cgi"
|
77
|
-
|
78
|
-
return if uri.query.nil?
|
79
|
-
CGI.parse(uri.query).dig("code", 0)
|
80
|
-
end
|
81
|
-
|
82
|
-
class SocketResponder
|
83
|
-
def initialize(socket)
|
84
|
-
@socket = socket
|
85
|
-
end
|
86
|
-
|
87
|
-
def send(response)
|
88
|
-
@socket.print response.to_s
|
89
|
-
@socket.close
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|