schleuder 2.2.4 → 3.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/crypt.rb
DELETED
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
module Schleuder
|
|
2
|
-
# Wrapper for ruby-gpgme. Method naming is not strictly logical, this might
|
|
3
|
-
# change but aliases will be set up then.
|
|
4
|
-
class Crypt
|
|
5
|
-
# Instantiates and stores password
|
|
6
|
-
def initialize(password, options={})
|
|
7
|
-
unless options[:new_keyring]
|
|
8
|
-
# Check file permissions. ruby-gpgme unfortunately returns unspecific
|
|
9
|
-
# errors if it can't read files.
|
|
10
|
-
%w(pubring.gpg secring.gpg trustdb.gpg).each do |fn|
|
|
11
|
-
f = File.join(ENV['GNUPGHOME'], fn)
|
|
12
|
-
if ! File.readable?(f)
|
|
13
|
-
raise Errno::EACCES.new('%s is not readable' % f)
|
|
14
|
-
elsif ! File.writable?(f)
|
|
15
|
-
raise Errno::EACCES.new('%s is not writable' % f)
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
@password = password
|
|
21
|
-
if GPGME.respond_to? 'check_version'
|
|
22
|
-
GPGME::check_version('0.0.0')
|
|
23
|
-
end
|
|
24
|
-
@ctx = GPGME::Ctx.new
|
|
25
|
-
# feed the passphrase into the Context
|
|
26
|
-
@ctx.set_passphrase_cb(method(:passfunc))
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# Verify a gpg-signature. Use +signed_string+ if the signature is
|
|
30
|
-
# detached. Returns a GPGME::SignatureResult
|
|
31
|
-
def verify(sig, signed_string='')
|
|
32
|
-
in_signed = ''
|
|
33
|
-
if signed_string.empty?
|
|
34
|
-
# verify +sig+ as cleartext (aka pgp/inline) signature
|
|
35
|
-
Schleuder.log.debug 'No extra signed_string, verifying cleartext signature'
|
|
36
|
-
output = GPGME.verify(sig) do |sig|
|
|
37
|
-
in_signed = sig
|
|
38
|
-
end
|
|
39
|
-
else
|
|
40
|
-
# verify detached signature
|
|
41
|
-
Schleuder.log.debug 'Verifying detached signature'
|
|
42
|
-
# Don't know why we need a GPGME::Data object this time but without gpgme throws exceptions
|
|
43
|
-
plain = GPGME::Data.new
|
|
44
|
-
GPGME.verify(sig, signed_string, plain) do |sig|
|
|
45
|
-
in_signed = sig
|
|
46
|
-
end
|
|
47
|
-
output = signed_string
|
|
48
|
-
|
|
49
|
-
end
|
|
50
|
-
Schleuder.log.debug 'verify_result: ' + in_signed.inspect
|
|
51
|
-
|
|
52
|
-
[output, in_signed]
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# Decrypt a string.
|
|
56
|
-
def decrypt(str)
|
|
57
|
-
output = ""
|
|
58
|
-
in_encrypted = nil
|
|
59
|
-
in_signed = nil
|
|
60
|
-
|
|
61
|
-
# TODO: return ciphertext if missing key when decrypting inline
|
|
62
|
-
# attachments or recursing into mime-messages. Breaking if even the
|
|
63
|
-
# whole message is not decryptable is a job for the processor.
|
|
64
|
-
|
|
65
|
-
# match pgp-mime- and inline-pgp-signatures
|
|
66
|
-
if str =~ /^-----BEGIN PGP SIG/
|
|
67
|
-
Schleuder.log.debug 'found ascii-armored, signed, not encrypted message, verifying'
|
|
68
|
-
output, in_signed = verify(str)
|
|
69
|
-
else
|
|
70
|
-
begin
|
|
71
|
-
Schleuder.log.debug 'Trying to decrypt'
|
|
72
|
-
output = GPGME.decrypt(str, :passphrase_callback => method(:passfunc)) do |sig|
|
|
73
|
-
in_signed = sig
|
|
74
|
-
end
|
|
75
|
-
in_encrypted = true
|
|
76
|
-
rescue GPGME::Error::NoData => exc
|
|
77
|
-
Schleuder.log.debug "Caught NoData-exception from gpgme. This probably means we're dealing with a binary signature, trying to verify."
|
|
78
|
-
output, in_signed = verify(str)
|
|
79
|
-
if output.empty?
|
|
80
|
-
Schleuder.log.debug "Empty output from verification. No more options, returning."
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
Schleuder.log.debug "mime_type of decrypted content: #{output.mime.inspect}"
|
|
85
|
-
Schleuder.log.debug "in_signed: #{in_signed.inspect}"
|
|
86
|
-
Schleuder.log.debug "in_encrypted: #{in_encrypted.inspect}"
|
|
87
|
-
if output.empty?
|
|
88
|
-
Schleuder.log.debug "Empty output, returning input"
|
|
89
|
-
output = str
|
|
90
|
-
end
|
|
91
|
-
# TODO: return mailadresses or keys instead of signature-objects?
|
|
92
|
-
[output, in_encrypted, in_signed]
|
|
93
|
-
rescue GPGME::Error::General => exc
|
|
94
|
-
Schleuder.log.warn "gpgme returned a general error. Most likely this is due to unexpected input, but as you never know here's the input and the exception:\ninput:\n#{str.inspect}\n#{exc.to_s}\n#{exc.backtrace[0..9].join("\n")}"
|
|
95
|
-
[str, nil, nil]
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
# Encrypt a string to a single receiver and sign it. +receiver+ must be a
|
|
99
|
-
# Schleuder::Member
|
|
100
|
-
def encrypt_str(str, receiver)
|
|
101
|
-
# encrypt and sign and return encrypted data as string
|
|
102
|
-
# For some reason sometimes the last two characters of str are stolen
|
|
103
|
-
# unless we append a blank or newline... Life is hard...
|
|
104
|
-
GPGME.encrypt([receiver.key],
|
|
105
|
-
"#{str} ",
|
|
106
|
-
{:passphrase_callback => method(:passfunc),
|
|
107
|
-
:armor => true,
|
|
108
|
-
:sign => true,
|
|
109
|
-
:always_trust => true
|
|
110
|
-
})
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
# Lists all public keys matching +pattern+. Returns an array of
|
|
114
|
-
# GPGME::GpgKey's
|
|
115
|
-
def list_keys(pattern='')
|
|
116
|
-
GPGME.list_keys(pattern)
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
# Returns the GPGME::GpgKey matching +pattern+. Log an error if more than
|
|
120
|
-
# one matches, because duplicated user-ids is a sensitive issue.
|
|
121
|
-
def get_key(pattern, only_valid_keys=false)
|
|
122
|
-
pattern = "<#{pattern}>" if pattern =~ /.*@.*/ && !(pattern =~ /^<.*>$/)
|
|
123
|
-
keys = list_keys(pattern)
|
|
124
|
-
|
|
125
|
-
keys.reject! { |key| unusable_key?(key) } if only_valid_keys
|
|
126
|
-
|
|
127
|
-
if keys.empty?
|
|
128
|
-
[false, "no key found for #{pattern}."]
|
|
129
|
-
elsif keys.length > 1
|
|
130
|
-
Schleuder.log.warn "There's more than one key matching the pattern you gave me!"
|
|
131
|
-
Schleuder.log.debug { "Pattern: #{pattern.inspect}" }
|
|
132
|
-
Schleuder.log.debug { "Keys: #{keys.inspect}" }
|
|
133
|
-
[false, "no distinct key for #{pattern.inspect} found. Matching keys: #{key_infos(keys,only_valid_keys).join(', ')}"]
|
|
134
|
-
else
|
|
135
|
-
[keys.first]
|
|
136
|
-
end
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
# Signs +string+ with the private key of the list (aka detached signature)
|
|
140
|
-
def sign(string)
|
|
141
|
-
GPGME::detach_sign(string, {:armor => true, :passphrase_callback => method(:passfunc)})
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
# Clearsigns +string+ with the private key of the list
|
|
145
|
-
def clearsign(string)
|
|
146
|
-
GPGME::clearsign(string, {:armor => true, :passphrase_callback => method(:passfunc)})
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
# Exports the public key matching +keyid+ as ascii key block.
|
|
150
|
-
def export(keyid)
|
|
151
|
-
GPGME.export(keyid, :armor=>:true)
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
# Delete the public key matching +pattern+ from the public key ring of the
|
|
155
|
-
# list
|
|
156
|
-
def delete_key(key)
|
|
157
|
-
msg = nil
|
|
158
|
-
key, msg = get_key(key) if key.kind_of?(String)
|
|
159
|
-
|
|
160
|
-
if key
|
|
161
|
-
@ctx.delete_key(key)
|
|
162
|
-
return true
|
|
163
|
-
else
|
|
164
|
-
msg
|
|
165
|
-
end
|
|
166
|
-
rescue => e
|
|
167
|
-
return e
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
# Import +keydata+ into public key ring of the list
|
|
171
|
-
def add_key(keydata)
|
|
172
|
-
GPGME.import(keydata)
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
def add_key_from_file(keyfile)
|
|
176
|
-
add_key(File.read(keyfile))
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
def key_descr(key)
|
|
180
|
-
key.to_s.split("\n").first.split[1..2].join(' ')
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
private
|
|
184
|
-
|
|
185
|
-
def key_infos(keys, only_valid_keys=false)
|
|
186
|
-
keys.collect do |key|
|
|
187
|
-
info = key_descr(key)
|
|
188
|
-
unless only_valid_keys
|
|
189
|
-
info << trust_info(key)
|
|
190
|
-
end
|
|
191
|
-
info
|
|
192
|
-
end
|
|
193
|
-
end
|
|
194
|
-
|
|
195
|
-
def trust_info(key)
|
|
196
|
-
unusable_key?(key) ? " *#{key.trust}*" : ''
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
def unusable_key?(key)
|
|
200
|
-
[:revoked, :expired].include?(key.trust)
|
|
201
|
-
end
|
|
202
|
-
|
|
203
|
-
def passfunc(hook, uid_hint, passphrase_info, prev_was_bad, fd)
|
|
204
|
-
io = IO.for_fd(fd, 'w')
|
|
205
|
-
io.puts @password
|
|
206
|
-
io.flush
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
end
|
|
210
|
-
end
|
data/lib/schleuder/errors.rb
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
# the list config class - a simple container
|
|
2
|
-
|
|
3
|
-
module Schleuder
|
|
4
|
-
class ListConfig < Storage
|
|
5
|
-
|
|
6
|
-
# Options and their defaults
|
|
7
|
-
# If you want to change the defaults, edit conf/default-list.conf
|
|
8
|
-
|
|
9
|
-
# Emailaddress of the list
|
|
10
|
-
schleuder_attr :myaddr, ''
|
|
11
|
-
|
|
12
|
-
# Realname of this list address (mainly used for gpg key)
|
|
13
|
-
schleuder_attr :myname, ''
|
|
14
|
-
|
|
15
|
-
# Listadmin's emailaddress(es). Must be an array.
|
|
16
|
-
schleuder_attr :admins, []
|
|
17
|
-
|
|
18
|
-
# Default mime setting
|
|
19
|
-
schleuder_attr :default_mime, 'MIME'
|
|
20
|
-
|
|
21
|
-
# The gpg password
|
|
22
|
-
schleuder_attr :gpg_password, nil
|
|
23
|
-
|
|
24
|
-
# The fingerprint of the key used for this list
|
|
25
|
-
schleuder_attr :key_fingerprint, nil
|
|
26
|
-
|
|
27
|
-
# Wether sending emails in the clear is allowed or not.
|
|
28
|
-
schleuder_attr :send_encrypted_only, false
|
|
29
|
-
|
|
30
|
-
# Wether to accept only incoming emails that are encrypted
|
|
31
|
-
schleuder_attr :receive_encrypted_only, false
|
|
32
|
-
|
|
33
|
-
# Wether to accept only emails that are validly signed
|
|
34
|
-
schleuder_attr :receive_signed_only, false
|
|
35
|
-
|
|
36
|
-
# Wether to accept only emails that are validly signed by a list-member's key
|
|
37
|
-
schleuder_attr :receive_authenticated_only, false
|
|
38
|
-
|
|
39
|
-
# Wether to accept only emails that are validly signed by a list-admin's key
|
|
40
|
-
schleuder_attr :receive_admin_only, false
|
|
41
|
-
|
|
42
|
-
# Whether to accept only emails that are sent from a members address.
|
|
43
|
-
# NOTE: better rely on :receive_authenticated_only and ignore that option.
|
|
44
|
-
schleuder_attr :receive_from_member_emailaddresses_only, false
|
|
45
|
-
|
|
46
|
-
# Wether to keep the msgid or not
|
|
47
|
-
schleuder_attr :keep_msgid, true
|
|
48
|
-
|
|
49
|
-
# Footer for outgoing mails
|
|
50
|
-
schleuder_attr :public_footer, ''
|
|
51
|
-
|
|
52
|
-
# Subject prefix for incoming (signed) mails from listmembers
|
|
53
|
-
schleuder_attr :prefix, ''
|
|
54
|
-
|
|
55
|
-
# Subject prefix for incoming mails
|
|
56
|
-
schleuder_attr :prefix_in, ''
|
|
57
|
-
|
|
58
|
-
# Subject prefix for outgoing mails
|
|
59
|
-
schleuder_attr :prefix_out, ''
|
|
60
|
-
|
|
61
|
-
# The log_level (ERROR || WARN || INFO || DEBUG)
|
|
62
|
-
schleuder_attr :log_level, 'ERROR'
|
|
63
|
-
|
|
64
|
-
# Log to SYSLOG?
|
|
65
|
-
schleuder_attr :log_syslog, false
|
|
66
|
-
|
|
67
|
-
# Log to IO (writing into STDIN of another process/executable)
|
|
68
|
-
schleuder_attr :log_io, false
|
|
69
|
-
|
|
70
|
-
# Log to a file? If the path doesn't start with a slash the list-dir will
|
|
71
|
-
# be prefixed.
|
|
72
|
-
schleuder_attr :log_file, 'list.log'
|
|
73
|
-
|
|
74
|
-
# Which headers from original mail to include into the internal meta data
|
|
75
|
-
schleuder_attr :headers_to_meta, [:from, :to, :cc, :date]
|
|
76
|
-
|
|
77
|
-
# Restrict specific plugins to admin
|
|
78
|
-
schleuder_attr :keywords_admin_only, ['ADD-MEMBER', 'DELETE-MEMBER', 'DELETE-KEY', 'SAVE-MEMBERS', 'DEL-KEY' ]
|
|
79
|
-
|
|
80
|
-
# Notify admin if these keywords triggered commands.
|
|
81
|
-
schleuder_attr :keywords_admin_notify, [ 'ADD-KEY' ]
|
|
82
|
-
|
|
83
|
-
# Drop any bounces (incoming email not passing the receive_*_only-rules)
|
|
84
|
-
schleuder_attr :bounces_drop_all, false
|
|
85
|
-
|
|
86
|
-
# Drop bounces if they match one of these headers. Must be a hash, keys and values are case insensitive.
|
|
87
|
-
schleuder_attr :bounces_drop_on_headers, {'x-spam-flag' => 'yes'}
|
|
88
|
-
|
|
89
|
-
# Send a notice to admin(s) on bouncing or dropping
|
|
90
|
-
schleuder_attr :bounces_notify_admin, true
|
|
91
|
-
|
|
92
|
-
# Include RFC-compliant List-* Headers into member mails
|
|
93
|
-
schleuder_attr :include_list_headers, true
|
|
94
|
-
|
|
95
|
-
# Include OpenPGP-Header
|
|
96
|
-
schleuder_attr :include_openpgp_header, true
|
|
97
|
-
# Preferred way to receive emails to note in OpenPGP-Header ('sign'|'encrypt'|'signencrypt'|'unprotected'|'none')
|
|
98
|
-
# 'none' to not include a preference
|
|
99
|
-
# default: 'signencrypt'
|
|
100
|
-
schleuder_attr :openpgp_header_preference, 'signencrypt'
|
|
101
|
-
|
|
102
|
-
# If we want to dump the original incoming mail.
|
|
103
|
-
# ATTENTION: this stores the incoming e-mail on disk!
|
|
104
|
-
schleuder_attr :dump_incoming_mail, false
|
|
105
|
-
|
|
106
|
-
# Maximum size of message allowed on the list in kilobyte. All others will be bounced.
|
|
107
|
-
schleuder_attr :max_message_size, 10240 # 10MB
|
|
108
|
-
|
|
109
|
-
# Whether to archive messages sent to list members or not.
|
|
110
|
-
# default: false
|
|
111
|
-
schleuder_attr :archive, false
|
|
112
|
-
|
|
113
|
-
### END OF CONFIG OPTIONS
|
|
114
|
-
|
|
115
|
-
def initialize(config=nil)
|
|
116
|
-
# First Overload with default-list.conf then load our config
|
|
117
|
-
overload_from_file!(Schleuder.config.lists_default_conf)
|
|
118
|
-
# overload with config_file
|
|
119
|
-
super(config)
|
|
120
|
-
|
|
121
|
-
# load admins as members
|
|
122
|
-
self.admins = self.admins
|
|
123
|
-
# compress fingerprint
|
|
124
|
-
self.key_fingerprint = self.key_fingerprint
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
def key_fingerprint=(fpr)
|
|
128
|
-
schleuder_attributes['key_fingerprint'] = Schleuder::Utils.compress_fingerprint(fpr)
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
def admins=(ary)
|
|
132
|
-
schleuder_attributes['admins'] = Array(ary).collect { |mem|
|
|
133
|
-
if mem.kind_of?(Member)
|
|
134
|
-
mem
|
|
135
|
-
else
|
|
136
|
-
if mem.kind_of?(Hash) && mem.has_key?("email")
|
|
137
|
-
Member.new(mem)
|
|
138
|
-
else
|
|
139
|
-
Schleuder.log.error "Wrong input: #{mem.inspect} is not suitable data for a Member."
|
|
140
|
-
nil
|
|
141
|
-
end
|
|
142
|
-
end
|
|
143
|
-
}.compact
|
|
144
|
-
end
|
|
145
|
-
end
|
|
146
|
-
end
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
module Schleuder
|
|
2
|
-
class ListLogger < Log4r::Logger
|
|
3
|
-
# Instantiates the list-logger and sets outputters and level.
|
|
4
|
-
# Warning: Do *not* rely on the list-object here! It's not yet available
|
|
5
|
-
# (this actually is part of setting it up) and you'd produce loops and
|
|
6
|
-
# break the whole thing.
|
|
7
|
-
def initialize(listname, listdir, config)
|
|
8
|
-
# Initialize self
|
|
9
|
-
super('list')
|
|
10
|
-
|
|
11
|
-
# define the initial log_level for all outputters (they inherit it)
|
|
12
|
-
@level = eval("Log4r::#{config.log_level.upcase}")
|
|
13
|
-
|
|
14
|
-
# Setting up outputters.
|
|
15
|
-
fmtr = Log4r::PatternFormatter.new(:pattern => "%d #{listname} %l\t%M")
|
|
16
|
-
|
|
17
|
-
if config.log_file
|
|
18
|
-
require 'log4r/outputter/fileoutputter'
|
|
19
|
-
filename = config.log_file
|
|
20
|
-
filename = File.join(listdir, filename) unless filename[0..0].eql?('/')
|
|
21
|
-
filename = File.join(filename, "#{listname}.log") if filename.end_with?('/')
|
|
22
|
-
add Log4r::FileOutputter.new("file",
|
|
23
|
-
{ :level => @level,
|
|
24
|
-
:filename => filename,
|
|
25
|
-
:formatter => fmtr }
|
|
26
|
-
)
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
if config.log_syslog
|
|
30
|
-
require 'log4r/outputter/syslogoutputter'
|
|
31
|
-
syslogfmtr = Log4r::PatternFormatter.new(:pattern => "#{listname}: %M")
|
|
32
|
-
add Log4r::SyslogOutputter.new("syslog",
|
|
33
|
-
{ :level => @level,
|
|
34
|
-
:ident => 'schleuder',
|
|
35
|
-
:facility => "LOG_MAIL",
|
|
36
|
-
:formatter => syslogfmtr }
|
|
37
|
-
)
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
if config.log_io
|
|
41
|
-
require 'log4r/outputter/iooutputter'
|
|
42
|
-
require 'stringio'
|
|
43
|
-
io = IO.popen(config.log_io, 'w')
|
|
44
|
-
add Log4r::IOOutputter.new("io", io, :level => @level)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
# Add this as last outputter, else you'll see logging-statements from
|
|
48
|
-
# sending the email before the original error is logged — that's a little
|
|
49
|
-
# confusing.
|
|
50
|
-
add EmailOutputter.new("email", :formatter => fmtr)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def notify_admin(*args)
|
|
54
|
-
Log4r::Outputter['email'].notify_admin *args
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
module Schleuder
|
|
2
|
-
class EmailOutputter < Log4r::EmailOutputter
|
|
3
|
-
def initialize(name, hash={})
|
|
4
|
-
# The class needs to/from/subject, we don't use it
|
|
5
|
-
hash = {:to => Schleuder.config.superadminaddr,
|
|
6
|
-
:from => Schleuder.config.myaddr,
|
|
7
|
-
:'error-to' => Schleuder.config.superadminaddr,
|
|
8
|
-
:subject => 'Error',
|
|
9
|
-
:server => Schleuder.config.smtp_host,
|
|
10
|
-
:port => Schleuder.config.smtp_port,
|
|
11
|
-
:immediate_at => 'ERROR, FATAL',
|
|
12
|
-
:formatter => formatter,
|
|
13
|
-
:domain => 'schleuder', # necessary for log4r from debian "stable"
|
|
14
|
-
:buffsize => 1024**1024 # set the buff size very high otherwise we would trigger random log mails on random log statements if the buffer is full.
|
|
15
|
-
}.merge(hash)
|
|
16
|
-
@altmsg = "Hello,\n\nsending an encrypted error message to you failed. Therefore you receive only\nthis message and are kindly requested to take care of the encryption problem\n(e.g. fix your keys) and have a look at the logs to find the error.\n\nYours, Schleuder\n"
|
|
17
|
-
super name, hash
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def format(events)
|
|
21
|
-
events.map { |event| @formatter.format(event) }
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def notify_admin(subject, msg)
|
|
25
|
-
send_mail(makeemail(subject, msg))
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def makeemail(subject=@subject, msg=nil)
|
|
29
|
-
m = Mail.new
|
|
30
|
-
m.subject = subject
|
|
31
|
-
m.date = Time.now
|
|
32
|
-
m.from = @from
|
|
33
|
-
|
|
34
|
-
if msg
|
|
35
|
-
case msg
|
|
36
|
-
when String
|
|
37
|
-
m.body = msg
|
|
38
|
-
when Array
|
|
39
|
-
m.body = ''
|
|
40
|
-
m.mime_version = 1.0
|
|
41
|
-
msg.each do |msgpart|
|
|
42
|
-
part = Mail.new
|
|
43
|
-
case msgpart
|
|
44
|
-
when Mail
|
|
45
|
-
# This contruction is needed to have valid boundaries. Did I mention that Tmail sucks?
|
|
46
|
-
part.body = Mail.parse(msgpart.to_s).to_s
|
|
47
|
-
part.content_type = 'message/rfc822'
|
|
48
|
-
when String
|
|
49
|
-
part.body = msgpart.to_s
|
|
50
|
-
part.content_type = 'text/plain'
|
|
51
|
-
else
|
|
52
|
-
# This shouldn't happen (we should only have forwarded emails or
|
|
53
|
-
# strings to notify admins), but who knows.
|
|
54
|
-
part.body = msgpart
|
|
55
|
-
part.content_type = 'application/octet-stream'
|
|
56
|
-
end
|
|
57
|
-
m.parts.push part
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
else
|
|
61
|
-
# Get the triggering error-msg(s).
|
|
62
|
-
msg = format(@buff.select { |e| e.level > Log4r::WARN }).join
|
|
63
|
-
# Get the whole log.
|
|
64
|
-
backlog = format(@buff).join
|
|
65
|
-
|
|
66
|
-
infopart = Mail.new
|
|
67
|
-
infopart.body = "An error occurred working for list #{Schleuder.list.listname}:\n\n#{msg}\n\nSee also attachments.\n\n"
|
|
68
|
-
m.parts.push infopart
|
|
69
|
-
|
|
70
|
-
if Schleuder.origmsg
|
|
71
|
-
origm = Mail.new
|
|
72
|
-
origm.body = Schleuder.origmsg << "\n"
|
|
73
|
-
origm.content_type = "message/rfc822"
|
|
74
|
-
origm.set_content_disposition 'inline', { :filename => 'schleuder-orig-message.txt' }
|
|
75
|
-
origm['content-description'] = "'The originally incoming message'"
|
|
76
|
-
m.parts.push origm
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
backlogpart = Mail.new
|
|
80
|
-
backlogpart.body = backlog << "\n\n"
|
|
81
|
-
backlogpart['content-description'] = "'Schleuder logging output'"
|
|
82
|
-
backlogpart.set_content_disposition 'inline', { :filename => 'schleuder-log.txt' }
|
|
83
|
-
m.parts.push backlogpart
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
# Trigger re-parsing of the body, else TMail doesn't know it's multipart... :/
|
|
87
|
-
m.to_s
|
|
88
|
-
m
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
def send_mail(mail=makeemail)
|
|
92
|
-
if @send_mail_lock
|
|
93
|
-
self.level = Log4r::OFF # it's possible that the loglevel haven't yet been changed
|
|
94
|
-
Schleuder.log.warn "This is a loop in sending a mail in the EmailOutputer, breaking!"
|
|
95
|
-
return false
|
|
96
|
-
end
|
|
97
|
-
@send_mail_lock = true
|
|
98
|
-
Schleuder.log.info 'Sending notification to admin'
|
|
99
|
-
Schleuder.list.config.admins.each do |admin|
|
|
100
|
-
Schleuder.log.debug { "Looping for admin #{admin}" }
|
|
101
|
-
m = mail.individualize(admin)
|
|
102
|
-
m.to = admin.email
|
|
103
|
-
sender = Schleuder.config.superadminaddr
|
|
104
|
-
if !Processor.send(m, admin, true, sender)
|
|
105
|
-
m.body = @altmsg
|
|
106
|
-
m.content_type = 'text/plain'
|
|
107
|
-
Processor.send(m, admin, false, sender)
|
|
108
|
-
end
|
|
109
|
-
end
|
|
110
|
-
Schleuder.log.info { 'Sending notification done' }
|
|
111
|
-
rescue => e
|
|
112
|
-
# switch off logging per email, else we create loops here!
|
|
113
|
-
self.level = Log4r::OFF
|
|
114
|
-
raise
|
|
115
|
-
ensure
|
|
116
|
-
@send_mail_lock = false
|
|
117
|
-
@buff.clear
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
end
|