schleuder 2.2.4 → 3.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +138 -0
- data/Rakefile +136 -0
- data/bin/pinentry-clearpassphrase +72 -0
- data/bin/schleuder +9 -89
- data/bin/schleuder-api-daemon +4 -0
- data/db/migrate/20140501103532_create_lists.rb +39 -0
- data/db/migrate/20140501112859_create_subscriptions.rb +21 -0
- data/db/migrate/201508092100_add_language_to_lists.rb +11 -0
- data/db/migrate/20150812165700_change_keywords_admin_only_defaults.rb +8 -0
- data/db/migrate/20150813235800_add_forward_all_incoming_to_admins.rb +11 -0
- data/db/migrate/201508141727_change_send_encrypted_only_default.rb +8 -0
- data/db/migrate/201508222143_add_logfiles_to_keep_to_lists.rb +11 -0
- data/db/migrate/201508261723_rename_delivery_disabled_to_delivery_enabled_and_change_default.rb +14 -0
- data/db/migrate/201508261815_strip_gpg_passphrase.rb +11 -0
- data/db/migrate/201508261827_remove_default_mime.rb +9 -0
- data/db/migrate/20160501172700_fix_headers_to_meta_defaults.rb +8 -0
- data/db/migrate/20170713215059_add_internal_footer_to_list.rb +11 -0
- data/db/schema.rb +62 -0
- data/etc/init.d/schleuder-api-daemon +87 -0
- data/etc/list-defaults.yml +123 -0
- data/etc/postfix/schleuder_sqlite.cf +28 -0
- data/etc/schleuder-api-daemon.service +10 -0
- data/etc/schleuder.cron.weekly +6 -0
- data/etc/schleuder.yml +61 -0
- data/lib/schleuder-api-daemon.rb +420 -0
- data/lib/schleuder.rb +81 -47
- data/lib/schleuder/cli.rb +334 -0
- data/lib/schleuder/cli/cert.rb +24 -0
- data/lib/schleuder/cli/schleuder_cert_manager.rb +84 -0
- data/lib/schleuder/cli/subcommand_fix.rb +11 -0
- data/lib/schleuder/conf.rb +131 -0
- data/lib/schleuder/errors/active_model_error.rb +15 -0
- data/lib/schleuder/errors/base.rb +17 -0
- data/lib/schleuder/errors/decryption_failed.rb +16 -0
- data/lib/schleuder/errors/fatal_error.rb +13 -0
- data/lib/schleuder/errors/file_not_found.rb +14 -0
- data/lib/schleuder/errors/invalid_listname.rb +13 -0
- data/lib/schleuder/errors/key_adduid_failed.rb +13 -0
- data/lib/schleuder/errors/key_generation_failed.rb +16 -0
- data/lib/schleuder/errors/keyword_admin_only.rb +13 -0
- data/lib/schleuder/errors/list_exists.rb +13 -0
- data/lib/schleuder/errors/list_not_found.rb +14 -0
- data/lib/schleuder/errors/list_property_missing.rb +14 -0
- data/lib/schleuder/errors/listdir_problem.rb +16 -0
- data/lib/schleuder/errors/loading_list_settings_failed.rb +14 -0
- data/lib/schleuder/errors/message_empty.rb +14 -0
- data/lib/schleuder/errors/message_not_from_admin.rb +13 -0
- data/lib/schleuder/errors/message_sender_not_subscribed.rb +13 -0
- data/lib/schleuder/errors/message_too_big.rb +14 -0
- data/lib/schleuder/errors/message_unauthenticated.rb +13 -0
- data/lib/schleuder/errors/message_unencrypted.rb +13 -0
- data/lib/schleuder/errors/message_unsigned.rb +13 -0
- data/lib/schleuder/errors/standard_error.rb +5 -0
- data/lib/schleuder/errors/too_many_keys.rb +17 -0
- data/lib/schleuder/errors/unknown_list_option.rb +14 -0
- data/lib/schleuder/filters/auth_filter.rb +39 -0
- data/lib/schleuder/filters/bounces_filter.rb +12 -0
- data/lib/schleuder/filters/forward_filter.rb +17 -0
- data/lib/schleuder/filters/forward_incoming.rb +13 -0
- data/lib/schleuder/filters/hotmail_message_filter.rb +25 -0
- data/lib/schleuder/filters/max_message_size.rb +14 -0
- data/lib/schleuder/filters/request_filter.rb +26 -0
- data/lib/schleuder/filters/send_key_filter.rb +20 -0
- data/lib/schleuder/filters/strip_alternative_filter.rb +21 -0
- data/lib/schleuder/filters_runner.rb +83 -0
- data/lib/schleuder/gpgme/ctx.rb +274 -0
- data/lib/schleuder/gpgme/import_status.rb +27 -0
- data/lib/schleuder/gpgme/key.rb +212 -0
- data/lib/schleuder/gpgme/sub_key.rb +13 -0
- data/lib/schleuder/gpgme/user_id.rb +22 -0
- data/lib/schleuder/list.rb +318 -127
- data/lib/schleuder/list_builder.rb +139 -0
- data/lib/schleuder/listlogger.rb +31 -0
- data/lib/schleuder/logger.rb +23 -0
- data/lib/schleuder/logger_notifications.rb +69 -0
- data/lib/schleuder/mail/message.rb +482 -0
- data/lib/schleuder/mail/parts_list.rb +9 -0
- data/lib/schleuder/plugin_runners/base.rb +91 -0
- data/lib/schleuder/plugin_runners/list_plugins_runner.rb +24 -0
- data/lib/schleuder/plugin_runners/request_plugins_runner.rb +27 -0
- data/lib/schleuder/plugins/attach_listkey.rb +17 -0
- data/lib/schleuder/plugins/get_version.rb +7 -0
- data/lib/schleuder/plugins/key_management.rb +113 -0
- data/lib/schleuder/plugins/list_management.rb +15 -0
- data/lib/schleuder/plugins/resend.rb +196 -0
- data/lib/schleuder/plugins/sign_this.rb +46 -0
- data/lib/schleuder/plugins/subscription_management.rb +140 -0
- data/lib/schleuder/runner.rb +130 -0
- data/lib/schleuder/subscription.rb +98 -0
- data/lib/schleuder/validators/boolean_validator.rb +7 -0
- data/lib/schleuder/validators/email_validator.rb +7 -0
- data/lib/schleuder/validators/fingerprint_validator.rb +7 -0
- data/lib/schleuder/validators/greater_than_zero_validator.rb +7 -0
- data/lib/schleuder/validators/no_line_breaks_validator.rb +7 -0
- data/lib/schleuder/version.rb +1 -1
- data/locales/de.yml +179 -0
- data/locales/en.yml +179 -0
- metadata +305 -108
- checksums.yaml.gz.sig +0 -3
- data.tar.gz.sig +0 -2
- data/LICENSE +0 -339
- data/README +0 -32
- data/bin/schleuder-fix-gem-dependencies +0 -37
- data/bin/schleuder-init-setup +0 -37
- data/bin/schleuder-migrate-v2.1-to-v2.2 +0 -225
- data/bin/schleuder-newlist +0 -413
- data/contrib/check-expired-keys.rb +0 -60
- data/contrib/mutt-schleuder-colors.rc +0 -10
- data/contrib/mutt-schleuder-resend.vim +0 -24
- data/contrib/smtpserver.rb +0 -76
- data/ext/default-list.conf +0 -149
- data/ext/default-members.conf +0 -7
- data/ext/list.conf.example +0 -14
- data/ext/schleuder.conf +0 -64
- data/lib/schleuder/archiver.rb +0 -46
- data/lib/schleuder/crypt.rb +0 -210
- data/lib/schleuder/errors.rb +0 -5
- data/lib/schleuder/list_config.rb +0 -146
- data/lib/schleuder/log/listlogger.rb +0 -57
- data/lib/schleuder/log/outputter/emailoutputter.rb +0 -120
- data/lib/schleuder/log/outputter/metaemailoutputter.rb +0 -50
- data/lib/schleuder/log/schleuderlogger.rb +0 -34
- data/lib/schleuder/mail.rb +0 -873
- data/lib/schleuder/mailer.rb +0 -26
- data/lib/schleuder/member.rb +0 -69
- data/lib/schleuder/plugin.rb +0 -54
- data/lib/schleuder/processor.rb +0 -363
- data/lib/schleuder/schleuder_config.rb +0 -75
- data/lib/schleuder/storage.rb +0 -84
- data/lib/schleuder/utils.rb +0 -80
- data/man/schleuder-newlist.8 +0 -174
- data/man/schleuder.8 +0 -416
- data/plugins/README +0 -20
- data/plugins/manage_keys_plugin.rb +0 -113
- data/plugins/manage_members_plugin.rb +0 -156
- data/plugins/manage_self_plugin.rb +0 -26
- data/plugins/resend_plugin.rb +0 -35
- data/plugins/sign_this_plugin.rb +0 -14
- data/plugins/version_plugin.rb +0 -12
- metadata.gz.sig +0 -0
data/lib/schleuder/mailer.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
module Schleuder
|
2
|
-
class Mailer
|
3
|
-
def self.send(msg, to=nil, sender=Schleuder.list.bounce_addr, nolog=false)
|
4
|
-
to = msg.to if to.nil?
|
5
|
-
|
6
|
-
# TODO: TLS
|
7
|
-
host = Schleuder.config.smtp_host
|
8
|
-
port = Schleuder.config.smtp_port
|
9
|
-
unless nolog
|
10
|
-
Schleuder.log.info { "Delivering mail to #{host}:#{port}" }
|
11
|
-
Schleuder.log.debug { "Mail has Sender: #{sender} - To: #{to.inspect}" }
|
12
|
-
end
|
13
|
-
Net::SMTP.start(host, port) do |smtpcon|
|
14
|
-
smtpcon.send_message msg.to_s, sender, to
|
15
|
-
end
|
16
|
-
true
|
17
|
-
rescue => e
|
18
|
-
if e.message.frozen?
|
19
|
-
Schleuder.log.warn "Something went wrong, while sending a message. I'll better preserve the message that should have been sent:\n#{msg.to_s}"
|
20
|
-
else
|
21
|
-
e.message << "\nOriginal message:\n#{msg.to_s}"
|
22
|
-
end
|
23
|
-
raise
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
data/lib/schleuder/member.rb
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
module Schleuder
|
2
|
-
class Member < Storage
|
3
|
-
schleuder_attr :email, nil
|
4
|
-
schleuder_attr :mime, 'MIME'
|
5
|
-
# only send encrypted mail to this member
|
6
|
-
schleuder_attr :encrypted_only, false
|
7
|
-
schleuder_attr :key_fingerprint, nil
|
8
|
-
|
9
|
-
def initialize(config=nil)
|
10
|
-
super(config)
|
11
|
-
|
12
|
-
# compress fingerprint
|
13
|
-
self.key_fingerprint = self.key_fingerprint
|
14
|
-
end
|
15
|
-
|
16
|
-
def to_hash
|
17
|
-
Hash[*self.class.default_schleuder_attributes.keys.collect { |key|
|
18
|
-
unless (val = send(key)).to_s.empty?
|
19
|
-
[ key, val ]
|
20
|
-
else
|
21
|
-
nil
|
22
|
-
end
|
23
|
-
}.flatten.compact]
|
24
|
-
end
|
25
|
-
|
26
|
-
def key_fingerprint=(fpr)
|
27
|
-
schleuder_attributes['key_fingerprint'] = Schleuder::Utils.compress_fingerprint(fpr)
|
28
|
-
end
|
29
|
-
|
30
|
-
def to_s
|
31
|
-
email
|
32
|
-
end
|
33
|
-
|
34
|
-
def key(only_valid_keys=true)
|
35
|
-
if @key.nil? || !only_valid_keys # by default we want only valid keys. If
|
36
|
-
# we ask also for invalid keys we want
|
37
|
-
# to redo the keylookup
|
38
|
-
lookup_str = self.key_fingerprint.nil? ? self.email : self.key_fingerprint
|
39
|
-
key_result = crypt.get_key(lookup_str,only_valid_keys)
|
40
|
-
if k = key_result.first
|
41
|
-
@key = k
|
42
|
-
self.key_fingerprint = @key.subkeys.first.fingerprint
|
43
|
-
else
|
44
|
-
@key = nil
|
45
|
-
self.key_fingerprint = nil
|
46
|
-
return key_result
|
47
|
-
end
|
48
|
-
end
|
49
|
-
@key
|
50
|
-
end
|
51
|
-
|
52
|
-
def uses_key?(other_key)
|
53
|
-
key # initialize @key
|
54
|
-
!@key.nil? && @key.subkeys.first.fingerprint == other_key.subkeys.first.fingerprint
|
55
|
-
end
|
56
|
-
|
57
|
-
def key_descr
|
58
|
-
k, msg = key
|
59
|
-
k ? crypt.key_descr(k) : "*Warning:* #{msg}"
|
60
|
-
end
|
61
|
-
|
62
|
-
private
|
63
|
-
def crypt
|
64
|
-
# No simple way to get hands on mail.crypt, so we create another here.
|
65
|
-
# But on class side as it does not need to be per member
|
66
|
-
@@crypt ||= Crypt.new(nil)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
data/lib/schleuder/plugin.rb
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
module Schleuder
|
2
|
-
# Parent-class for plugins. Sets up stub and helper methods.
|
3
|
-
class Plugin
|
4
|
-
# Define whether this plugin should be used for emails sent to the
|
5
|
-
# list-address or the request-address.
|
6
|
-
attr_reader :plugin_type
|
7
|
-
|
8
|
-
def Plugin.signing_key(mail)
|
9
|
-
@@key ||= mail.crypt.get_key(mail.in_signed.fpr).first
|
10
|
-
end
|
11
|
-
|
12
|
-
# Helper: creates a reply to the sender of the incoming message. The
|
13
|
-
# destination address is detemined by finding the list-member connected to
|
14
|
-
# the key that signed the incoming message. +msg+ is used as body for the
|
15
|
-
# outgoing mail.
|
16
|
-
def Plugin.reply(mail, msg, keywords)
|
17
|
-
Schleuder.log.info "Building reply mail"
|
18
|
-
out = Mail.new
|
19
|
-
|
20
|
-
out.subject = "Re: #{mail.subject}"
|
21
|
-
key = Plugin.signing_key(mail)
|
22
|
-
Schleuder.log.debug "Looking up member by key: #{key.inspect}"
|
23
|
-
member = Schleuder.list.find_member_by_key(key) || Schleuder.list.find_admin_by_key(key)
|
24
|
-
Schleuder.log.debug { "Result: #{member.inspect}" }
|
25
|
-
if member
|
26
|
-
Schleuder.log.info { "Found member for key: %s" % member.inspect }
|
27
|
-
else
|
28
|
-
Schleuder.log.error "No member or admin found for signing key, aborting reply."
|
29
|
-
return false
|
30
|
-
end
|
31
|
-
|
32
|
-
imail = out.individualize(member)
|
33
|
-
imail.in_reply_to = mail.message_id
|
34
|
-
imail.body = msg
|
35
|
-
|
36
|
-
unless imail.encrypt!(member)
|
37
|
-
Schleuder.log.debug 'encrypting failed, replacing body with please-fix-message'
|
38
|
-
imail.body = "Encrypting to #{imail.to} failed. Please fix."
|
39
|
-
end
|
40
|
-
|
41
|
-
Schleuder.log.info "Sending to #{imail.to}"
|
42
|
-
Mailer.send(imail)
|
43
|
-
|
44
|
-
unless (Schleuder.list.config.keywords_admin_notify & keywords).empty?
|
45
|
-
Schleuder.log.info "Sending notification to admins"
|
46
|
-
msg = "Hello list-admin,\n\nmember #{member.email} sent the keyword(s) '#{keywords.join("','")}' and received the following reply-message:\n\n\n".fmt << msg
|
47
|
-
Schleuder.log.notify_admin 'Notice', msg
|
48
|
-
end
|
49
|
-
|
50
|
-
Schleuder.log.info "Exiting"
|
51
|
-
exit 0
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
data/lib/schleuder/processor.rb
DELETED
@@ -1,363 +0,0 @@
|
|
1
|
-
module Schleuder
|
2
|
-
def log
|
3
|
-
SchleuderLogger.new unless Log4r::Logger['log4r']
|
4
|
-
# If there's a ListLogger we use that, else the global SchleuderLogger.
|
5
|
-
# The ListLogger is being set up in List::initialize().
|
6
|
-
Log4r::Logger['list'] || Log4r::Logger['log4r']
|
7
|
-
end
|
8
|
-
module_function :log
|
9
|
-
|
10
|
-
def config(config_file=nil)
|
11
|
-
# read the base config (class overloads itself with conf/schleuder.conf)
|
12
|
-
@config ||= SchleuderConfig.new(config_file)
|
13
|
-
end
|
14
|
-
module_function :config
|
15
|
-
|
16
|
-
def list
|
17
|
-
@list || nil
|
18
|
-
end
|
19
|
-
module_function :list
|
20
|
-
|
21
|
-
def list=(list)
|
22
|
-
@list = list
|
23
|
-
end
|
24
|
-
module_function :list=
|
25
|
-
|
26
|
-
def origmsg=(msg)
|
27
|
-
@origmsg = msg
|
28
|
-
end
|
29
|
-
module_function :origmsg=
|
30
|
-
|
31
|
-
def origmsg
|
32
|
-
@origmsg || nil
|
33
|
-
end
|
34
|
-
module_function :origmsg
|
35
|
-
|
36
|
-
def self.listname(listname=nil)
|
37
|
-
@listname ||= listname
|
38
|
-
end
|
39
|
-
|
40
|
-
class Processor
|
41
|
-
def self.run(listname, message)
|
42
|
-
Schleuder.listname(listname)
|
43
|
-
Schleuder.origmsg = message
|
44
|
-
Schleuder.log.debug "Testing if list-dir exists"
|
45
|
-
unless File.directory?(List.listdir(listname))
|
46
|
-
msg = "No such list: #{listname}"
|
47
|
-
$stderr.puts msg
|
48
|
-
Schleuder.log.warn msg
|
49
|
-
exit 1
|
50
|
-
end
|
51
|
-
|
52
|
-
Schleuder.log.debug "Creating list"
|
53
|
-
Schleuder.list = List.new(listname)
|
54
|
-
|
55
|
-
Schleuder.log.debug "Parsing incoming message"
|
56
|
-
mail = Mail.parse(message)
|
57
|
-
Schleuder.log.info "New mail incoming from #{mail.from}"
|
58
|
-
|
59
|
-
msize = message.size / 1024
|
60
|
-
lsize = Schleuder.list.config.max_message_size
|
61
|
-
if msize > lsize
|
62
|
-
self.bounce_or_drop "too big (#{msize}kB > #{lsize}kB)", "This address accepts only messages up to #{Schleuder.list.config.max_message_size} kilobyte.", mail
|
63
|
-
end
|
64
|
-
|
65
|
-
# if mail is a bounce we forward it directly to the admins, as
|
66
|
-
# dealing with those probably fails (encrypted attachments etc.)
|
67
|
-
if mail.bounce?
|
68
|
-
Schleuder.log.info "This is a bounce, forwarding to admins and exiting"
|
69
|
-
Schleuder.log.notify_admin "Problem", [ "Hello,\n\nI caught a bounce. Please take care of it.", message ]
|
70
|
-
Schleuder.log.info "Exiting cleanly"
|
71
|
-
exit(0)
|
72
|
-
end
|
73
|
-
|
74
|
-
if Schleuder.list.config.dump_incoming_mail
|
75
|
-
dump_dir = File.join(Schleuder.list.listdir,'dumps')
|
76
|
-
Dir.mkdir dump_dir unless File.directory? dump_dir
|
77
|
-
require 'digest/sha1'
|
78
|
-
msg_file = File.join(dump_dir,"#{Digest::SHA1.hexdigest(message[0..10000])}.msg")
|
79
|
-
Schleuder.log.info "Dumping message to #{msg_file}"
|
80
|
-
File.open(msg_file,"w") { |f| f << message }
|
81
|
-
Schleuder.log.notify_admin "Dump notification", "Hello,\n\nI dumped the current incoming message to #{msg_file} \n\nYou should erase that file after inspection!"
|
82
|
-
end
|
83
|
-
|
84
|
-
# if mail is a send-key-request we answer directly
|
85
|
-
if mail.to.to_a.include?(Schleuder.list.sendkey_addr) || (mail.subject.strip.downcase == 'send key!' && mail.body.strip.empty?)
|
86
|
-
Schleuder.log.info "Found send-key-request"
|
87
|
-
# TODO: refactor with Plugin::reply
|
88
|
-
out = Mail.new
|
89
|
-
out.subject = "Re: #{mail.subject}"
|
90
|
-
Schleuder.log.info "Building reply"
|
91
|
-
iout = out.individualize(Member.new({'email' => mail.from.first}))
|
92
|
-
iout.in_reply_to = mail.message_id
|
93
|
-
Schleuder.log.debug "Filling body with key-id and key"
|
94
|
-
iout.body = "#{Schleuder.list.key.to_s}\n#{mail.crypt.export(Schleuder.list.key_fingerprint).to_s}"
|
95
|
-
Schleuder.log.debug "Signing outgoing email"
|
96
|
-
rawmail = iout.sign
|
97
|
-
Schleuder.log.info "Handing over to Mailer"
|
98
|
-
Mailer.send(rawmail, iout.to)
|
99
|
-
Schleuder.log.info "Exiting"
|
100
|
-
exit 0
|
101
|
-
end
|
102
|
-
|
103
|
-
# Analyse data (hopefully an incoming mail).
|
104
|
-
# Is it multi-part? encrypted? pgp/mime? signed?
|
105
|
-
Schleuder.log.debug "Analysing incoming mail"
|
106
|
-
begin
|
107
|
-
mail.decrypt!
|
108
|
-
rescue GPGME::Error::DecryptFailed => e
|
109
|
-
Schleuder.log.error "#{e}\n\nOriginal message:\n#{message}"
|
110
|
-
$stdout.puts "Schleuder speaking. Cannot decrypt. Please check your setup.\nMessages to this list need to be encrypted with this key:\n#{Schleuder.list.key}"
|
111
|
-
exit 100
|
112
|
-
end
|
113
|
-
|
114
|
-
if !mail.to.nil? && mail.to.include?(Schleuder.list.owner_addr)
|
115
|
-
Schleuder.log.info "This is a message to the owner(s), forwarding to admins and exiting"
|
116
|
-
Schleuder.log.notify_admin "Message", [ "Hello,\n\nthe attached message is directed to you as list-owner(s). Please take care of it!\n\n", mail ]
|
117
|
-
Schleuder.log.info "Exiting cleanly"
|
118
|
-
exit(0)
|
119
|
-
end
|
120
|
-
|
121
|
-
if Schleuder.list.config.receive_signed_only && !mail.in_signed
|
122
|
-
self.bounce_or_drop "not validly signed", "This address accepts only messages validly signed in an OpenPGP-compatible way", mail
|
123
|
-
end
|
124
|
-
|
125
|
-
if Schleuder.list.config.receive_encrypted_only && !mail.in_encrypted
|
126
|
-
self.bounce_or_drop 'not encrypted', "This address accepts only messages encrypted with this key:\n#{Schleuder.list.key}", mail
|
127
|
-
end
|
128
|
-
|
129
|
-
if Schleuder.list.config.receive_authenticated_only && !(mail.from_member || mail.from_admin)
|
130
|
-
self.bounce_or_drop "not authenticated", "This address requires properly signed emails by its list-members. Either the signature can't be verified or is missing.", mail
|
131
|
-
end
|
132
|
-
|
133
|
-
if Schleuder.list.config.receive_from_member_emailaddresses_only && !(mail.from_member_address?||mail.from_admin_address?)
|
134
|
-
self.bounce_or_drop "not from a member e-mail address", "This address accepts only messages from member addresses.", mail
|
135
|
-
end
|
136
|
-
|
137
|
-
if Schleuder.list.config.receive_admin_only && !mail.from_admin
|
138
|
-
self.bounce_or_drop "not authenticated as admin", "This address requires properly signed emails by its list-admins. Either the signature can't be verified or is missing.", mail
|
139
|
-
end
|
140
|
-
|
141
|
-
if mail.to.to_a.include?(Schleuder.list.request_addr)
|
142
|
-
if (mail.from_member || mail.from_admin) && mail.in_encrypted
|
143
|
-
process_plugins(mail)
|
144
|
-
# If we reach this point no plugin took over
|
145
|
-
self.bounce_or_drop "not a valid request", "No valid command found in message. This address (-request) accepts only messages containing valid schleuder-keyword-commands.".fmt, mail
|
146
|
-
end
|
147
|
-
self.bounce_or_drop "not authenticated", "This address (-request) accepts only encrypted messages by list-members.".fmt, mail
|
148
|
-
end
|
149
|
-
|
150
|
-
unless mail.from_member || mail.from_admin
|
151
|
-
Schleuder.log.debug "Mail is not from a list-member, adding prefix_in"
|
152
|
-
mail.add_prefix_in!
|
153
|
-
end
|
154
|
-
|
155
|
-
# Checking for keywords in mail-body (e.g. X-RESEND)
|
156
|
-
if mail.from_member || mail.from_admin
|
157
|
-
if mail.in_encrypted
|
158
|
-
Schleuder.log.info "Incoming mail is encrypted and authorized, processing plugins"
|
159
|
-
process_plugins(mail)
|
160
|
-
else
|
161
|
-
Schleuder.log.info "Incoming mail is not encrypted or authorized, skipping plugins"
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
|
-
# first encrypt and send message to external recipients and collect
|
166
|
-
# information about the process
|
167
|
-
mail.resend_to.each do |receiver|
|
168
|
-
if receiver.email.to_s.empty?
|
169
|
-
errmsg = "Invalid value for receiver.email: %s. Skipping."
|
170
|
-
Schleuder.log.warn { errmsg % receiver.email.inspect }
|
171
|
-
next
|
172
|
-
end
|
173
|
-
|
174
|
-
imail = mail.individualize(receiver)
|
175
|
-
imail.add_public_footer!
|
176
|
-
|
177
|
-
if Schleuder.list.config.send_encrypted_only
|
178
|
-
enc_only = true
|
179
|
-
else
|
180
|
-
enc_only = receiver.encrypted_only
|
181
|
-
end
|
182
|
-
|
183
|
-
begin
|
184
|
-
ret = self.send(imail, receiver, enc_only)
|
185
|
-
if ret.first
|
186
|
-
# store meta-data about the sent message
|
187
|
-
crypt = " (#{ret[1]})"
|
188
|
-
mail.metadata[:resent_to] << receiver.email + crypt
|
189
|
-
else
|
190
|
-
mail.metadata[:error] << "Not resent to #{receiver.email}: #{ret[1]}"
|
191
|
-
end
|
192
|
-
rescue => e
|
193
|
-
Schleuder.log.error e
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
mail.add_prefix_out! unless mail.metadata[:resent_to].empty?
|
198
|
-
mail.add_prefix!
|
199
|
-
mail.add_metadata!
|
200
|
-
|
201
|
-
# archive message if necessary
|
202
|
-
Schleuder.list.archive(mail) if Schleuder.list.config.archive
|
203
|
-
|
204
|
-
# encrypt message and send mail for each list-member
|
205
|
-
Schleuder.log.info { 'Looping over all list-members to send out' }
|
206
|
-
Schleuder.list.members.each do |receiver|
|
207
|
-
Schleuder.log.debug { "Looping for #{receiver.inspect}" }
|
208
|
-
|
209
|
-
if receiver.email.to_s.empty?
|
210
|
-
errmsg = "Invalid value for receiver.email: %s. Skipping."
|
211
|
-
Schleuder.log.warn { errmsg % receiver.email.inspect }
|
212
|
-
next
|
213
|
-
end
|
214
|
-
|
215
|
-
imail = mail.individualize_member(receiver)
|
216
|
-
|
217
|
-
if Schleuder.list.config.send_encrypted_only
|
218
|
-
enc_only = true
|
219
|
-
else
|
220
|
-
enc_only = receiver.encrypted_only
|
221
|
-
end
|
222
|
-
|
223
|
-
# encrypt for each receiver
|
224
|
-
begin
|
225
|
-
sent = self.send(imail, receiver, enc_only)
|
226
|
-
unless sent.first
|
227
|
-
Schleuder.log.error sent[1]
|
228
|
-
end
|
229
|
-
rescue => e
|
230
|
-
Schleuder.log.error e
|
231
|
-
end
|
232
|
-
end
|
233
|
-
Schleuder.log.info { 'Processing done, this is the end.' }
|
234
|
-
end
|
235
|
-
|
236
|
-
def self.send(mail, receiver, encrypted_only=true, sender=Schleuder.list.bounce_addr)
|
237
|
-
begin
|
238
|
-
encrypted, errmsg = mail.encrypt!(receiver)
|
239
|
-
rescue GPGME::Error::UnusablePublicKey => e
|
240
|
-
# This exception is thrown, if the public key of a certain list
|
241
|
-
# member is not usable (because it is revoked, expired, disabled or
|
242
|
-
# invalid).
|
243
|
-
k = e.keys.first
|
244
|
-
key = mail.crypt.get_key(k.fpr).first
|
245
|
-
errmsg = "#{e.message}: (#{k.class})\n#{key.to_s}"
|
246
|
-
Schleuder.log.error "Encryption failed (#{errmsg})"
|
247
|
-
encrypted = false
|
248
|
-
rescue GPGME::Error::General => e
|
249
|
-
errmsg = e.message
|
250
|
-
Schleuder.log.error "Encryption failed (#{errmsg})"
|
251
|
-
encrypted = false
|
252
|
-
end
|
253
|
-
if encrypted
|
254
|
-
Mailer.send(mail, nil, sender)
|
255
|
-
return [true, 'encrypted']
|
256
|
-
else
|
257
|
-
if encrypted_only
|
258
|
-
Schleuder.log.debug "Sending plaintext not allowed, message not sent to #{receiver.inspect}!"
|
259
|
-
return [false, "Encrypting to #{receiver.email.inspect} failed: #{errmsg} (sending plaintext disallowed)"]
|
260
|
-
else
|
261
|
-
Schleuder.log.info "Sending plaintext allowed, doing so"
|
262
|
-
# sign msg
|
263
|
-
if rawmail = mail.sign
|
264
|
-
Mailer.send(rawmail, mail.to, sender)
|
265
|
-
return [true, "unencrypted (#{errmsg})"]
|
266
|
-
else
|
267
|
-
return [false, "signing failed"]
|
268
|
-
end
|
269
|
-
end
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
|
-
def self.test(listname=nil)
|
274
|
-
# Doing things that trigger exceptions if they fail, which we rescue and
|
275
|
-
# put to stderr
|
276
|
-
# TODO: test #{smtp_host}:25
|
277
|
-
begin
|
278
|
-
# test listdir
|
279
|
-
Dir.entries Schleuder.config.lists_dir
|
280
|
-
|
281
|
-
# test superadminaddr
|
282
|
-
Utils::verify_addr('superadminaddr', Schleuder.config.superadminaddr)
|
283
|
-
|
284
|
-
if listname
|
285
|
-
# testwise create a list-object (reads list-config etc.)
|
286
|
-
list = List.new listname
|
287
|
-
# test for listdir
|
288
|
-
Dir.entries list.listdir
|
289
|
-
# test admins
|
290
|
-
list.config.admins.each do |a|
|
291
|
-
Utils::verify_addr('adminaddr', a.email)
|
292
|
-
key, msg = a.key
|
293
|
-
if !key
|
294
|
-
raise "Admin: #{a}'s key lookup fails! Problem: #{msg}"
|
295
|
-
end
|
296
|
-
end
|
297
|
-
|
298
|
-
crypt = Crypt.new(list.config.gpg_password)
|
299
|
-
|
300
|
-
list.members.each do |m|
|
301
|
-
Utils::verify_addr('member address', m.email)
|
302
|
-
key, msg = m.key
|
303
|
-
if !key
|
304
|
-
raise "#{m}'s key lookup fails! Problem: #{msg}"
|
305
|
-
end
|
306
|
-
end
|
307
|
-
end
|
308
|
-
rescue => e
|
309
|
-
$stderr.puts e.message
|
310
|
-
$stderr.puts e.backtrace
|
311
|
-
exit 1
|
312
|
-
end
|
313
|
-
end
|
314
|
-
|
315
|
-
def self.newlist(listname, interactive='true', args=nil)
|
316
|
-
created_list = Schleuder::ListCreator.create(listname,interactive,args)
|
317
|
-
end
|
318
|
-
|
319
|
-
def self.bounce_or_drop(status, bounce_msg, mail)
|
320
|
-
Schleuder.log.warn "Mail is #{status}, not passing it along"
|
321
|
-
|
322
|
-
if Schleuder.list.config.bounces_drop_all
|
323
|
-
Schleuder.log.warn "Found bounces_drop_all being true: dropping!"
|
324
|
-
self.bounce_notify_admin status, "bounces_drop_all is true"
|
325
|
-
exit 0
|
326
|
-
end
|
327
|
-
|
328
|
-
Schleuder.log.debug "Testing bounces_drop_on_headers"
|
329
|
-
Schleuder.list.config.bounces_drop_on_headers.each do |header,value|
|
330
|
-
Schleuder.log.debug "Testing #{header} => #{value}"
|
331
|
-
if mail.header[header].to_s.downcase == value.to_s.downcase
|
332
|
-
Schleuder.log.warn "Found matching drop-header: #{header} => #{value} -- dropping!"
|
333
|
-
self.bounce_notify_admin status, "Forbidden header found: '#{header.capitalize}: #{value.capitalize}'"
|
334
|
-
exit 0
|
335
|
-
end
|
336
|
-
end
|
337
|
-
|
338
|
-
# if we're still alive: bounce message
|
339
|
-
Schleuder.log.info "bouncing mail to sender"
|
340
|
-
self.bounce_notify_admin("#{status}. - #{bounce_msg}")
|
341
|
-
$stdout.puts bounce_msg
|
342
|
-
exit 100
|
343
|
-
end
|
344
|
-
|
345
|
-
def self.bounce_notify_admin(reason, drop_reason='')
|
346
|
-
msg = "The attached incoming email has not been passed to the list.\nReason: #{reason}.\n"
|
347
|
-
if drop_reason.empty?
|
348
|
-
msg += "\nIt has been bounced to the sender.\n"
|
349
|
-
else
|
350
|
-
msg += "\nIt has *not* been bounced but dropped.\nReason: #{drop_reason}.\n"
|
351
|
-
end
|
352
|
-
|
353
|
-
Schleuder.log.notify_admin("Notice", [ msg, Mail.parse(Schleuder.origmsg) ]) if Schleuder.list.config.bounces_notify_admin
|
354
|
-
end
|
355
|
-
|
356
|
-
def self.process_plugins(mail)
|
357
|
-
Schleuder.log.info 'Email is encrypted and authorized, processing plugins'
|
358
|
-
# process plugins
|
359
|
-
Schleuder.log.debug 'Processing plugins'
|
360
|
-
mail.process_plugins!
|
361
|
-
end
|
362
|
-
end
|
363
|
-
end
|