summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Rodríguez <[email protected]>2021-08-24 12:02:29 +0200
committerHiroshi SHIBATA <[email protected]>2021-08-31 19:06:14 +0900
commit1e290c31f4fdfd330b9cd1d5c7fe61efa4ab066c (patch)
tree0d3e58f3df45c7ab430375fe27550db6f6df6a65
parentf0c6cc14b10616a61d3113dd5a88291fe915461b (diff)
[rubygems/rubygems] Merge `Gem::UriParser` and `Gem::PrintableUri` into a `Gem::Uri` class
The new class is a wrapper on top of an URI. And then, when you want credentials redacted, you call `#redacted` that returns a copy of itself, but with credentials redacted. https://github.com/rubygems/rubygems/commit/9581c2740a
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/4789
-rw-r--r--lib/rubygems/commands/install_command.rb5
-rw-r--r--lib/rubygems/printable_uri.rb61
-rw-r--r--lib/rubygems/remote_fetcher.rb17
-rw-r--r--lib/rubygems/request.rb3
-rw-r--r--lib/rubygems/uri.rb102
-rw-r--r--lib/rubygems/uri_parser.rb42
-rw-r--r--test/rubygems/test_gem_printable_uri.rb44
-rw-r--r--test/rubygems/test_gem_uri.rb32
-rw-r--r--test/rubygems/test_gem_uri_parser.rb17
9 files changed, 145 insertions, 178 deletions
diff --git a/lib/rubygems/commands/install_command.rb b/lib/rubygems/commands/install_command.rb
index ee50cba472..adf2cdba84 100644
--- a/lib/rubygems/commands/install_command.rb
+++ b/lib/rubygems/commands/install_command.rb
@@ -5,7 +5,6 @@ require_relative '../dependency_installer'
require_relative '../local_remote_options'
require_relative '../validator'
require_relative '../version_option'
-require_relative '../printable_uri'
##
# Gem installer command line tool
@@ -261,8 +260,8 @@ You can use `i` command instead of `install`.
errors.each do |x|
return unless Gem::SourceFetchProblem === x
- printable_uri = Gem::PrintableUri.parse_uri(x.source.uri.clone)
- msg = "Unable to pull data from '#{printable_uri}': #{x.error.message}"
+ require_relative "../uri"
+ msg = "Unable to pull data from '#{Gem::Uri.new(x.source.uri).redacted}': #{x.error.message}"
alert_warning msg
end
diff --git a/lib/rubygems/printable_uri.rb b/lib/rubygems/printable_uri.rb
deleted file mode 100644
index 93c852e268..0000000000
--- a/lib/rubygems/printable_uri.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-# frozen_string_literal: true
-
-require_relative 'uri_parser'
-
-class Gem::PrintableUri
- def self.parse_uri(uri)
- printable_uri = new(uri)
- printable_uri.parse_uri
-
- printable_uri
- end
-
- def initialize(original_uri)
- @original_uri = original_uri
- end
-
- def parse_uri
- @original_uri = Gem::UriParser.parse_uri(@original_uri)
- @uri = @original_uri.dup
- redact_credential if valid_uri?
- end
-
- def valid_uri?
- @uri.respond_to?(:user) &&
- @uri.respond_to?(:user=) &&
- @uri.respond_to?(:password) &&
- @uri.respond_to?(:password=)
- end
-
- def original_password
- @original_uri.password
- end
-
- def to_s
- @uri.to_s
- end
-
- private
-
- def redact_credential
- if token?
- @uri.user = 'REDACTED'
- elsif oauth_basic?
- @uri.user = 'REDACTED'
- elsif password?
- @uri.password = 'REDACTED'
- end
- end
-
- def password?
- end
-
- def oauth_basic?
- @uri.password == 'x-oauth-basic'
- end
-
- def token?
- [email protected]? && @uri.password.nil?
- end
-end
diff --git a/lib/rubygems/remote_fetcher.rb b/lib/rubygems/remote_fetcher.rb
index 33c02b46f6..0724a51ee0 100644
--- a/lib/rubygems/remote_fetcher.rb
+++ b/lib/rubygems/remote_fetcher.rb
@@ -4,8 +4,7 @@ require_relative 'request'
require_relative 'request/connection_pools'
require_relative 's3_uri_signer'
require_relative 'uri_formatter'
-require_relative 'uri_parser'
-require_relative 'printable_uri'
+require_relative 'uri'
require_relative 'user_interaction'
##
@@ -26,12 +25,12 @@ class Gem::RemoteFetcher
attr_accessor :uri, :original_uri
def initialize(message, uri)
- @original_uri = uri.dup
- uri = Gem::PrintableUri.parse_uri(uri)
+ uri = Gem::Uri.new(uri)
- super(uri.valid_uri? && uri.original_password ? message.sub(uri.original_password, 'REDACTED') : message)
+ super uri.redact_credentials_from(message)
- @uri = uri.to_s
+ @original_uri = uri.to_s
+ @uri = uri.redacted.to_s
end
def to_s # :nodoc:
@@ -127,7 +126,7 @@ class Gem::RemoteFetcher
require "fileutils"
FileUtils.mkdir_p cache_dir rescue nil unless File.exist? cache_dir
- source_uri = Gem::UriParser.parse_uri(source_uri)
+ source_uri = Gem::Uri.new(source_uri)
scheme = source_uri.scheme
@@ -222,7 +221,7 @@ class Gem::RemoteFetcher
unless location = response['Location']
raise FetchError.new("redirecting but no redirect location was given", uri)
end
- location = Gem::UriParser.parse_uri location
+ location = Gem::Uri.new location
if https?(uri) && !https?(location)
raise FetchError.new("redirecting to non-https resource: #{location}", uri)
@@ -240,7 +239,7 @@ class Gem::RemoteFetcher
# Downloads +uri+ and returns it as a String.
def fetch_path(uri, mtime = nil, head = false)
- uri = Gem::UriParser.parse_uri uri
+ uri = Gem::Uri.new uri
unless uri.scheme
raise ArgumentError, "uri scheme is invalid: #{uri.scheme.inspect}"
diff --git a/lib/rubygems/request.rb b/lib/rubygems/request.rb
index fdc4c55da0..72e25e20ab 100644
--- a/lib/rubygems/request.rb
+++ b/lib/rubygems/request.rb
@@ -184,7 +184,6 @@ class Gem::Request
def perform_request(request) # :nodoc:
connection = connection_for @uri
- uri = Gem::PrintableUri.parse_uri(@uri)
retried = false
bad_response = false
@@ -192,7 +191,7 @@ class Gem::Request
begin
@requests[connection.object_id] += 1
- verbose "#{request.method} #{uri}"
+ verbose "#{request.method} #{Gem::Uri.new(@uri).redacted}"
file_name = File.basename(@uri.path)
# perform download progress reporter only for gems
diff --git a/lib/rubygems/uri.rb b/lib/rubygems/uri.rb
new file mode 100644
index 0000000000..031d7e01c3
--- /dev/null
+++ b/lib/rubygems/uri.rb
@@ -0,0 +1,102 @@
+# frozen_string_literal: true
+
+##
+# The Uri handles rubygems source URIs.
+#
+
+class Gem::Uri
+ def initialize(source_uri)
+ @parsed_uri = parse(source_uri)
+ end
+
+ def redacted
+ return self unless valid_uri?
+
+ if token? || oauth_basic?
+ with_redacted_user
+ elsif password?
+ with_redacted_password
+ else
+ self
+ end
+ end
+
+ def to_s
+ @parsed_uri.to_s
+ end
+
+ def redact_credentials_from(text)
+ return text unless valid_uri? && password?
+
+ text.sub(password, 'REDACTED')
+ end
+
+ def method_missing(method_name, *args, &blk)
+ if @parsed_uri.respond_to?(method_name)
+ @parsed_uri.send(method_name, *args, &blk)
+ else
+ super
+ end
+ end
+
+ def respond_to_missing?(method_name, include_private = false)
+ @parsed_uri.respond_to?(method_name, include_private) || super
+ end
+
+ private
+
+ ##
+ # Parses the #uri, raising if it's invalid
+
+ def parse!(uri)
+ require "uri"
+
+ raise URI::InvalidURIError unless uri
+
+ # Always escape URI's to deal with potential spaces and such
+ # It should also be considered that source_uri may already be
+ # a valid URI with escaped characters. e.g. "{DESede}" is encoded
+ # as "%7BDESede%7D". If this is escaped again the percentage
+ # symbols will be escaped.
+ begin
+ URI.parse(uri)
+ rescue URI::InvalidURIError
+ URI.parse(URI::DEFAULT_PARSER.escape(uri))
+ end
+ end
+
+ ##
+ # Parses the #uri, returning the original uri if it's invalid
+
+ def parse(uri)
+ return uri unless uri.is_a?(String)
+
+ parse!(uri)
+ rescue URI::InvalidURIError
+ uri
+ end
+
+ def with_redacted_user
+ clone.tap {|uri| uri.user = 'REDACTED' }
+ end
+
+ def with_redacted_password
+ clone.tap {|uri| uri.password = 'REDACTED' }
+ end
+
+ def valid_uri?
+ !@parsed_uri.is_a?(String)
+ end
+
+ def password?
+ !!password
+ end
+
+ def oauth_basic?
+ password == 'x-oauth-basic'
+ end
+
+ def token?
+ !user.nil? && password.nil?
+ end
+end
diff --git a/lib/rubygems/uri_parser.rb b/lib/rubygems/uri_parser.rb
deleted file mode 100644
index f51d77a4af..0000000000
--- a/lib/rubygems/uri_parser.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-# frozen_string_literal: true
-
-##
-# The UriParser handles parsing URIs.
-#
-
-class Gem::UriParser
- def self.parse_uri(source_uri)
- return source_uri unless source_uri.is_a?(String)
-
- new.parse(source_uri)
- end
-
- ##
- # Parses the #uri, raising if it's invalid
-
- def parse!(uri)
- require "uri"
-
- raise URI::InvalidURIError unless uri
-
- # Always escape URI's to deal with potential spaces and such
- # It should also be considered that source_uri may already be
- # a valid URI with escaped characters. e.g. "{DESede}" is encoded
- # as "%7BDESede%7D". If this is escaped again the percentage
- # symbols will be escaped.
- begin
- URI.parse(uri)
- rescue URI::InvalidURIError
- URI.parse(URI::DEFAULT_PARSER.escape(uri))
- end
- end
-
- ##
- # Parses the #uri, returning the original uri if it's invalid
-
- def parse(uri)
- parse!(uri)
- rescue URI::InvalidURIError
- uri
- end
-end
diff --git a/test/rubygems/test_gem_printable_uri.rb b/test/rubygems/test_gem_printable_uri.rb
deleted file mode 100644
index 6d4be6efc2..0000000000
--- a/test/rubygems/test_gem_printable_uri.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-require_relative 'helper'
-require 'rubygems/printable_uri'
-
-class TestPrintableUri < Gem::TestCase
- def test_parsed_uri
- assert_equal true, Gem::PrintableUri.parse_uri("https://www.example.com").valid_uri?
- end
-
- def test_valid_uri_with_invalid_uri
- assert_equal false, Gem::PrintableUri.parse_uri("https://www.example.com:80index").valid_uri?
- end
-
- def test_original_password_user_pass
- assert_equal "pass", Gem::PrintableUri.parse_uri("https://user:[email protected]").original_password
- end
-
- def test_original_password_with_token
- assert_equal nil, Gem::PrintableUri.parse_uri("https://[email protected]").original_password
- end
-
- def test_original_password_without_credential
- assert_equal nil, Gem::PrintableUri.parse_uri("https://www.example.com").original_password
- end
-
- def test_to_s_with_user_pass
- assert_equal "https://user:[email protected]", Gem::PrintableUri.parse_uri("https://user:[email protected]").to_s
- end
-
- def test_to_s_with_token
- assert_equal "https://[email protected]", Gem::PrintableUri.parse_uri("https://[email protected]").to_s
- end
-
- def test_to_s_with_user_x_oauth_basic
- assert_equal "https://REDACTED:[email protected]", Gem::PrintableUri.parse_uri("https://token:[email protected]").to_s
- end
-
- def test_to_s_without_credential
- assert_equal "https://www.example.com", Gem::PrintableUri.parse_uri("https://www.example.com").to_s
- end
-
- def test_to_s_with_invalid_uri
- assert_equal "https://www.example.com:80index", Gem::PrintableUri.parse_uri("https://www.example.com:80index").to_s
- end
-end
diff --git a/test/rubygems/test_gem_uri.rb b/test/rubygems/test_gem_uri.rb
new file mode 100644
index 0000000000..0c70443f32
--- /dev/null
+++ b/test/rubygems/test_gem_uri.rb
@@ -0,0 +1,32 @@
+require_relative 'helper'
+require 'rubygems/uri'
+
+class TestUri < Gem::TestCase
+ def test_to_s_not_string
+ assert_equal "not_a_uri", Gem::Uri.new(:not_a_uri).to_s
+ end
+
+ def test_to_s_invalid_uri
+ assert_equal "https://www.example.com:80index", Gem::Uri.new("https://www.example.com:80index").to_s
+ end
+
+ def test_redacted_with_user_pass
+ assert_equal "https://user:[email protected]", Gem::Uri.new("https://user:[email protected]").redacted.to_s
+ end
+
+ def test_redacted_with_token
+ assert_equal "https://[email protected]", Gem::Uri.new("https://[email protected]").redacted.to_s
+ end
+
+ def test_redacted_with_user_x_oauth_basic
+ assert_equal "https://REDACTED:[email protected]", Gem::Uri.new("https://token:[email protected]").redacted.to_s
+ end
+
+ def test_redacted_without_credential
+ assert_equal "https://www.example.com", Gem::Uri.new("https://www.example.com").redacted.to_s
+ end
+
+ def test_redacted_with_invalid_uri
+ assert_equal "https://www.example.com:80index", Gem::Uri.new("https://www.example.com:80index").redacted.to_s
+ end
+end
diff --git a/test/rubygems/test_gem_uri_parser.rb b/test/rubygems/test_gem_uri_parser.rb
deleted file mode 100644
index 095b193666..0000000000
--- a/test/rubygems/test_gem_uri_parser.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require_relative 'helper'
-require 'uri'
-require 'rubygems/uri_parser'
-
-class TestUriParser < Gem::TestCase
- def test_parse_uri_none_string
- assert_equal :not_a_uri, Gem::UriParser.parse_uri(:not_a_uri)
- end
-
- def test_parse_uri_invalid_uri
- assert_equal "https://www.example.com:80index", Gem::UriParser.parse_uri("https://www.example.com:80index")
- end
-
- def test_parse_uri
- assert_equal URI::HTTPS, Gem::UriParser.parse_uri("https://www.example.com").class
- end
-end