line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# <@LICENSE> |
2
|
|
|
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
3
|
|
|
|
|
|
|
# you may not use this file except in compliance with the License. |
4
|
|
|
|
|
|
|
# You may obtain a copy of the License at |
5
|
|
|
|
|
|
|
# |
6
|
|
|
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0 |
7
|
|
|
|
|
|
|
# |
8
|
|
|
|
|
|
|
# Unless required by applicable law or agreed to in writing, software |
9
|
|
|
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS, |
10
|
|
|
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
11
|
|
|
|
|
|
|
# See the License for the specific language governing permissions and |
12
|
|
|
|
|
|
|
# limitations under the License. |
13
|
|
|
|
|
|
|
# @LICENSE> |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
package Mail::SpamAssassin::Plugin::Konfidi; |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
=head1 NAME |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
Mail::SpamAssassin::Plugin::Konfidi - A SpamAssassin plugin that uses the Konfidi distributed trust network for authenticated messages. |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
=head1 VERSION |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
Version 1.0.1 |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
=cut |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
our $VERSION = '1.0.1'; |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=head1 SYNOPSIS |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
Install this module by running: |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
cpan Mail::SpamAssassin::Plugin::Konfidi |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
Tell SpamAssassin to use it by putting the following (from this module's F) in a configuration file |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
loadplugin Mail::SpamAssassin::Plugin::Konfidi |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
Configure the plugin by putting the following (from this module's F) in a configuration file (see L) |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
ifplugin Mail::SpamAssassin::Plugin::Konfidi |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
full KONFIDI_TRUST_VALUE eval:check_konfidi() |
44
|
|
|
|
|
|
|
describe KONFIDI_TRUST_VALUE Konfidi-computed trust value for sender, if sender is authenticated |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
endif # Mail::SpamAssassin::Plugin::Konfidi |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
Set settings for yourself: |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
konfidi_service_url http://test-server.konfidi.org/ |
51
|
|
|
|
|
|
|
konfidi_my_pgp_fingerprint 1234DEADBEEF5678... # this should be your full 40-digit fingerprint |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
konfidi_rating0_becomes_score 0 |
54
|
|
|
|
|
|
|
konfidi_rating1_becomes_score -20 |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
The rating-becomes-score settings define a linear scale, so using the above example, a Konfidi rating of 0.75 would generate a SpamAssassin score of -15. You do not set any regular 'score' rules since the scores are assigned dynamically based on these settings. |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
=head1 DESCRIPTION |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
This plugin currently only uses OpenPGP signatures for authentication and requires L. Future versions will also support L and |
61
|
|
|
|
|
|
|
L for authentication. |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
The loadplugin statement for OpenPGP must occur before the loadplugin statement for Konfidi. This can be done by putting them in order in one file, or naming your configuration files in order like 26_openpgp.cf and 61_konfidi.cf |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
For project information, see L |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
=head1 USER SETTINGS |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
If you want to add a header that shows the Konfidi trust value, use this: |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
add_header all Konfidi-Trust-Value _KONFIDITRUSTVALUE_ |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
=cut |
74
|
|
|
|
|
|
|
|
75
|
2
|
|
|
2
|
|
302491
|
use warnings; |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
98
|
|
76
|
2
|
|
|
2
|
|
12
|
use strict; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
120
|
|
77
|
2
|
|
|
2
|
|
1173
|
use Mail::SpamAssassin::Plugin; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
use Mail::SpamAssassin::Logger; |
79
|
|
|
|
|
|
|
use Mail::SpamAssassin::Timeout; |
80
|
|
|
|
|
|
|
use Konfidi::Client; |
81
|
|
|
|
|
|
|
use Error qw(:try); |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
use vars qw(@ISA); |
84
|
|
|
|
|
|
|
@ISA = qw(Mail::SpamAssassin::Plugin); |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
sub new { |
87
|
|
|
|
|
|
|
my $class = shift; |
88
|
|
|
|
|
|
|
my $mailsaobject = shift; |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
# some boilerplate... |
91
|
|
|
|
|
|
|
$class = ref($class) || $class; |
92
|
|
|
|
|
|
|
my $self = $class->SUPER::new($mailsaobject); |
93
|
|
|
|
|
|
|
bless ($self, $class); |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
dbg "konfidi: created"; |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
$self->register_eval_rule ("check_konfidi"); |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
$self->{konfidi_client} = Konfidi::Client->new(); |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
$self->set_config($mailsaobject->{conf}); |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
return $self; |
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
# SA 3.1 style of parsing config options |
107
|
|
|
|
|
|
|
sub set_config { |
108
|
|
|
|
|
|
|
my($self, $conf) = @_; |
109
|
|
|
|
|
|
|
my @cmds = (); |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
# see Mail::SpamAssassin::Conf::Parser for expected format of the "config blocks" stored in @cmds |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
push(@cmds, { |
114
|
|
|
|
|
|
|
setting => 'konfidi_service_url', |
115
|
|
|
|
|
|
|
default => 'http://test-server.konfidi.org/', |
116
|
|
|
|
|
|
|
type => $Mail::SpamAssassin::Conf::CONF_TYPE_STRING, |
117
|
|
|
|
|
|
|
}); |
118
|
|
|
|
|
|
|
push(@cmds, { |
119
|
|
|
|
|
|
|
setting => 'konfidi_my_pgp_fingerprint', |
120
|
|
|
|
|
|
|
#default => 'http://test-server.konfidi.org/', |
121
|
|
|
|
|
|
|
type => $Mail::SpamAssassin::Conf::CONF_TYPE_STRING, |
122
|
|
|
|
|
|
|
}); |
123
|
|
|
|
|
|
|
#TODO: make this required |
124
|
|
|
|
|
|
|
# TODO validate format |
125
|
|
|
|
|
|
|
push(@cmds, { |
126
|
|
|
|
|
|
|
setting => 'konfidi_rating1_becomes_score', |
127
|
|
|
|
|
|
|
default => 0, |
128
|
|
|
|
|
|
|
type => $Mail::SpamAssassin::Conf::CONF_TYPE_NUMERIC, |
129
|
|
|
|
|
|
|
}); |
130
|
|
|
|
|
|
|
push(@cmds, { |
131
|
|
|
|
|
|
|
setting => 'konfidi_rating0_becomes_score', |
132
|
|
|
|
|
|
|
default => 0, |
133
|
|
|
|
|
|
|
type => $Mail::SpamAssassin::Conf::CONF_TYPE_NUMERIC, |
134
|
|
|
|
|
|
|
}); |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
# grr, why isn't register_commands documented? |
137
|
|
|
|
|
|
|
$conf->{parser}->register_commands(\@cmds); |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
# FIXME: validate that this gets set |
140
|
|
|
|
|
|
|
$self->{konfidi_client}->server($conf->{konfidi_service_url}); |
141
|
|
|
|
|
|
|
} |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
# see http://wiki.apache.org/spamassassin/PluginWritingTips "Writing plugins with dynamic score rules" |
144
|
|
|
|
|
|
|
sub check_konfidi { |
145
|
|
|
|
|
|
|
my ($self, $scan) = @_; |
146
|
|
|
|
|
|
|
dbg "konfidi: running check_konfidi"; |
147
|
|
|
|
|
|
|
if ($scan->{openpgp_signed_good}) { |
148
|
|
|
|
|
|
|
# FIXME: timeouts, ala http://wiki.apache.org/spamassassin/iXhash |
149
|
|
|
|
|
|
|
my $kr; |
150
|
|
|
|
|
|
|
try { |
151
|
|
|
|
|
|
|
$kr = $self->{konfidi_client}->query($scan->{conf}->{konfidi_my_pgp_fingerprint}, $scan->{openpgp_fingerprint}, 'http://www.konfidi.org/ns/topics/0.0#internet-communication'); |
152
|
|
|
|
|
|
|
dbg "konfidi: response value: " . $kr->{'Rating'}; |
153
|
|
|
|
|
|
|
} catch Konfidi::Client::Error with { |
154
|
|
|
|
|
|
|
my $E = shift; |
155
|
|
|
|
|
|
|
dbg "konfidi: couldn't query the trustserver: $E"; |
156
|
|
|
|
|
|
|
# for some reason this doesn't exit the sub??? |
157
|
|
|
|
|
|
|
return 0; |
158
|
|
|
|
|
|
|
}; |
159
|
|
|
|
|
|
|
return 0 unless $kr; |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
# convert [0,1] rating to SA score |
162
|
|
|
|
|
|
|
my $score = $scan->{conf}->{konfidi_rating0_becomes_score} - $kr->{'Rating'} * |
163
|
|
|
|
|
|
|
($scan->{conf}->{konfidi_rating0_becomes_score} - $scan->{conf}->{konfidi_rating1_becomes_score}); |
164
|
|
|
|
|
|
|
dbg "konfidi: scoring " . sprintf("%0.3f", $score); |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
# http://wiki.apache.org/spamassassin/PluginWritingTips dynamic score rules |
167
|
|
|
|
|
|
|
$scan->got_hit("KONFIDI_TRUST_VALUE", "KONFIDI: ", ruletype => 'eval', score => $score); |
168
|
|
|
|
|
|
|
for my $set (0..3) { |
169
|
|
|
|
|
|
|
$scan->{conf}->{scoreset}->[$set]->{"KONFIDI_TRUST_VALUE"} = sprintf("%0.3f", $score); |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
# "KONFIDI" as $area? |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
# Mail::SpamAssassin::Plugin::AWL 3.1.7 line 387 |
174
|
|
|
|
|
|
|
# $scan->_handle_hit("KONFIDI_TRUST_VALUE", $score, "KONFIDI: ", $scan->{conf}->{descriptions}->{KONFIDI_TRUST_VALUE}); |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
$scan->set_tag("KONFIDITRUSTVALUE", $kr->{'Rating'}); |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
} else { |
179
|
|
|
|
|
|
|
dbg "konfidi: skipping message, did not have a good PGP signature (make sure Mail::SpamAssassin::Plugin::OpenPGP is in use)"; |
180
|
|
|
|
|
|
|
} |
181
|
|
|
|
|
|
|
return 0; |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
# http://mail-archives.apache.org/mod_mbox/spamassassin-dev/200707.mbox/%3c46AFF6EC.3090404@brondsema.net%3e |
185
|
|
|
|
|
|
|
#~ sub parsed_metadata { |
186
|
|
|
|
|
|
|
#~ my ($self, $opts) = @_; |
187
|
|
|
|
|
|
|
#~ return if $self->{main}->{local_tests_only}; |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
#~ my $scan = $opts->{permsgstatus} or die "No scanner!"; |
190
|
|
|
|
|
|
|
#~ dbg "konfidi: parsed_metadata: " . $scan->{openpgp_signed}; |
191
|
|
|
|
|
|
|
#~ #$self->_karma_send($scanner); |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
#~ return undef; |
194
|
|
|
|
|
|
|
#~ } |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
#~ # "This is a good place to harvest your own asynchronously-started network lookups." |
197
|
|
|
|
|
|
|
#~ # http://search.cpan.org/~shevek/Mail-Karmasphere-Client-2.10/lib/Mail/SpamAssassin/Plugin/Karmasphere.pm#INTERNALS |
198
|
|
|
|
|
|
|
#~ sub check_post_dnsbl { |
199
|
|
|
|
|
|
|
#~ my ($self, $opts) = @_; |
200
|
|
|
|
|
|
|
#~ return if $self->{main}->{local_tests_only}; |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
#~ my $scan = $opts->{permsgstatus} or die "No scanner!"; |
203
|
|
|
|
|
|
|
#~ dbg "konfidi: check_post_dnsbl: " . $scan->{openpgp_signed}; |
204
|
|
|
|
|
|
|
#~ } |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
1; # End of Mail::SpamAssassin::Plugin::Konfidi |
207
|
|
|
|
|
|
|
__END__ |