schleuder 2.2.4 → 3.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +138 -0
  3. data/Rakefile +136 -0
  4. data/bin/pinentry-clearpassphrase +72 -0
  5. data/bin/schleuder +9 -89
  6. data/bin/schleuder-api-daemon +4 -0
  7. data/db/migrate/20140501103532_create_lists.rb +39 -0
  8. data/db/migrate/20140501112859_create_subscriptions.rb +21 -0
  9. data/db/migrate/201508092100_add_language_to_lists.rb +11 -0
  10. data/db/migrate/20150812165700_change_keywords_admin_only_defaults.rb +8 -0
  11. data/db/migrate/20150813235800_add_forward_all_incoming_to_admins.rb +11 -0
  12. data/db/migrate/201508141727_change_send_encrypted_only_default.rb +8 -0
  13. data/db/migrate/201508222143_add_logfiles_to_keep_to_lists.rb +11 -0
  14. data/db/migrate/201508261723_rename_delivery_disabled_to_delivery_enabled_and_change_default.rb +14 -0
  15. data/db/migrate/201508261815_strip_gpg_passphrase.rb +11 -0
  16. data/db/migrate/201508261827_remove_default_mime.rb +9 -0
  17. data/db/migrate/20160501172700_fix_headers_to_meta_defaults.rb +8 -0
  18. data/db/migrate/20170713215059_add_internal_footer_to_list.rb +11 -0
  19. data/db/schema.rb +62 -0
  20. data/etc/init.d/schleuder-api-daemon +87 -0
  21. data/etc/list-defaults.yml +123 -0
  22. data/etc/postfix/schleuder_sqlite.cf +28 -0
  23. data/etc/schleuder-api-daemon.service +10 -0
  24. data/etc/schleuder.cron.weekly +6 -0
  25. data/etc/schleuder.yml +61 -0
  26. data/lib/schleuder-api-daemon.rb +420 -0
  27. data/lib/schleuder.rb +81 -47
  28. data/lib/schleuder/cli.rb +334 -0
  29. data/lib/schleuder/cli/cert.rb +24 -0
  30. data/lib/schleuder/cli/schleuder_cert_manager.rb +84 -0
  31. data/lib/schleuder/cli/subcommand_fix.rb +11 -0
  32. data/lib/schleuder/conf.rb +131 -0
  33. data/lib/schleuder/errors/active_model_error.rb +15 -0
  34. data/lib/schleuder/errors/base.rb +17 -0
  35. data/lib/schleuder/errors/decryption_failed.rb +16 -0
  36. data/lib/schleuder/errors/fatal_error.rb +13 -0
  37. data/lib/schleuder/errors/file_not_found.rb +14 -0
  38. data/lib/schleuder/errors/invalid_listname.rb +13 -0
  39. data/lib/schleuder/errors/key_adduid_failed.rb +13 -0
  40. data/lib/schleuder/errors/key_generation_failed.rb +16 -0
  41. data/lib/schleuder/errors/keyword_admin_only.rb +13 -0
  42. data/lib/schleuder/errors/list_exists.rb +13 -0
  43. data/lib/schleuder/errors/list_not_found.rb +14 -0
  44. data/lib/schleuder/errors/list_property_missing.rb +14 -0
  45. data/lib/schleuder/errors/listdir_problem.rb +16 -0
  46. data/lib/schleuder/errors/loading_list_settings_failed.rb +14 -0
  47. data/lib/schleuder/errors/message_empty.rb +14 -0
  48. data/lib/schleuder/errors/message_not_from_admin.rb +13 -0
  49. data/lib/schleuder/errors/message_sender_not_subscribed.rb +13 -0
  50. data/lib/schleuder/errors/message_too_big.rb +14 -0
  51. data/lib/schleuder/errors/message_unauthenticated.rb +13 -0
  52. data/lib/schleuder/errors/message_unencrypted.rb +13 -0
  53. data/lib/schleuder/errors/message_unsigned.rb +13 -0
  54. data/lib/schleuder/errors/standard_error.rb +5 -0
  55. data/lib/schleuder/errors/too_many_keys.rb +17 -0
  56. data/lib/schleuder/errors/unknown_list_option.rb +14 -0
  57. data/lib/schleuder/filters/auth_filter.rb +39 -0
  58. data/lib/schleuder/filters/bounces_filter.rb +12 -0
  59. data/lib/schleuder/filters/forward_filter.rb +17 -0
  60. data/lib/schleuder/filters/forward_incoming.rb +13 -0
  61. data/lib/schleuder/filters/hotmail_message_filter.rb +25 -0
  62. data/lib/schleuder/filters/max_message_size.rb +14 -0
  63. data/lib/schleuder/filters/request_filter.rb +26 -0
  64. data/lib/schleuder/filters/send_key_filter.rb +20 -0
  65. data/lib/schleuder/filters/strip_alternative_filter.rb +21 -0
  66. data/lib/schleuder/filters_runner.rb +83 -0
  67. data/lib/schleuder/gpgme/ctx.rb +274 -0
  68. data/lib/schleuder/gpgme/import_status.rb +27 -0
  69. data/lib/schleuder/gpgme/key.rb +212 -0
  70. data/lib/schleuder/gpgme/sub_key.rb +13 -0
  71. data/lib/schleuder/gpgme/user_id.rb +22 -0
  72. data/lib/schleuder/list.rb +318 -127
  73. data/lib/schleuder/list_builder.rb +139 -0
  74. data/lib/schleuder/listlogger.rb +31 -0
  75. data/lib/schleuder/logger.rb +23 -0
  76. data/lib/schleuder/logger_notifications.rb +69 -0
  77. data/lib/schleuder/mail/message.rb +482 -0
  78. data/lib/schleuder/mail/parts_list.rb +9 -0
  79. data/lib/schleuder/plugin_runners/base.rb +91 -0
  80. data/lib/schleuder/plugin_runners/list_plugins_runner.rb +24 -0
  81. data/lib/schleuder/plugin_runners/request_plugins_runner.rb +27 -0
  82. data/lib/schleuder/plugins/attach_listkey.rb +17 -0
  83. data/lib/schleuder/plugins/get_version.rb +7 -0
  84. data/lib/schleuder/plugins/key_management.rb +113 -0
  85. data/lib/schleuder/plugins/list_management.rb +15 -0
  86. data/lib/schleuder/plugins/resend.rb +196 -0
  87. data/lib/schleuder/plugins/sign_this.rb +46 -0
  88. data/lib/schleuder/plugins/subscription_management.rb +140 -0
  89. data/lib/schleuder/runner.rb +130 -0
  90. data/lib/schleuder/subscription.rb +98 -0
  91. data/lib/schleuder/validators/boolean_validator.rb +7 -0
  92. data/lib/schleuder/validators/email_validator.rb +7 -0
  93. data/lib/schleuder/validators/fingerprint_validator.rb +7 -0
  94. data/lib/schleuder/validators/greater_than_zero_validator.rb +7 -0
  95. data/lib/schleuder/validators/no_line_breaks_validator.rb +7 -0
  96. data/lib/schleuder/version.rb +1 -1
  97. data/locales/de.yml +179 -0
  98. data/locales/en.yml +179 -0
  99. metadata +305 -108
  100. checksums.yaml.gz.sig +0 -3
  101. data.tar.gz.sig +0 -2
  102. data/LICENSE +0 -339
  103. data/README +0 -32
  104. data/bin/schleuder-fix-gem-dependencies +0 -37
  105. data/bin/schleuder-init-setup +0 -37
  106. data/bin/schleuder-migrate-v2.1-to-v2.2 +0 -225
  107. data/bin/schleuder-newlist +0 -413
  108. data/contrib/check-expired-keys.rb +0 -60
  109. data/contrib/mutt-schleuder-colors.rc +0 -10
  110. data/contrib/mutt-schleuder-resend.vim +0 -24
  111. data/contrib/smtpserver.rb +0 -76
  112. data/ext/default-list.conf +0 -149
  113. data/ext/default-members.conf +0 -7
  114. data/ext/list.conf.example +0 -14
  115. data/ext/schleuder.conf +0 -64
  116. data/lib/schleuder/archiver.rb +0 -46
  117. data/lib/schleuder/crypt.rb +0 -210
  118. data/lib/schleuder/errors.rb +0 -5
  119. data/lib/schleuder/list_config.rb +0 -146
  120. data/lib/schleuder/log/listlogger.rb +0 -57
  121. data/lib/schleuder/log/outputter/emailoutputter.rb +0 -120
  122. data/lib/schleuder/log/outputter/metaemailoutputter.rb +0 -50
  123. data/lib/schleuder/log/schleuderlogger.rb +0 -34
  124. data/lib/schleuder/mail.rb +0 -873
  125. data/lib/schleuder/mailer.rb +0 -26
  126. data/lib/schleuder/member.rb +0 -69
  127. data/lib/schleuder/plugin.rb +0 -54
  128. data/lib/schleuder/processor.rb +0 -363
  129. data/lib/schleuder/schleuder_config.rb +0 -75
  130. data/lib/schleuder/storage.rb +0 -84
  131. data/lib/schleuder/utils.rb +0 -80
  132. data/man/schleuder-newlist.8 +0 -174
  133. data/man/schleuder.8 +0 -416
  134. data/plugins/README +0 -20
  135. data/plugins/manage_keys_plugin.rb +0 -113
  136. data/plugins/manage_members_plugin.rb +0 -156
  137. data/plugins/manage_self_plugin.rb +0 -26
  138. data/plugins/resend_plugin.rb +0 -35
  139. data/plugins/sign_this_plugin.rb +0 -14
  140. data/plugins/version_plugin.rb +0 -12
  141. 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,15 @@
1
+ module Schleuder
2
+ module Errors
3
+ class ActiveModelError < Base
4
+ def initialize(errors)
5
+ @errors = errors
6
+ end
7
+
8
+ def message
9
+ @errors.messages.map do |message|
10
+ message.join(' ')
11
+ end.join("\n")
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ module Schleuder
2
+ module Errors
3
+ class Base < StandardError
4
+ def t(*args)
5
+ I18n.t(*args)
6
+ end
7
+
8
+ def to_s
9
+ super + t('errors.signoff')
10
+ end
11
+
12
+ def set_default_locale
13
+ I18n.locale = I18n.default_locale
14
+ end
15
+ end
16
+ end
17
+ 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,13 @@
1
+ module Schleuder
2
+ module Errors
3
+ class FatalError < Base
4
+ def initialize
5
+ end
6
+
7
+ def to_s
8
+ t("errors.fatalerror")
9
+ end
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,14 @@
1
+ module Schleuder
2
+ module Errors
3
+ class FileNotFound < Base
4
+ def initialize(file)
5
+ @file = file
6
+ end
7
+
8
+ def message
9
+ t('errors.file_not_found', file: @file)
10
+ end
11
+ end
12
+ end
13
+ end
14
+
@@ -0,0 +1,13 @@
1
+ module Schleuder
2
+ module Errors
3
+ class InvalidListname < Base
4
+ def initialize(listname)
5
+ @listname = listname
6
+ end
7
+
8
+ def message
9
+ t('errors.invalid_listname', email: @listname)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Schleuder
2
+ module Errors
3
+ class KeyAdduidFailed < Base
4
+ def initialize(errmsg)
5
+ @errmsg = errmsg
6
+ end
7
+
8
+ def message
9
+ t('errors.key_adduid_failed', { errmsg: @errmsg })
10
+ end
11
+ end
12
+ end
13
+ 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,13 @@
1
+ module Schleuder
2
+ module Errors
3
+ class KeywordAdminOnly < Base
4
+ def initialize(keyword)
5
+ @keyword = keyword
6
+ end
7
+
8
+ def message
9
+ t('errors.keyword_admin_only', keyword: @keyword)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Schleuder
2
+ module Errors
3
+ class ListExists < Base
4
+ def initialize(listname)
5
+ @listname = listname
6
+ end
7
+
8
+ def message
9
+ t('errors.list_exists', email: @listname)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ module Schleuder
2
+ module Errors
3
+ class ListNotFound < Base
4
+ def initialize(recipient)
5
+ @recipient = recipient
6
+ end
7
+
8
+ def message
9
+ t('errors.list_not_found', email: @recipient)
10
+ end
11
+ end
12
+ end
13
+ end
14
+
@@ -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
+