[rubygems/rubygems] Introduce `Gem::PrintableUri` that would redact URIs to be used on outputs

We need to redact URI credential in several places and copy pasting the code into each part of it is not ideal. This class is responsible for parsing URI strings and redacting credential from it. Also, it will handle URI object in the same manner. We will be reusing this class whenever we need to print/display a URI to users.
URI with the following format will be redacted:
- Token: `http://my-secure-token@example.com` => `http://REDACTED@example.com`
- Username & Password: `http://my-username:my-secure-password@example.com` => `http://my-username:REDACTED@example.com`
- x-oauth-basic: `http://my-secure-token:x-oauth-basic@example.com` => `http://REDACTED:x-oauth-basic@example.com`

https://github.com/rubygems/rubygems/commit/f1e45d3a89
This commit is contained in:
Daniel Niknam 2021-08-22 01:31:03 +10:00 коммит произвёл Hiroshi SHIBATA
Родитель 14a9e24f7e
Коммит b41802421a
2 изменённых файлов: 197 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,81 @@
# frozen_string_literal: true
require 'uri'
require_relative 'uri_parser'
class Gem::PrintableUri
def self.parse_uri(uri)
new(uri).parse_uri
end
def initialize(original_uri)
@credential_redacted = false
@original_uri = original_uri
end
def parse_uri
@original_uri = Gem::UriParser.parse_uri(@original_uri)
@uri = @original_uri.clone
redact_credential
self
end
def parsed_uri?
@uri.is_a? URI::Generic
end
def credential_redacted?
@credential_redacted
end
def original_password
return unless parsed_uri?
@original_uri.password
end
def to_s
@uri.to_s
end
private
def redact_credential
return unless redactable_credential?
if token?
@uri.user = 'REDACTED'
elsif oauth_basic?
@uri.user = 'REDACTED'
elsif password?
@uri.password = 'REDACTED' if password?
end
@credential_redacted = true
end
def redactable_credential?
return false unless parsed_uri?
password? || oauth_basic? || token?
end
def password?
return false unless parsed_uri?
!!@uri.password
end
def oauth_basic?
return false unless parsed_uri?
@uri.password == 'x-oauth-basic'
end
def token?
return false unless parsed_uri?
!@uri.user.nil? && @uri.password.nil?
end
end

Просмотреть файл

@ -0,0 +1,116 @@
require_relative 'helper'
require 'uri'
require 'rubygems/printable_uri'
class TestPrintableUri < Gem::TestCase
def test_parsed_uri
assert_equal true, Gem::PrintableUri.parse_uri("https://www.example.com").parsed_uri?
end
def test_parsed_uri_with_empty_uri_object
assert_equal true, Gem::PrintableUri.parse_uri(URI("")).parsed_uri?
end
def test_parsed_uri_with_valid_uri_object
assert_equal true, Gem::PrintableUri.parse_uri(URI("https://www.example.com")).parsed_uri?
end
def test_parsed_uri_with_other_objects
assert_equal false, Gem::PrintableUri.parse_uri(Object.new).parsed_uri?
end
def test_parsed_uri_with_invalid_uri
assert_equal false, Gem::PrintableUri.parse_uri("https://www.example.com:80index").parsed_uri?
end
def test_credential_redacted_with_user_pass
assert_equal true, Gem::PrintableUri.parse_uri("https://user:pass@example.com").credential_redacted?
end
def test_credential_redacted_with_token
assert_equal true, Gem::PrintableUri.parse_uri("https://token@example.com").credential_redacted?
end
def test_credential_redacted_with_user_x_oauth_basic
assert_equal true, Gem::PrintableUri.parse_uri("https://token:x-oauth-basic@example.com").credential_redacted?
end
def test_credential_redacted_without_credential
assert_equal false, Gem::PrintableUri.parse_uri("https://www.example.com").credential_redacted?
end
def test_credential_redacted_with_empty_uri_object
assert_equal false, Gem::PrintableUri.parse_uri(URI("")).credential_redacted?
end
def test_credential_redacted_with_valid_uri_object
assert_equal true, Gem::PrintableUri.parse_uri(URI("https://user:pass@example.com")).credential_redacted?
end
def test_credential_redacted_with_other_objects
assert_equal false, Gem::PrintableUri.parse_uri(Object.new).credential_redacted?
end
def test_original_password_user_pass
assert_equal "pass", Gem::PrintableUri.parse_uri("https://user:pass@example.com").original_password
end
def test_original_password_with_token
assert_equal nil, Gem::PrintableUri.parse_uri("https://token@example.com").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_original_password_with_invalid_uri
assert_equal nil, Gem::PrintableUri.parse_uri("https://www.example.com:80index").original_password
end
def test_original_password_with_empty_uri_object
assert_equal nil, Gem::PrintableUri.parse_uri(URI("")).original_password
end
def test_original_password_with_valid_uri_object
assert_equal "pass", Gem::PrintableUri.parse_uri(URI("https://user:pass@example.com")).original_password
end
def test_original_password_with_other_objects
assert_equal nil, Gem::PrintableUri.parse_uri(Object.new).original_password
end
def test_to_s_with_user_pass
assert_equal "https://user:REDACTED@example.com", Gem::PrintableUri.parse_uri("https://user:pass@example.com").to_s
end
def test_to_s_with_token
assert_equal "https://REDACTED@example.com", Gem::PrintableUri.parse_uri("https://token@example.com").to_s
end
def test_to_s_with_user_x_oauth_basic
assert_equal "https://REDACTED:x-oauth-basic@example.com", Gem::PrintableUri.parse_uri("https://token:x-oauth-basic@example.com").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
def test_to_s_with_empty_uri_object
assert_equal "", Gem::PrintableUri.parse_uri(URI("")).to_s
end
def test_to_s_with_valid_uri_object
assert_equal "https://user:REDACTED@example.com", Gem::PrintableUri.parse_uri(URI("https://user:pass@example.com")).to_s
end
def test_to_s_with_other_objects
obj = Object.new
obj.stub(:to_s, "my-to-s") do
assert_equal "my-to-s", Gem::PrintableUri.parse_uri(obj).to_s
end
end
end