diff --git a/CHANGELOG.md b/CHANGELOG.md index 37fd688d..68d4473f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ Changelog ========= +## v6.26.3 (24 January 2024) + +* Handle mailto links in `Cleaner#clean_url` + | [#813](https://github.com/bugsnag/bugsnag-ruby/pull/813) + ## v6.26.2 (17 January 2024) ### Fixes diff --git a/VERSION b/VERSION index dde9f42f..7eeb87d9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.26.2 +6.26.3 diff --git a/lib/bugsnag/cleaner.rb b/lib/bugsnag/cleaner.rb index 600ba8e1..33d0cd09 100644 --- a/lib/bugsnag/cleaner.rb +++ b/lib/bugsnag/cleaner.rb @@ -30,25 +30,19 @@ def clean_url(url) begin uri = URI(url) - rescue URI::InvalidURIError - pre_query_string, _query_string = url.split('?', 2) - - return "#{pre_query_string}?#{FILTERED}" - end - return url unless uri.query - - query_params = uri.query.split('&').map { |pair| pair.split('=') } - query_params.map! do |key, val| - if filters_match?(key) - "#{key}=#{FILTERED}" + if uri.is_a?(URI::MailTo) + clean_mailto_url(url, uri) else - "#{key}=#{val}" + clean_generic_url(url, uri) end - end + rescue URI::InvalidURIError + pre_query_string, _query_string = url.split('?', 2) - uri.query = query_params.join('&') - uri.to_s + "#{pre_query_string}?#{FILTERED}" + rescue StandardError + FILTERED + end end ## @@ -209,5 +203,33 @@ def scope_should_be_filtered?(scope) scope.start_with?("#{scope_to_filter}.") end end + + def clean_generic_url(original_url, uri) + return original_url unless uri.query + + query_params = uri.query.split('&').map { |pair| pair.split('=') } + + uri.query = filter_uri_parameter_array(query_params).join('&') + uri.to_s + end + + def clean_mailto_url(original_url, uri) + return original_url unless uri.headers + + # headers in mailto links can't contain square brackets so we replace + # filtered parameters with 'FILTERED' instead of '[FILTERED]' + uri.headers = filter_uri_parameter_array(uri.headers, 'FILTERED').join('&') + uri.to_s + end + + def filter_uri_parameter_array(parameters, replacement = FILTERED) + parameters.map do |key, value| + if filters_match?(key) + "#{key}=#{replacement}" + else + "#{key}=#{value}" + end + end + end end end diff --git a/spec/cleaner_spec.rb b/spec/cleaner_spec.rb index f6908dbe..417ff7b5 100644 --- a/spec/cleaner_spec.rb +++ b/spec/cleaner_spec.rb @@ -552,5 +552,29 @@ def to_s let(:url) { "https://host.example/a b c d e f g" } it { should eq "https://host.example/a b c d e f g" } end + + context "with a mailto URL" do + let(:filters) { [/token/] } + let(:url) { "mailto:hello@example.com?token=secret&subject=Hello" } + it { should eq "mailto:hello@example.com?token=FILTERED&subject=Hello" } + end + + context "with a mailto URL without a to address" do + let(:filters) { [/token/] } + let(:url) { "mailto:?subject=Hello&token=password" } + it { should eq "mailto:?subject=Hello&token=FILTERED" } + end + + context "with a websocket URL" do + let(:filters) { [/secret/] } + let(:url) { "ws://example.com?abc=xyz&secret=password" } + it { should eq "ws://example.com?abc=xyz&secret=[FILTERED]" } + end + + context "with a websocket over TLS URL" do + let(:filters) { [/secret/] } + let(:url) { "wss://example.com?abc=xyz&secret=password" } + it { should eq "wss://example.com?abc=xyz&secret=[FILTERED]" } + end end end