Skip to content

Commit

Permalink
[rubygems/rubygems] Introduce Gem::PrintableUri that would redact U…
Browse files Browse the repository at this point in the history
…RIs 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`

rubygems/rubygems@f1e45d3a89
  • Loading branch information
daniel-niknam authored and hsbt committed Aug 31, 2021
1 parent 14a9e24 commit b418024
Show file tree
Hide file tree
Showing 2 changed files with 197 additions and 0 deletions.
81 changes: 81 additions & 0 deletions lib/rubygems/printable_uri.rb
@@ -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
116 changes: 116 additions & 0 deletions test/rubygems/test_gem_printable_uri.rb
@@ -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

0 comments on commit b418024

Please sign in to comment.