File Coverage

blib/lib/Mail/Milter/Authentication/Handler/SenderID.pm
Criterion Covered Total %
statement 57 84 67.8
branch 21 28 75.0
condition 1 3 33.3
subroutine 14 16 87.5
pod 1 9 11.1
total 94 140 67.1


line stmt bran cond sub pod time code
1             package Mail::Milter::Authentication::Handler::SenderID;
2 34     34   17119 use 5.20.0;
  34         195  
3 34     34   221 use strict;
  34         108  
  34         961  
4 34     34   244 use warnings;
  34         111  
  34         1097  
5 34     34   278 use Mail::Milter::Authentication::Pragmas;
  34         151  
  34         329  
6             # ABSTRACT: Handler class for SenderID
7             our $VERSION = '3.20230629'; # VERSION
8 34     34   8685 use base 'Mail::Milter::Authentication::Handler';
  34         130  
  34         3642  
9 34     34   9219 use Mail::Milter::Authentication::Handler::SPF;
  34         118  
  34         1069  
10 34     34   277 use Mail::SPF;
  34         113  
  34         31452  
11              
12             sub default_config {
13             return {
14 0     0 0 0 'hide_none' => 1,
15             };
16             }
17              
18             sub grafana_rows {
19 0     0 0 0 my ( $self ) = @_;
20 0         0 my @rows;
21 0         0 push @rows, $self->get_json( 'SenderID_metrics' );
22 0         0 return \@rows;
23             }
24              
25             sub setup_callback {
26 69     69 0 413 my ( $self ) = @_;
27             # Call connect_callback from SPF handler to setup object creation
28             # Required if SenderID is enabled but SPF is disabled.
29 69         508 return Mail::Milter::Authentication::Handler::SPF::setup_callback( $self );
30             }
31              
32             sub register_metrics {
33             return {
34 33     33 1 322 'senderid_total' => 'The number of emails processed for Sender ID',
35             };
36             }
37              
38             sub helo_callback {
39 74     74 0 398 my ( $self, $helo_host ) = @_;
40 74         389 $self->{'helo_name'} = $helo_host;
41             }
42              
43             sub envfrom_callback {
44 74     74 0 405 my ( $self, $env_from ) = @_;
45 74 100       605 return if ( $self->is_local_ip_address() );
46 66 100       502 return if ( $self->is_trusted_ip_address() );
47 64 50       474 return if ( $self->is_authenticated() );
48 64         438 delete $self->{'from_header'};
49             }
50              
51             sub header_callback {
52 875     875 0 2898 my ( $self, $header, $value ) = @_;
53 875 100       2933 return if ( $self->is_local_ip_address() );
54 758 100       2513 return if ( $self->is_trusted_ip_address() );
55 728 50       2446 return if ( $self->is_authenticated() );
56 728 100       3236 if ( lc $header eq 'from' ) {
57 66         419 $self->{'from_header'} = $value;
58             }
59             }
60              
61             sub eoh_callback {
62 74     74 0 336 my ($self) = @_;
63 74         476 my $config = $self->handler_config();
64 74 100       488 return if ( $self->is_local_ip_address() );
65 66 100       504 return if ( $self->is_trusted_ip_address() );
66 64 50       457 return if ( $self->is_authenticated() );
67              
68 64         545 my $spf_server = $self->get_object('spf_server');
69 64 50       380 if ( ! $spf_server ) {
70 0         0 $self->log_error( 'SenderID Setup Error' );
71 0         0 my $header = Mail::AuthenticationResults::Header::Entry->new()->set_key( 'senderid' )->safe_set_value( 'temperror' );
72 0         0 $self->add_auth_header($header);
73 0         0 $self->metric_count( 'senderid_total', { 'result' => 'error' } );
74 0         0 return;
75             }
76              
77 64         314 my $scope = 'pra';
78              
79 64         456 my $identity = $self->get_address_from( $self->{'from_header'} );
80              
81 64 50       360 if ( ! $identity ) {
82 0         0 $self->log_error( 'SENDERID Error No Identity' );
83 0         0 my $header = Mail::AuthenticationResults::Header::Entry->new()->set_key( 'senderid' )->safe_set_value( 'permerror' );
84 0         0 $self->add_auth_header( $header );
85 0         0 $self->metric_count( 'senderid_total', { 'result' => 'permerror' } );
86 0         0 return;
87             }
88              
89 64         194 eval {
90             my $spf_request = Mail::SPF::Request->new(
91             'versions' => [2],
92             'scope' => $scope,
93             'identity' => $identity,
94             'ip_address' => $self->ip_address(),
95 64         569 'helo_identity' => $self->{'helo_name'},
96             );
97              
98 64         63727 my $spf_result = $spf_server->process($spf_request);
99              
100 64         181318 my $result_code = $spf_result->code();
101 64         698 $self->metric_count( 'senderid_total', {'result' => $result_code } );
102 64         593 $self->dbgout( 'SenderIdCode', $result_code, LOG_DEBUG );
103              
104 64 50 33     1276 if ( ! ( $config->{'hide_none'} && $result_code eq 'none' ) ) {
105 0         0 my $auth_header = Mail::AuthenticationResults::Header::Entry->new()->set_key( 'senderid' )->safe_set_value( $result_code );
106 0         0 $self->add_auth_header( $auth_header );
107             #my $result_local = $spf_result->local_explanation;
108             #my $result_auth = $spf_result->can( 'authority_explanation' ) ? $spf_result->authority_explanation() : '';
109 0         0 my $result_header = $spf_result->received_spf_header();
110 0         0 my ( $header, $value ) = split( ': ', $result_header, 2 );
111 0         0 $self->prepend_header( $header, $value );
112 0         0 $self->dbgout( 'SPFHeader', $result_header, LOG_DEBUG );
113             }
114             };
115 64 50       478 if ( my $error = $@ ) {
116 0         0 $self->handle_exception( $error );
117 0         0 $self->log_error( 'SENDERID Error ' . $error );
118 0         0 $self->metric_count( 'senderid_total', { 'result' => 'error' } );
119 0         0 my $header = Mail::AuthenticationResults::Header::Entry->new()->set_key( 'senderid' )->safe_set_value( 'temperror' );
120 0         0 $self->add_auth_header($header);
121 0         0 return;
122             }
123             }
124              
125             sub close_callback {
126 117     117 0 425 my ( $self ) = @_;
127 117         410 delete $self->{'from_header'};
128 117         430 delete $self->{'helo_name'};
129             }
130              
131             1;
132              
133             __END__
134              
135             =pod
136              
137             =encoding UTF-8
138              
139             =head1 NAME
140              
141             Mail::Milter::Authentication::Handler::SenderID - Handler class for SenderID
142              
143             =head1 VERSION
144              
145             version 3.20230629
146              
147             =head1 DESCRIPTION
148              
149             Implements the SenderID standard checks.
150              
151             =head1 CONFIGURATION
152              
153             "SenderID" : { | Config for the SenderID Module
154             "hide_none" : 1 | Hide auth line if the result is 'none'
155             },
156              
157             =head1 AUTHOR
158              
159             Marc Bradshaw <marc@marcbradshaw.net>
160              
161             =head1 COPYRIGHT AND LICENSE
162              
163             This software is copyright (c) 2020 by Marc Bradshaw.
164              
165             This is free software; you can redistribute it and/or modify it under
166             the same terms as the Perl 5 programming language system itself.
167              
168             =cut