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,24 @@
|
|
1
|
+
module Schleuder
|
2
|
+
class Cert < Thor
|
3
|
+
extend SubcommandFix
|
4
|
+
|
5
|
+
desc 'generate', 'Generate a new TLS-certificate.'
|
6
|
+
def generate
|
7
|
+
key = Conf.api['tls_key_file']
|
8
|
+
cert = Conf.api['tls_cert_file']
|
9
|
+
fingerprint = SchleuderCertManager.generate('schleuder', key, cert)
|
10
|
+
puts "Fingerprint of generated certificate: #{fingerprint}"
|
11
|
+
puts "Have this fingerprint included into the configuration-file of all clients that want to connect to your Schleuder API."
|
12
|
+
if Process.euid == 0
|
13
|
+
puts "! Warning: this process was run as root — please make sure the above files are accessible by the user that is running `schleuder-api-daemon`."
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'fingerprint', 'Show fingerprint of configured certificate.'
|
18
|
+
def fingerprint
|
19
|
+
cert = Conf.api['tls_cert_file']
|
20
|
+
fingerprint = SchleuderCertManager.fingerprint(cert)
|
21
|
+
say "Fingerprint of #{Conf.api['tls_cert_file']}: #{fingerprint}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
class SchleuderCertManager
|
5
|
+
def self.generate(project_name, filename_key, filename_cert)
|
6
|
+
keysize = 2048
|
7
|
+
subject = "/C=MW/O=Schleuder/OU=#{project_name}"
|
8
|
+
filename_key = Pathname.new(filename_key).expand_path
|
9
|
+
filename_cert = Pathname.new(filename_cert).expand_path
|
10
|
+
|
11
|
+
key = OpenSSL::PKey::RSA.new(keysize)
|
12
|
+
cert = OpenSSL::X509::Certificate.new
|
13
|
+
cert.subject = OpenSSL::X509::Name.parse(subject)
|
14
|
+
cert.issuer = cert.subject
|
15
|
+
cert.not_before = Time.now
|
16
|
+
cert.not_after = Time.now + 10 * 365 * 24 * 60 * 60
|
17
|
+
cert.public_key = key.public_key
|
18
|
+
cert.serial = 0x0
|
19
|
+
cert.version = 2
|
20
|
+
|
21
|
+
ef = OpenSSL::X509::ExtensionFactory.new
|
22
|
+
ef.subject_certificate = cert
|
23
|
+
ef.issuer_certificate = cert
|
24
|
+
cert.extensions = [
|
25
|
+
ef.create_extension("basicConstraints","CA:TRUE", true),
|
26
|
+
ef.create_extension("subjectKeyIdentifier", "hash"),
|
27
|
+
]
|
28
|
+
cert.add_extension ef.create_extension("authorityKeyIdentifier",
|
29
|
+
"keyid:always,issuer:always")
|
30
|
+
|
31
|
+
cert.sign key, OpenSSL::Digest::SHA256.new
|
32
|
+
|
33
|
+
filename_key = prepare_writing(filename_key)
|
34
|
+
filename_cert = prepare_writing(filename_cert)
|
35
|
+
|
36
|
+
filename_key.open('w', 400) do |fd|
|
37
|
+
fd.puts key
|
38
|
+
end
|
39
|
+
puts "Private key written to: #{filename_key}"
|
40
|
+
|
41
|
+
filename_cert.open('w') do |fd|
|
42
|
+
fd.puts cert.to_pem
|
43
|
+
end
|
44
|
+
puts "Certificate written to: #{filename_cert}"
|
45
|
+
|
46
|
+
fingerprint(cert)
|
47
|
+
rescue => exc
|
48
|
+
error exc.message
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.fingerprint(cert)
|
52
|
+
if ! cert.is_a?(OpenSSL::X509::Certificate)
|
53
|
+
path = Pathname.new(cert).expand_path
|
54
|
+
if ! path.readable?
|
55
|
+
error "Error: Not a readable file: #{path}"
|
56
|
+
end
|
57
|
+
cert = OpenSSL::X509::Certificate.new(path.read)
|
58
|
+
end
|
59
|
+
OpenSSL::Digest::SHA256.new(cert.to_der).to_s
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.error(msg)
|
63
|
+
$stderr.puts "Error: #{msg}"
|
64
|
+
exit 1
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.note(msg)
|
68
|
+
$stdout.puts "Note: #{msg}"
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.prepare_writing(filename)
|
72
|
+
if filename.exist?
|
73
|
+
note "File exists: #{filename} — writing to current directory, you should move the file manually or change the configuration file."
|
74
|
+
if filename.basename.exist?
|
75
|
+
error "File exists: #{filename.basename} — (re)move it or fix previous error and try again."
|
76
|
+
end
|
77
|
+
filename = filename.basename
|
78
|
+
end
|
79
|
+
if ! filename.dirname.exist?
|
80
|
+
filename.dirname.mkpath
|
81
|
+
end
|
82
|
+
filename
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Schleuder
|
2
|
+
module SubcommandFix
|
3
|
+
|
4
|
+
# Fixing a bug in Thor where the actual subcommand wouldn't show up
|
5
|
+
# with some invokations of the help-output.
|
6
|
+
def banner(task, namespace = true, subcommand = true)
|
7
|
+
"#{basename} #{task.formatted_usage(self, true, subcommand).split(':').join(' ')}"
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module Schleuder
|
4
|
+
class Conf
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
EMAIL_REGEXP = /\A.+@[[:alnum:]_.-]+\z/i
|
8
|
+
FINGERPRINT_REGEXP = /\A(0x)?[a-f0-9]{32,}\z/i
|
9
|
+
|
10
|
+
DEFAULTS = {
|
11
|
+
'lists_dir' => '/var/lib/schleuder/lists',
|
12
|
+
'listlogs_dir' => '/var/lib/schleuder/lists',
|
13
|
+
'plugins_dir' => '/etc/schleuder/plugins',
|
14
|
+
'log_level' => 'warn',
|
15
|
+
'superadmin' => 'root@localhost',
|
16
|
+
'keyserver' => 'hkp://pool.sks-keyservers.net',
|
17
|
+
'smtp_settings' => {
|
18
|
+
'address' => 'localhost',
|
19
|
+
'port' => 25,
|
20
|
+
'domain' => 'localhost',
|
21
|
+
'enable_starttls_auto' => true,
|
22
|
+
# Don't verify by default because most smtp servers don't include
|
23
|
+
# 'localhost' into their TLS-certificates.
|
24
|
+
'openssl_verify_mode' => 'none',
|
25
|
+
'authentication' => nil,
|
26
|
+
'user_name' => nil,
|
27
|
+
'password' => nil,
|
28
|
+
},
|
29
|
+
'database' => {
|
30
|
+
'production' => {
|
31
|
+
'adapter' => 'sqlite3',
|
32
|
+
'database' => '/var/lib/schleuder/db.sqlite',
|
33
|
+
'timeout' => 5000
|
34
|
+
}
|
35
|
+
},
|
36
|
+
'api' => {
|
37
|
+
'host' => 'localhost',
|
38
|
+
'port' => 4443,
|
39
|
+
'tls_cert_file' => '/etc/schleuder/schleuder-certificate.pem',
|
40
|
+
'tls_key_file' => '/etc/schleuder/schleuder-private-key.pem',
|
41
|
+
'valid_api_keys' => []
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
def config
|
46
|
+
@config ||= load_config(ENV['SCHLEUDER_CONFIG'])
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.lists_dir
|
50
|
+
instance.config['lists_dir']
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.listlogs_dir
|
54
|
+
instance.config['listlogs_dir']
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.plugins_dir
|
58
|
+
instance.config['plugins_dir']
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.database
|
62
|
+
instance.config['database'][ENV['SCHLEUDER_ENV']]
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.databases
|
66
|
+
instance.config['database']
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.superadmin
|
70
|
+
instance.config['superadmin']
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.log_level
|
74
|
+
instance.config['log_level'] || 'WARN'
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.api
|
78
|
+
instance.config['api'] || {}
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.api_valid_api_keys
|
82
|
+
Array(api['valid_api_keys'])
|
83
|
+
end
|
84
|
+
|
85
|
+
# Three legacy options
|
86
|
+
def self.smtp_host
|
87
|
+
instance.config['smtp_host']
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.smtp_port
|
91
|
+
instance.config['smtp_port']
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.smtp_helo_domain
|
95
|
+
instance.config['smtp_helo_domain']
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.smtp_settings
|
99
|
+
settings = instance.config['smtp_settings'] || {}
|
100
|
+
# Support previously used config-options.
|
101
|
+
# Remove this in future versions.
|
102
|
+
{smtp_host: :address, smtp_port: :port, smtp_helo_domain: :domain}.each do |old, new|
|
103
|
+
value = self.send(old)
|
104
|
+
if value.present?
|
105
|
+
Schleuder.logger.warn "Deprecation warning: In schleuder.yml #{old} should be changed to smtp_settings[#{new}]."
|
106
|
+
settings[new] = value
|
107
|
+
end
|
108
|
+
end
|
109
|
+
settings
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.keyserver
|
113
|
+
instance.config['keyserver']
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
def load_config(filename)
|
119
|
+
DEFAULTS.deep_merge(load_config_file(filename))
|
120
|
+
end
|
121
|
+
|
122
|
+
def load_config_file(filename)
|
123
|
+
file = Pathname.new(filename)
|
124
|
+
if file.readable?
|
125
|
+
YAML.load(ERB.new(file.read).result)
|
126
|
+
else
|
127
|
+
{}
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Schleuder
|
2
|
+
module Errors
|
3
|
+
class DecryptionFailed < Base
|
4
|
+
def initialize(list)
|
5
|
+
set_default_locale
|
6
|
+
@list = list
|
7
|
+
end
|
8
|
+
|
9
|
+
def message
|
10
|
+
t('errors.decryption_failed',
|
11
|
+
{ key: @list.key.to_s,
|
12
|
+
email: @list.sendkey_address })
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Schleuder
|
2
|
+
module Errors
|
3
|
+
class KeyGenerationFailed < Base
|
4
|
+
def initialize(listdir, listname)
|
5
|
+
@listdir = listdir
|
6
|
+
@listname = listname
|
7
|
+
end
|
8
|
+
|
9
|
+
def message
|
10
|
+
t('errors.key_generation_failed',
|
11
|
+
{ listdir: @listdir,
|
12
|
+
listname: @listname })
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Schleuder
|
2
|
+
module Errors
|
3
|
+
class ListPropertyMissing < Base
|
4
|
+
def initialize(listdir, property)
|
5
|
+
@listdir = listdir
|
6
|
+
@property = property
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_s
|
10
|
+
t("errors.list_#{@property}_missing", listdir: @listdir)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Schleuder
|
2
|
+
module Errors
|
3
|
+
class ListdirProblem < Base
|
4
|
+
def initialize(dir, problem)
|
5
|
+
@dir = dir
|
6
|
+
@problem = problem
|
7
|
+
end
|
8
|
+
|
9
|
+
def message
|
10
|
+
problem = t("errors.listdir_problem.#{@problem}")
|
11
|
+
t('errors.listdir_problem.message', dir: @dir, problem: problem)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|