From d06cefae02a940f1bfba4e2cf931fe83cd88cf9c Mon Sep 17 00:00:00 2001 From: Alexander Kireev Date: Fri, 3 Jul 2026 08:53:36 +0700 Subject: [PATCH] Fix Wildcard#match? matching the rule value with no wildcard label A wildcard rule like *.com requires an extra label before it, but Rule::Base#match? was chomping the value off and calling it a match whenever the diff was empty - so match?("com") returned true for the *.com rule, same as it would for a plain "com" rule. There's actually a FIXME comment marking this exact case in the tests already. Added a Wildcard#match? override that requires the extra label (i.e. the diff must end with a dot, not just be empty), and uncommented/ extended the test case. --- lib/public_suffix/rule.rb | 15 +++++++++++++++ test/unit/rule_test.rb | 17 +++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/lib/public_suffix/rule.rb b/lib/public_suffix/rule.rb index 27c04ac..e021d36 100644 --- a/lib/public_suffix/rule.rb +++ b/lib/public_suffix/rule.rb @@ -241,6 +241,21 @@ def rule value == "" ? STAR : STAR + DOT + value end + # Checks if this rule matches +name+. + # + # Unlike {Base#match?}, an exact match against +value+ is not enough, + # because the wildcard label requires an additional leading label + # to be present in +name+. For example, "*.com" doesn't match "com", + # only names with at least one label before it (e.g. "example.com"). + # + # @param name [String] the domain name to check + # @return [Boolean] + def match?(name) + return super if value == "" + + name.chomp(value).end_with?(DOT) + end + # Decomposes the domain name according to rule properties. # # @param domain [#to_s] The domain name to decompose diff --git a/test/unit/rule_test.rb b/test/unit/rule_test.rb index 2490919..fa06cb5 100644 --- a/test/unit/rule_test.rb +++ b/test/unit/rule_test.rb @@ -89,10 +89,11 @@ def test_match_standard def test_match_wildcard_and_exception [ - # FIXME - # [PublicSuffix::Rule.factory("*.com"), "com", false], + [PublicSuffix::Rule.factory("*.com"), "com", false], [PublicSuffix::Rule.factory("*.com"), "example.com", true], [PublicSuffix::Rule.factory("*.com"), "foo.example.com", true], + [PublicSuffix::Rule.factory("*.co.uk"), "co.uk", false], + [PublicSuffix::Rule.factory("*.co.uk"), "example.co.uk", true], [PublicSuffix::Rule.factory("!example.com"), "com", false], [PublicSuffix::Rule.factory("!example.com"), "example.com", true], [PublicSuffix::Rule.factory("!example.com"), "foo.example.com", true], @@ -243,6 +244,18 @@ def test_parts assert_equal %w[co uk], @klass.build("*.co.uk").parts end + def test_match + # the wildcard label requires an extra leading label in the input, + # so the rule's own value alone must not match + [ + ["uk", false], + ["google.uk", true], + ["foo.google.uk", true], + ].each do |input, expected| + assert_equal expected, @klass.build("*.uk").match?(input) + end + end + def test_decompose assert_equal [nil, nil], @klass.build("*.do").decompose("nic.do") assert_equal %w[google co.uk], @klass.build("*.uk").decompose("google.co.uk")