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
@@ -0,0 +1,14 @@
|
|
1
|
+
module Schleuder
|
2
|
+
module Errors
|
3
|
+
class LoadingListSettingsFailed < Base
|
4
|
+
def initialize
|
5
|
+
@config_file = ENV['SCHLEUDER_LIST_DEFAULTS']
|
6
|
+
end
|
7
|
+
|
8
|
+
def message
|
9
|
+
t('errors.loading_list_settings_failed', config_file: @config_file)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Schleuder
|
2
|
+
module Errors
|
3
|
+
class MessageEmpty < Base
|
4
|
+
def initialize(list)
|
5
|
+
set_default_locale
|
6
|
+
@request_address = list.request_address
|
7
|
+
end
|
8
|
+
|
9
|
+
def message
|
10
|
+
t('errors.message_empty', { request_address: @request_address })
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Schleuder
|
2
|
+
module Errors
|
3
|
+
class MessageTooBig < Base
|
4
|
+
def initialize(list)
|
5
|
+
set_default_locale
|
6
|
+
@allowed_size = list.max_message_size_kb
|
7
|
+
end
|
8
|
+
|
9
|
+
def message
|
10
|
+
t('errors.message_too_big', { allowed_size: @allowed_size })
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Schleuder
|
2
|
+
module Errors
|
3
|
+
class TooManyKeys < Base
|
4
|
+
def initialize(listdir, listname)
|
5
|
+
@listdir = listdir
|
6
|
+
@listname = listname
|
7
|
+
end
|
8
|
+
|
9
|
+
def message
|
10
|
+
t('errors.too_many_keys',
|
11
|
+
{ listdir: @listdir,
|
12
|
+
listname: @listname })
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Schleuder
|
2
|
+
module Errors
|
3
|
+
class UnknownListOption < Base
|
4
|
+
def initialize(exception)
|
5
|
+
@option = exception.attribute
|
6
|
+
@config_file = ENV['SCHLEUDER_LIST_DEFAULTS']
|
7
|
+
end
|
8
|
+
|
9
|
+
def message
|
10
|
+
t('errors.unknown_list_option', option: @option, config_file: @config_file)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Schleuder
|
2
|
+
module Filters
|
3
|
+
|
4
|
+
def self.receive_encrypted_only(list, mail)
|
5
|
+
if list.receive_encrypted_only? && ! mail.was_encrypted?
|
6
|
+
list.logger.info "Rejecting mail as unencrypted"
|
7
|
+
return Errors::MessageUnencrypted.new(list)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.receive_signed_only(list, mail)
|
12
|
+
if list.receive_signed_only? && ! mail.was_validly_signed?
|
13
|
+
list.logger.info "Rejecting mail as unsigned"
|
14
|
+
return Errors::MessageUnsigned.new(list)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.receive_authenticated_only(list, mail)
|
19
|
+
if list.receive_authenticated_only? && ( ! mail.was_encrypted? || ! mail.was_validly_signed? )
|
20
|
+
list.logger.info "Rejecting mail as unauthenticated"
|
21
|
+
return Errors::MessageUnauthenticated.new
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.receive_from_subscribed_emailaddresses_only(list, mail)
|
26
|
+
if list.receive_from_subscribed_emailaddresses_only? && list.subscriptions.where(email: mail.from.first).blank?
|
27
|
+
list.logger.info "Rejecting mail as not from subscribed address."
|
28
|
+
return Errors::MessageSenderNotSubscribed.new(list)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.receive_admin_only(list, mail)
|
33
|
+
if list.receive_admin_only? && ( ! mail.was_validly_signed? || ! mail.signer.admin? )
|
34
|
+
list.logger.info "Rejecting mail as not from admin."
|
35
|
+
return Errors::MessageNotFromAdmin.new(list)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Schleuder
|
2
|
+
module Filters
|
3
|
+
def self.forward_bounce_to_admins(list, mail)
|
4
|
+
if mail.automated_message?
|
5
|
+
list.logger.info "Forwarding automated message to admins"
|
6
|
+
list.logger.notify_admin I18n.t(:forward_automated_message_to_admins), mail.original_message, I18n.t('automated_message_subject')
|
7
|
+
exit
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Schleuder
|
2
|
+
module Filters
|
3
|
+
def self.forward_to_owner(list, mail)
|
4
|
+
return if ! mail.to_owner?
|
5
|
+
|
6
|
+
list.logger.debug "Forwarding addressed to -owner"
|
7
|
+
mail.add_pseudoheader(:note, I18n.t(:owner_forward_prefix))
|
8
|
+
cleanmail = mail.clean_copy(true)
|
9
|
+
list.admins.each do |admin|
|
10
|
+
list.logger.debug "Forwarding message to #{admin}"
|
11
|
+
admin.send_mail(cleanmail)
|
12
|
+
end
|
13
|
+
exit
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Schleuder
|
2
|
+
module Filters
|
3
|
+
|
4
|
+
def self.forward_all_incoming_to_admins(list, mail)
|
5
|
+
if list.forward_all_incoming_to_admins
|
6
|
+
list.logger.notify_admin I18n.t(:forward_all_incoming_to_admins), mail.original_message, I18n.t('incoming_message')
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Schleuder
|
2
|
+
module Filters
|
3
|
+
|
4
|
+
# Outlook / Hotmail seems to dismantle multipart/encrypted messages and
|
5
|
+
# put them again together as multipart/mixed, which is wrong and makes
|
6
|
+
# it problematic to correctly detect the message as a valid pgp/mime-mail.
|
7
|
+
# Here we fix the mail to be a proper pgp/mime aka. multipart/encrypted
|
8
|
+
# message, so further processing will detect it properly.
|
9
|
+
# See #211 and #246 for background
|
10
|
+
def self.fix_hotmail_messages!(list, mail)
|
11
|
+
if mail.header['X-OriginatorOrg'].to_s.match(/(hotmail|outlook).com/) &&
|
12
|
+
!mail[:content_type].blank? &&
|
13
|
+
mail[:content_type].content_type == 'multipart/mixed' && mail.parts.size > 2 &&
|
14
|
+
mail.parts[0][:content_type].content_type == 'text/plain' &&
|
15
|
+
mail.parts[0].body.to_s.blank? &&
|
16
|
+
mail.parts[1][:content_type].content_type == 'application/pgp-encrypted' &&
|
17
|
+
mail.parts[2][:content_type].content_type == 'application/octet-stream'
|
18
|
+
mail.parts.delete_at(0)
|
19
|
+
mail.content_type = [:multipart, :encrypted, {protocol: "application/pgp-encrypted", boundary: mail.boundary}]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Schleuder
|
2
|
+
module Filters
|
3
|
+
|
4
|
+
def self.max_message_size(list, mail)
|
5
|
+
if (mail.raw_source.size / 1024) > list.max_message_size_kb
|
6
|
+
list.logger.info "Rejecting mail as too big"
|
7
|
+
return Errors::MessageTooBig.new(list)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Schleuder
|
2
|
+
module Filters
|
3
|
+
def self.request(list, mail)
|
4
|
+
return if ! mail.request?
|
5
|
+
|
6
|
+
list.logger.debug "Request-message"
|
7
|
+
|
8
|
+
if ! mail.was_encrypted? || ! mail.was_validly_signed?
|
9
|
+
list.logger.debug "Error: Message was not encrypted and validly signed"
|
10
|
+
return Errors::MessageUnauthenticated.new
|
11
|
+
end
|
12
|
+
|
13
|
+
if mail.keywords.empty?
|
14
|
+
output = I18n.t(:no_keywords_error)
|
15
|
+
else
|
16
|
+
output = PluginRunners::RequestPluginsRunner.run(list, mail)
|
17
|
+
output = output.flatten.map(&:presence).compact
|
18
|
+
if output.blank?
|
19
|
+
output = I18n.t(:no_output_result)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
mail.reply_to_signer(output)
|
23
|
+
exit
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Schleuder
|
2
|
+
module Filters
|
3
|
+
def self.send_key(list, mail)
|
4
|
+
return if ! mail.sendkey_request?
|
5
|
+
|
6
|
+
list.logger.debug "Sending public key as reply."
|
7
|
+
|
8
|
+
out = mail.reply
|
9
|
+
out.from = list.email
|
10
|
+
# We're not sending to a subscribed address, so we need to specify a envelope-sender manually.
|
11
|
+
out.sender = list.bounce_address
|
12
|
+
out.body = I18n.t(:list_public_key_attached)
|
13
|
+
out.attach_list_key!(list)
|
14
|
+
# TODO: find out why the gpg-module puts all the headers into the first mime-part, too
|
15
|
+
out.gpg list.gpg_sign_options
|
16
|
+
out.deliver
|
17
|
+
exit
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Schleuder
|
2
|
+
module Filters
|
3
|
+
|
4
|
+
def self.strip_html_from_alternative!(list, mail)
|
5
|
+
if mail[:content_type].blank? ||
|
6
|
+
mail[:content_type].content_type != 'multipart/alternative' ||
|
7
|
+
! mail.to_s.include?('BEGIN PGP ')
|
8
|
+
return false
|
9
|
+
end
|
10
|
+
|
11
|
+
Schleuder.logger.debug "Stripping html-part from multipart/alternative-message"
|
12
|
+
mail.parts.delete_if do |part|
|
13
|
+
part[:content_type].content_type == 'text/html'
|
14
|
+
end
|
15
|
+
mail.content_type = 'multipart/mixed'
|
16
|
+
mail.add_pseudoheader(:note, I18n.t("pseudoheaders.stripped_html_from_multialt"))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module Schleuder
|
2
|
+
module Filters
|
3
|
+
class Runner
|
4
|
+
# To define priority sort this.
|
5
|
+
# The method `setup` parses, decrypts etc.
|
6
|
+
# the mail sent to the list. So before
|
7
|
+
# calling setup we do all the things
|
8
|
+
# that won't require e.g. validation of
|
9
|
+
# the sender.
|
10
|
+
PRE_SETUP_FILTERS = %w[
|
11
|
+
forward_bounce_to_admins
|
12
|
+
forward_all_incoming_to_admins
|
13
|
+
send_key
|
14
|
+
fix_hotmail_messages!
|
15
|
+
strip_html_from_alternative!
|
16
|
+
]
|
17
|
+
# message size must be checked after
|
18
|
+
# decryption as gpg heavily compresses
|
19
|
+
# messages.
|
20
|
+
POST_SETUP_FILTERS = %w[
|
21
|
+
request
|
22
|
+
max_message_size
|
23
|
+
forward_to_owner
|
24
|
+
receive_admin_only
|
25
|
+
receive_authenticated_only
|
26
|
+
receive_signed_only
|
27
|
+
receive_encrypted_only
|
28
|
+
receive_from_subscribed_emailaddresses_only
|
29
|
+
]
|
30
|
+
|
31
|
+
attr_reader :list
|
32
|
+
|
33
|
+
def initialize(list)
|
34
|
+
@list = list
|
35
|
+
end
|
36
|
+
|
37
|
+
def run(mail, filters)
|
38
|
+
filters.map do |cmd|
|
39
|
+
list.logger.debug "Calling filter #{cmd}"
|
40
|
+
response = Filters.send(cmd, list, mail)
|
41
|
+
if stop?(response)
|
42
|
+
if bounce?(response, mail)
|
43
|
+
return response
|
44
|
+
else
|
45
|
+
return nil
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
private
|
52
|
+
|
53
|
+
def stop?(response)
|
54
|
+
response.kind_of?(StandardError)
|
55
|
+
end
|
56
|
+
|
57
|
+
def bounce?(response, mail)
|
58
|
+
if list.bounces_drop_all
|
59
|
+
list.logger.debug "Dropping bounce as configurated"
|
60
|
+
notify_admins(I18n.t('.bounces_drop_all'), mail.original_message)
|
61
|
+
return false
|
62
|
+
end
|
63
|
+
|
64
|
+
list.bounces_drop_on_headers.each do |key, value|
|
65
|
+
if mail[key].to_s.match(/#{value}/i)
|
66
|
+
list.logger.debug "Incoming message header key '#{key}' matches value '#{value}': dropping the bounce."
|
67
|
+
notify_admins(I18n.t('.bounces_drop_on_headers', key: key, value: value), mail.original_message)
|
68
|
+
return false
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
list.logger.debug "Bouncing message"
|
73
|
+
true
|
74
|
+
end
|
75
|
+
|
76
|
+
def notify_admins(reason, original_message)
|
77
|
+
if list.bounces_notify_admins?
|
78
|
+
list.logger.notify_admin reason, original_message, I18n.t('notice')
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|