You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spamassassin.apache.org by gb...@apache.org on 2025/06/10 07:35:09 UTC
svn commit: r1926307 - in /spamassassin/trunk: lib/Mail/SpamAssassin/Plugin/HashBL.pm lib/Mail/SpamAssassin/Plugin/ReplaceTags.pm t/data/spam/hashbl t/hashbl.t
Author: gbechis
Date: Tue Jun 10 07:35:09 2025
New Revision: 1926307
URL: http://svn.apache.org/viewvc?rev=1926307&view=rev
Log:
use replacetags from HashBL plugin, by enabling the new "replace" option in "check_hashbl_bodyre",
tags in the regexp will be replaced with the original char
Modified:
spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/HashBL.pm
spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/ReplaceTags.pm
spamassassin/trunk/t/data/spam/hashbl
spamassassin/trunk/t/hashbl.t
Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/HashBL.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/HashBL.pm?rev=1926307&r1=1926306&r2=1926307&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/HashBL.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/HashBL.pm Tue Jun 10 07:35:09 2025
@@ -162,6 +162,10 @@ Additional supported OPTS:
num remove the chars from the match that are not numbers
+ replace if a regexp contains replace tags, replace the match of the regexp with the first option
+ of the regexp, ex. +1 8O8.l23.4567 will be changed to +1 808.123.4567
+ For the subsitution to work, replace tags must contain only single chars.
+
Optional subtest regexp to match DNS answer (default: '^127\.').
=back
@@ -239,7 +243,7 @@ use strict;
use warnings;
use re 'taint';
-my $VERSION = 0.101;
+my $VERSION = 0.102;
use Digest::MD5 qw(md5_hex);
use Digest::SHA qw(sha1_hex sha256);
@@ -740,6 +744,23 @@ sub check_hashbl_bodyre {
warn "HashBL: $rulename missing body regex\n";
return 0;
}
+
+ my $conf = $pms->{conf};
+ dbg("using regexp $re");
+ my $orig_re = $re;
+ my $replaced_regexp = 0;
+
+ # replace regexp matches only if requested
+ if(exists $conf->{plugins_loaded}{'Mail::SpamAssassin::Plugin::ReplaceTags'}) {
+ if(exists($conf->{replace_rules}->{$rulename})) {
+ $re = Mail::SpamAssassin::Plugin::ReplaceTags->replace_regexp($re, $conf);
+ if(defined $re and ($orig_re ne $re)) {
+ dbg("regexp $orig_re replaced with $re");
+ $replaced_regexp = 1;
+ }
+ }
+ }
+
my ($rec, $err) = compile_regexp($re, 0);
if (!$rec) {
warn "HashBL: $rulename invalid body regex: $@\n";
@@ -769,6 +790,12 @@ sub check_hashbl_bodyre {
while ($body =~ /$re/gs) {
next if !defined $1;
my $match = $opts->{case} ? $1 : lc($1);
+ # Check if ReplaceTags plugin is enabled
+ if(exists $conf->{plugins_loaded}{'Mail::SpamAssassin::Plugin::ReplaceTags'}) {
+ if($replaced_regexp and $opts->{replace}) {
+ $match = Mail::SpamAssassin::Plugin::ReplaceTags->replace_result($orig_re, $match, $conf);
+ }
+ }
if($opts->{num}) {
$match =~ tr/0-9//cd;
}
@@ -781,6 +808,12 @@ sub check_hashbl_bodyre {
while ($$bodyref =~ /$re/gs) {
next if !defined $1;
my $match = $opts->{case} ? $1 : lc($1);
+ # Check if ReplaceTags plugin is enabled
+ if(exists $conf->{plugins_loaded}{'Mail::SpamAssassin::Plugin::ReplaceTags'}) {
+ if($replaced_regexp and $opts->{replace}) {
+ $match = Mail::SpamAssassin::Plugin::ReplaceTags->replace_result($orig_re, $match, $conf);
+ }
+ }
if($opts->{num}) {
$match =~ tr/0-9//cd;
}
@@ -1112,6 +1145,7 @@ sub _finish_query {
# Version features
sub has_hashbl_bodyre { 1 }
sub has_hashbl_bodyre_num { 1 }
+sub has_hashbl_bodyre_replace { 1 }
sub has_hashbl_emails { 1 }
sub has_hashbl_uris { 1 }
sub has_hashbl_ignore { 1 }
Modified: spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/ReplaceTags.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/ReplaceTags.pm?rev=1926307&r1=1926306&r2=1926307&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/ReplaceTags.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/Plugin/ReplaceTags.pm Tue Jun 10 07:35:09 2025
@@ -83,15 +83,132 @@ sub finish_parsing_start {
return 1;
}
+sub replace_regexp {
+ my ($self, $re, $conf) = @_;
+
+ my $passes = 0;
+ my $doagain;
+ my $start = $conf->{replace_start};
+ my $end = $conf->{replace_end};
+
+ do {
+ my $pre_name;
+ my $post_name;
+ my $inter_name;
+ $doagain = 0;
+
+ # get modifier tags
+ if ($re =~ s/${start}pre (.+?)${end}//) {
+ $pre_name = $1;
+ }
+ if ($re =~ s/${start}post (.+?)${end}//) {
+ $post_name = $1;
+ }
+ if ($re =~ s/${start}inter (.+?)${end}//) {
+ $inter_name = $1;
+ }
+
+ # this will produce an array of tags to be replaced
+ # for two adjacent tags, an element of "" will be between the two
+ my @re = split(/(<[^<>]+>)/, $re);
+
+ if ($pre_name) {
+ my $pre = $conf->{replace_pre}->{$pre_name};
+ if ($pre) {
+ s{($start.+?$end)}{$pre$1} for @re;
+ }
+ }
+ if ($post_name) {
+ my $post = $conf->{replace_post}->{$post_name};
+ if ($post) {
+ s{($start.+?$end)}{$1$post}g for @re;
+ }
+ }
+ if ($inter_name) {
+ my $inter = $conf->{replace_inter}->{$inter_name};
+ if ($inter) {
+ s{^$}{$inter} for @re;
+ }
+ }
+ for (my $i = 0; $i < @re; $i++) {
+ if ($re[$i] =~ m|$start(.+?)$end|g) {
+ my $tag_name = $1;
+ # if the tag exists, replace it with the corresponding phrase
+ if ($tag_name) {
+ my $replacement = $conf->{replace_tag}->{$tag_name};
+ if ($replacement) {
+ $re[$i] =~ s|$start$tag_name$end|$replacement|g;
+ $doagain = 1 if !$doagain && $replacement =~ /<[^>]+>/;
+ }
+ }
+ }
+ }
+
+ $re = join('', @re);
+
+ $passes++;
+ } while $doagain && $passes <= 5;
+ return $re;
+}
+
+sub replace_result {
+ my ($self, $re, $match, $conf) = @_;
+
+ my $pre_name;
+ my $post_name;
+ my $inter_name;
+ my $start = $conf->{replace_start};
+ my $end = $conf->{replace_end};
+
+ my @re = split(/(<[^<>]+>)/, $re);
+
+ if ($pre_name) {
+ my $pre = $conf->{replace_pre}->{$pre_name};
+ if ($pre) {
+ s{($start.+?$end)}{$pre$1} for @re;
+ }
+ }
+ if ($post_name) {
+ my $post = $conf->{replace_post}->{$post_name};
+ if ($post) {
+ s{($start.+?$end)}{$1$post}g for @re;
+ }
+ }
+ if ($inter_name) {
+ my $inter = $conf->{replace_inter}->{$inter_name};
+ if ($inter) {
+ s{^$}{$inter} for @re;
+ }
+ }
+ for (my $i = 0; $i < @re; $i++) {
+ if ($re[$i] =~ m|$start(.+?)$end|g) {
+ my $tag_name = $1;
+ # if the tag exists, replace it with the corresponding phrase
+ if ($tag_name) {
+ my $replacement = $conf->{replace_tag}->{$tag_name};
+ if (defined $replacement) {
+ if($replacement =~ /^\(\?\:(.{1})/) {
+ my $subst = $1;
+ my ($rec, $err) = compile_regexp($replacement, 0);
+ if(!$rec) {
+ dbg("Invalid regexp $replacement");
+ return;
+ }
+ $match =~ s/$rec/$subst/g;
+ }
+ }
+ }
+ }
+ }
+ return $match;
+}
+
sub finish_parsing_end {
my ($self, $opts) = @_;
dbg("replacetags: replacing tags");
my $conf = $opts->{conf};
- my $start = $conf->{replace_start};
- my $end = $conf->{replace_end};
-
foreach my $rule (keys %{$conf->{replace_rules}}) {
# process rules only once, mark to replace_rules_done,
# do NOT delete $conf->{replace_rules}, it's used by BodyRuleExtractor
@@ -99,76 +216,19 @@ sub finish_parsing_end {
$self->{replace_rules_done}->{$rule} = 1;
if (!exists $conf->{test_qrs}->{$rule}) {
- dbg("replacetags: replace requested for non-existing or incompatible rule: $rule\n");
+ # HashBL rules will substitute "replace_tag" on a different code path
+ dbg("replacetags: replace requested for non-existing or incompatible/HashBL rule: $rule\n");
next;
}
my $re = qr_to_string($conf->{test_qrs}->{$rule});
next unless defined $re;
- my $origre = $re;
- my $passes = 0;
- my $doagain;
-
- do {
- my $pre_name;
- my $post_name;
- my $inter_name;
- $doagain = 0;
-
- # get modifier tags
- if ($re =~ s/${start}pre (.+?)${end}//) {
- $pre_name = $1;
- }
- if ($re =~ s/${start}post (.+?)${end}//) {
- $post_name = $1;
- }
- if ($re =~ s/${start}inter (.+?)${end}//) {
- $inter_name = $1;
- }
-
- # this will produce an array of tags to be replaced
- # for two adjacent tags, an element of "" will be between the two
- my @re = split(/(<[^<>]+>)/, $re);
-
- if ($pre_name) {
- my $pre = $conf->{replace_pre}->{$pre_name};
- if ($pre) {
- s{($start.+?$end)}{$pre$1} for @re;
- }
- }
- if ($post_name) {
- my $post = $conf->{replace_post}->{$post_name};
- if ($post) {
- s{($start.+?$end)}{$1$post}g for @re;
- }
- }
- if ($inter_name) {
- my $inter = $conf->{replace_inter}->{$inter_name};
- if ($inter) {
- s{^$}{$inter} for @re;
- }
- }
- for (my $i = 0; $i < @re; $i++) {
- if ($re[$i] =~ m|$start(.+?)$end|g) {
- my $tag_name = $1;
- # if the tag exists, replace it with the corresponding phrase
- if ($tag_name) {
- my $replacement = $conf->{replace_tag}->{$tag_name};
- if ($replacement) {
- $re[$i] =~ s|$start$tag_name$end|$replacement|g;
- $doagain = 1 if !$doagain && $replacement =~ /<[^>]+>/;
- }
- }
- }
- }
-
- $re = join('', @re);
+ my $origre = $re;
- $passes++;
- } while $doagain && $passes <= 5;
+ $re = $self->replace_regexp($re, $conf);
- if ($re ne $origre) {
+ if (defined $re and ($re ne $origre)) {
# do the actual replacement
my ($rec, $err) = compile_regexp($re, 0);
if (!$rec) {
Modified: spamassassin/trunk/t/data/spam/hashbl
URL: http://svn.apache.org/viewvc/spamassassin/trunk/t/data/spam/hashbl?rev=1926307&r1=1926306&r2=1926307&view=diff
==============================================================================
--- spamassassin/trunk/t/data/spam/hashbl (original)
+++ spamassassin/trunk/t/data/spam/hashbl Tue Jun 10 07:35:09 2025
@@ -41,6 +41,8 @@ email host/domain userpart@host.domain.c
telephone: +1(123)123-4567
+telephone: +1(l23)l23-4S67
+
--ETDFsshmzrOmOVdZ
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="macro.xlsm"
Modified: spamassassin/trunk/t/hashbl.t
URL: http://svn.apache.org/viewvc/spamassassin/trunk/t/hashbl.t?rev=1926307&r1=1926306&r2=1926307&view=diff
==============================================================================
--- spamassassin/trunk/t/hashbl.t (original)
+++ spamassassin/trunk/t/hashbl.t Tue Jun 10 07:35:09 2025
@@ -9,7 +9,7 @@ plan skip_all => "Can't use Net::DNS Saf
# run many times to catch some random natured failures
my $iterations = 5;
-plan tests => 13 * $iterations;
+plan tests => 14 * $iterations;
# ---------------------------------------------------------------------------
@@ -18,6 +18,7 @@ plan tests => 13 * $iterations;
q{ 1.0 X_HASHBL_OSENDR } => '',
q{ 1.0 X_HASHBL_BTC } => '',
q{ 1.0 X_HASHBL_NUM } => '',
+ q{ 1.0 X_HASHBL_ONUM } => '',
q{ 1.0 X_HASHBL_URI } => '',
q{ 1.0 X_HASHBL_TAG } => '',
q{ 1.0 META_HASHBL_EMAIL } => '',
@@ -83,6 +84,11 @@ sub check_queries {
return !%invalid;
}
+tstpre(q{
+loadplugin Mail::SpamAssassin::Plugin::HashBL
+loadplugin Mail::SpamAssassin::Plugin::ReplaceTags
+});
+
tstlocalrules(q{
rbl_timeout 30
@@ -102,6 +108,20 @@ tstlocalrules(q{
body X_HASHBL_NUM eval:check_hashbl_bodyre('hashbltest9.spamassassin.org', 'raw/max=10/shuffle/num', '\b(?:\+)?(?:\s)?((?:[0-9]{1,2})?(?:\s)?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6})\b', '127.0.0.2')
tflags X_HASHBL_NUM net
+ replace_tag N0 (?:0|O)
+ replace_tag N1 (?:1|l)
+ replace_tag N2 (?:2)
+ replace_tag N3 (?:3)
+ replace_tag N4 (?:4)
+ replace_tag N5 (?:5|S)
+ replace_tag N6 (?:6)
+ replace_tag N7 (?:7)
+ replace_tag N8 (?:8)
+ replace_tag N9 (?:9)
+ replace_rules X_HASHBL_ONUM
+ body X_HASHBL_ONUM eval:check_hashbl_bodyre('hashbltest9.spamassassin.org', 'raw/max=10/shuffle/num/case/replace', '(?<!\d)((?:<N1>[^a-zA-Z0-9]*)?(?:<N0>|<N1>|<N2>|<N3>|<N4>|<N5>|<N6>|<N7>|<N8>|<N9>){3}[^a-zA-Z0-9]+(?:<N0>|<N1>|<N2>|<N3>|<N4>|<N5>|<N6>|<N7>|<N8>|<N9>){3}[^a-zA-Z0-9]+(?:<N0>|<N1>|<N2>|<N3>|<N4>|<N5>|<N6>|<N7>|<N8>|<N9>){4,6})(?!\d)', '127.0.0.2')
+ tflags X_HASHBL_ONUM net
+
# Not supposed to hit, @valid_queries just checks that sha256 is calculated correctly
body X_HASHBL_SHA256 eval:check_hashbl_bodyre('hashbltest3.spamassassin.org', 'sha256/max=10/shuffle', '\b([13][a-km-zA-HJ-NP-Z1-9]{25,34})\b')
tflags X_HASHBL_SHA256 net