schleuder 3.5.3 → 4.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +10 -21
  3. data/Rakefile +15 -12
  4. data/bin/schleuder +1 -1
  5. data/db/migrate/20140501103532_create_lists.rb +1 -1
  6. data/db/migrate/20140501112859_create_subscriptions.rb +1 -1
  7. data/db/migrate/{201508092100_add_language_to_lists.rb → 20150809210000_add_language_to_lists.rb} +1 -1
  8. data/db/migrate/20150812165700_change_keywords_admin_only_defaults.rb +1 -1
  9. data/db/migrate/20150813235800_add_forward_all_incoming_to_admins.rb +1 -1
  10. data/db/migrate/{201508141727_change_send_encrypted_only_default.rb → 20150814172700_change_send_encrypted_only_default.rb} +1 -1
  11. data/db/migrate/{201508222143_add_logfiles_to_keep_to_lists.rb → 20150822214300_add_logfiles_to_keep_to_lists.rb} +1 -1
  12. data/db/migrate/{201508261723_rename_delivery_disabled_to_delivery_enabled_and_change_default.rb → 20150826172300_rename_delivery_disabled_to_delivery_enabled_and_change_default.rb} +1 -1
  13. data/db/migrate/{201508261815_strip_gpg_passphrase.rb → 20150826181500_strip_gpg_passphrase.rb} +1 -1
  14. data/db/migrate/{201508261827_remove_default_mime.rb → 20150826182700_remove_default_mime.rb} +1 -1
  15. data/db/migrate/20160501172700_fix_headers_to_meta_defaults.rb +1 -1
  16. data/db/migrate/20170713215059_add_internal_footer_to_list.rb +1 -1
  17. data/db/migrate/20180110203100_add_sig_enc_to_headers_to_meta_defaults.rb +1 -1
  18. data/db/migrate/20180723173900_add_deliver_selfsent_to_list.rb +1 -1
  19. data/db/migrate/20190906194820_add_autocrypt_header_to_list.rb +1 -1
  20. data/db/migrate/20200118170110_add_set_reply_to_to_sender_and_munge_from.rb +15 -0
  21. data/db/schema.rb +45 -45
  22. data/etc/list-defaults.yml +18 -0
  23. data/etc/postfix/schleuder_sqlite.cf +1 -1
  24. data/etc/schleuder-weekly-key-maintenance.service +9 -0
  25. data/etc/schleuder-weekly-key-maintenance.timer +9 -0
  26. data/etc/schleuder.yml +3 -3
  27. data/lib/schleuder-api-daemon/helpers/schleuder-api-daemon-helper.rb +3 -3
  28. data/lib/schleuder-api-daemon/routes/subscription.rb +4 -4
  29. data/lib/schleuder.rb +13 -12
  30. data/lib/schleuder/cli.rb +9 -189
  31. data/lib/schleuder/cli/cert.rb +2 -2
  32. data/lib/schleuder/cli/cli_helper.rb +14 -0
  33. data/lib/schleuder/cli/schleuder_cert_manager.rb +4 -4
  34. data/lib/schleuder/conf.rb +4 -4
  35. data/lib/schleuder/errors/base.rb +2 -2
  36. data/lib/schleuder/errors/decryption_failed.rb +1 -1
  37. data/lib/schleuder/errors/fatal_error.rb +1 -1
  38. data/lib/schleuder/errors/key_adduid_failed.rb +1 -1
  39. data/lib/schleuder/errors/key_generation_failed.rb +1 -1
  40. data/lib/schleuder/errors/message_empty.rb +1 -1
  41. data/lib/schleuder/errors/message_too_big.rb +1 -1
  42. data/lib/schleuder/errors/too_many_keys.rb +1 -1
  43. data/lib/schleuder/filters/post_decryption/10_request.rb +3 -3
  44. data/lib/schleuder/filters/post_decryption/20_max_message_size.rb +1 -1
  45. data/lib/schleuder/filters/post_decryption/30_forward_to_owner.rb +1 -1
  46. data/lib/schleuder/filters/post_decryption/40_receive_admin_only.rb +1 -1
  47. data/lib/schleuder/filters/post_decryption/50_receive_authenticated_only.rb +1 -1
  48. data/lib/schleuder/filters/post_decryption/60_receive_signed_only.rb +1 -1
  49. data/lib/schleuder/filters/post_decryption/70_receive_encrypted_only.rb +1 -1
  50. data/lib/schleuder/filters/post_decryption/80_receive_from_subscribed_emailaddresses_only.rb +1 -1
  51. data/lib/schleuder/filters/pre_decryption/10_forward_bounce_to_admins.rb +1 -1
  52. data/lib/schleuder/filters/pre_decryption/30_send_key.rb +1 -1
  53. data/lib/schleuder/filters/pre_decryption/40_fix_exchange_messages.rb +1 -1
  54. data/lib/schleuder/filters/pre_decryption/50_strip_html_from_alternative.rb +2 -2
  55. data/lib/schleuder/filters_runner.rb +9 -9
  56. data/lib/schleuder/gpgme/ctx.rb +15 -67
  57. data/lib/schleuder/gpgme/key.rb +4 -136
  58. data/lib/schleuder/gpgme/user_id.rb +2 -0
  59. data/lib/schleuder/keyword_handlers/attach_list_key.rb +17 -0
  60. data/lib/schleuder/keyword_handlers/base.rb +36 -0
  61. data/lib/schleuder/keyword_handlers/get_version.rb +11 -0
  62. data/lib/schleuder/keyword_handlers/key_management.rb +141 -0
  63. data/lib/schleuder/keyword_handlers/list_management.rb +19 -0
  64. data/lib/schleuder/keyword_handlers/resend.rb +208 -0
  65. data/lib/schleuder/keyword_handlers/sign_this.rb +54 -0
  66. data/lib/schleuder/keyword_handlers/subscription_management.rb +213 -0
  67. data/lib/schleuder/keyword_handlers_runner.rb +146 -0
  68. data/lib/schleuder/list.rb +28 -40
  69. data/lib/schleuder/list_builder.rb +16 -5
  70. data/lib/schleuder/listlogger.rb +1 -1
  71. data/lib/schleuder/logger.rb +2 -6
  72. data/lib/schleuder/mail/{encrypted_part.rb → gpg/encrypted_part.rb} +0 -0
  73. data/lib/schleuder/mail/gpg/sign_part.rb +33 -0
  74. data/lib/schleuder/mail/message.rb +135 -40
  75. data/lib/schleuder/runner.rb +18 -16
  76. data/lib/schleuder/subscription.rb +35 -13
  77. data/lib/schleuder/validators/boolean_validator.rb +1 -1
  78. data/lib/schleuder/validators/email_validator.rb +1 -1
  79. data/lib/schleuder/validators/fingerprint_validator.rb +1 -1
  80. data/lib/schleuder/validators/greater_than_zero_validator.rb +1 -1
  81. data/lib/schleuder/validators/no_line_breaks_validator.rb +1 -1
  82. data/lib/schleuder/version.rb +1 -1
  83. data/locales/de.yml +49 -36
  84. data/locales/en.yml +34 -21
  85. metadata +131 -79
  86. data/bin/pinentry-clearpassphrase +0 -72
  87. data/lib/schleuder/plugin_runners/base.rb +0 -91
  88. data/lib/schleuder/plugin_runners/list_plugins_runner.rb +0 -24
  89. data/lib/schleuder/plugin_runners/request_plugins_runner.rb +0 -27
  90. data/lib/schleuder/plugins/attach_listkey.rb +0 -13
  91. data/lib/schleuder/plugins/get_version.rb +0 -7
  92. data/lib/schleuder/plugins/key_management.rb +0 -121
  93. data/lib/schleuder/plugins/list_management.rb +0 -15
  94. data/lib/schleuder/plugins/resend.rb +0 -199
  95. data/lib/schleuder/plugins/sign_this.rb +0 -46
  96. data/lib/schleuder/plugins/subscription_management.rb +0 -207
@@ -0,0 +1,54 @@
1
+ module Schleuder
2
+ module KeywordHandlers
3
+ class SignThis < Base
4
+ handles_request_keyword 'sign-this', with_method: :sign_this
5
+
6
+ def sign_this
7
+ if @mail.has_attachments?
8
+ @list.logger.debug "Signing each attachment's body"
9
+ intro = I18n.t('keyword_handlers.sign_this.signatures_attached')
10
+ parts = @mail.attachments.map do |attachment|
11
+ make_signature_part(attachment)
12
+ end
13
+ [intro, parts].flatten
14
+ elsif @mail.first_plaintext_part.body.to_s.present?
15
+ @list.logger.debug 'Clear-signing first available text/plain part'
16
+ clearsign(@mail.first_plaintext_part.body.to_s)
17
+ else
18
+ @list.logger.debug 'Found no attachments and an empty body - sending error message'
19
+ I18n.t('keyword_handlers.sign_this.no_content_found')
20
+ end
21
+ end
22
+
23
+
24
+ private
25
+
26
+
27
+ def make_signature_part(attachment)
28
+ material = attachment.body.to_s
29
+ return nil if material.strip.blank?
30
+ file_basename = attachment.filename.presence || Digest::SHA256.hexdigest(material)
31
+ @list.logger.debug "Signing #{file_basename}"
32
+ filename = "#{file_basename}.sig"
33
+ part = Mail::Part.new
34
+ part.body = detachsign(material)
35
+ part.content_type = 'application/pgp-signature'
36
+ part.content_disposition = "attachment; filename=#{filename}"
37
+ part.content_description = "OpenPGP signature for '#{file_basename}'"
38
+ part
39
+ end
40
+
41
+ def detachsign(thing)
42
+ crypto.sign(thing, mode: GPGME::SIG_MODE_DETACH).to_s
43
+ end
44
+
45
+ def clearsign(string)
46
+ crypto.clearsign(string.to_s).to_s
47
+ end
48
+
49
+ def crypto
50
+ @crypto ||= GPGME::Crypto.new(armor: true)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,213 @@
1
+ module Schleuder
2
+ module KeywordHandlers
3
+ class SubscriptionManangement < Base
4
+ handles_request_keyword 'subscribe', with_method: :subscribe
5
+ handles_request_keyword 'unsubscribe', with_method: :unsubscribe
6
+ handles_request_keyword 'list-subscriptions', with_method: :list_subscriptions
7
+ handles_request_keyword 'set-fingerprint', with_method: :set_fingerprint
8
+ handles_request_keyword 'unset-fingerprint', with_method: :unset_fingerprint
9
+
10
+ def subscribe
11
+ if @arguments.blank?
12
+ return I18n.t(
13
+ 'keyword_handlers.subscription_management.subscribe_requires_arguments'
14
+ )
15
+ end
16
+
17
+ email = @arguments.shift.to_s.downcase
18
+
19
+ if @arguments.present?
20
+ # Collect all arguments that look like fingerprint-material
21
+ fingerprint = ''
22
+ while @arguments.first.present? && @arguments.first.match(/^(0x)?[a-f0-9]+$/i)
23
+ fingerprint << @arguments.shift.downcase
24
+ end
25
+ # Use possibly remaining args as flags.
26
+ adminflag = @arguments.shift.to_s.downcase.presence
27
+ deliveryflag = @arguments.shift.to_s.downcase.presence
28
+ end
29
+
30
+ sub, _ = @list.subscribe(email, fingerprint, adminflag, deliveryflag)
31
+
32
+ if sub.persisted?
33
+ I18n.t(
34
+ 'keyword_handlers.subscription_management.subscribed',
35
+ email: sub.email,
36
+ fingerprint: sub.fingerprint,
37
+ admin: sub.admin,
38
+ delivery_enabled: sub.delivery_enabled
39
+ )
40
+ else
41
+ I18n.t(
42
+ 'keyword_handlers.subscription_management.subscribing_failed',
43
+ email: sub.email,
44
+ errors: sub.errors.full_messages.join(".\n")
45
+ )
46
+ end
47
+ end
48
+
49
+ def unsubscribe
50
+ # If no address was given we unsubscribe the sender.
51
+ email = @arguments.first.to_s.downcase.presence || @mail.signer.email
52
+
53
+ # Refuse to unsubscribe the last admin.
54
+ if @list.admins.size == 1 && @list.admins.first.email == email
55
+ return I18n.t(
56
+ 'keyword_handlers.subscription_management.cannot_unsubscribe_last_admin', email: email
57
+ )
58
+ end
59
+
60
+ # TODO: May signers have multiple UIDs? We don't match those currently.
61
+ if ! @list.from_admin?(@mail) && email != @mail.signer.email
62
+ # Only admins may unsubscribe others.
63
+ return I18n.t(
64
+ 'keyword_handlers.subscription_management.forbidden', email: email
65
+ )
66
+ end
67
+
68
+ sub = @list.subscriptions.where(email: email).first
69
+
70
+ if sub.blank?
71
+ return I18n.t(
72
+ 'keyword_handlers.subscription_management.is_not_subscribed', email: email
73
+ )
74
+ end
75
+
76
+ if res = sub.delete
77
+ I18n.t(
78
+ 'keyword_handlers.subscription_management.unsubscribed', email: email
79
+ )
80
+ else
81
+ I18n.t(
82
+ 'keyword_handlers.subscription_management.unsubscribing_failed',
83
+ email: email,
84
+ error: res.errors.to_a
85
+ )
86
+ end
87
+ end
88
+
89
+ def list_subscriptions
90
+ subs = if @arguments.blank?
91
+ @list.subscriptions.all.to_a
92
+ else
93
+ @arguments.map do |argument|
94
+ @list.subscriptions.where('email like ?', "%#{argument}%").to_a
95
+ end.flatten
96
+ end
97
+
98
+ if subs.blank?
99
+ return nil
100
+ end
101
+
102
+ out = [ I18n.t('keyword_handlers.subscription_management.list_of_subscriptions') ]
103
+
104
+ out << subs.map do |subscription|
105
+ # Fingerprints are at most 40 characters long, and lines shouldn't
106
+ # exceed 80 characters if possible.
107
+ s = subscription.email
108
+ if subscription.fingerprint.present?
109
+ s << "\t0x#{subscription.fingerprint}"
110
+ end
111
+ if ! subscription.delivery_enabled?
112
+ s << "\tDelivery disabled!"
113
+ end
114
+ s
115
+ end
116
+
117
+ out.join("\n")
118
+ end
119
+
120
+ def set_fingerprint
121
+ if @arguments.blank?
122
+ return I18n.t(
123
+ 'keyword_handlers.subscription_management.set_fingerprint_requires_arguments'
124
+ )
125
+ end
126
+
127
+ if @arguments.first.match(/@/)
128
+ email = @arguments.shift.downcase
129
+ if email != @mail.signer.email && ! @list.from_admin?(@mail)
130
+ return I18n.t(
131
+ 'keyword_handlers.subscription_management.set_fingerprint_only_self'
132
+ )
133
+ end
134
+ else
135
+ email = @mail.signer.email
136
+ end
137
+
138
+ sub = @list.subscriptions.where(email: email).first
139
+
140
+ if sub.blank?
141
+ return I18n.t(
142
+ 'keyword_handlers.subscription_management.is_not_subscribed', email: email
143
+ )
144
+ end
145
+
146
+ fingerprint = @arguments.join
147
+ unless GPGME::Key.valid_fingerprint?(fingerprint)
148
+ return I18n.t(
149
+ 'keyword_handlers.subscription_management.set_fingerprint_requires_valid_fingerprint',
150
+ fingerprint: fingerprint
151
+ )
152
+ end
153
+
154
+ sub.fingerprint = fingerprint
155
+ if sub.save
156
+ I18n.t(
157
+ 'keyword_handlers.subscription_management.fingerprint_set',
158
+ email: email,
159
+ fingerprint: sub.fingerprint
160
+ )
161
+ else
162
+ I18n.t(
163
+ 'keyword_handlers.subscription_management.setting_fingerprint_failed',
164
+ email: email,
165
+ fingerprint: sub.fingerprint,
166
+ errors: sub.errors.to_a.join("\n")
167
+ )
168
+ end
169
+ end
170
+
171
+ def unset_fingerprint
172
+ if @arguments.blank?
173
+ return I18n.t(
174
+ 'keyword_handlers.subscription_management.unset_fingerprint_requires_arguments'
175
+ )
176
+ end
177
+
178
+ email = @arguments.shift.to_s.downcase
179
+ if email != @mail.signer.email && ! @list.from_admin?(mail)
180
+ return I18n.t(
181
+ 'keyword_handlers.subscription_management.unset_fingerprint_only_self'
182
+ )
183
+ end
184
+ if email == @mail.signer.email && @list.from_admin?(@mail) && @arguments.last.to_s.downcase != 'force'
185
+ return I18n.t(
186
+ 'keyword_handlers.subscription_management.unset_fingerprint_requires_arguments'
187
+ )
188
+ end
189
+
190
+ sub = @list.subscriptions.where(email: email).first
191
+ if sub.blank?
192
+ return I18n.t(
193
+ 'keyword_handlers.subscription_management.is_not_subscribed', email: email
194
+ )
195
+ end
196
+
197
+ sub.fingerprint = ''
198
+ if sub.save
199
+ I18n.t(
200
+ 'keyword_handlers.subscription_management.fingerprint_unset',
201
+ email: email
202
+ )
203
+ else
204
+ I18n.t(
205
+ 'keyword_handlers.subscription_management.unsetting_fingerprint_failed',
206
+ email: email,
207
+ errors: sub.errors.to_a.join("\n")
208
+ )
209
+ end
210
+ end
211
+ end
212
+ end
213
+ end
@@ -0,0 +1,146 @@
1
+ module Schleuder
2
+ class KeywordHandlersRunner
3
+ REGISTERED_KEYWORDS = {list: {}, request: {}}
4
+ RESERVED_KEYWORDS = %w[list-name]
5
+
6
+ class << self
7
+ attr_reader :keywords
8
+
9
+ def register_keyword(type:, keyword:, handler_class:, handler_method:, aliases:)
10
+ assert_valid_input!(type: type, keyword: keyword, handler_class: handler_class, handler_method: handler_method)
11
+
12
+ identifiers = [keyword] + Array(aliases)
13
+ identifiers.each do |identifier|
14
+ REGISTERED_KEYWORDS[type.to_sym][identifier.to_s.dasherize] = {
15
+ klass: handler_class,
16
+ method: handler_method.to_sym
17
+ }
18
+ end
19
+ end
20
+
21
+ def run(type:, list:, mail:)
22
+ list.logger.debug "Starting #{self}"
23
+ assert_valid_type!(type)
24
+ load_additional_keyword_handlers
25
+
26
+ error = check_unknown_keywords(mail, type)
27
+ return error if error.present?
28
+
29
+ error = check_mandatory_keywords(mail, list)
30
+ return [error] if error.present?
31
+
32
+ output = mail.keywords.map do |keyword, arguments|
33
+ if ! is_reserved_keyword?(keyword)
34
+ run_handler(mail, list, type, keyword.to_s.dasherize, Array(arguments))
35
+ end
36
+ end
37
+
38
+ output.flatten.compact
39
+ end
40
+
41
+
42
+ private
43
+
44
+
45
+ def check_unknown_keywords(mail, type)
46
+ known_keywords = REGISTERED_KEYWORDS[type.to_sym].keys + RESERVED_KEYWORDS
47
+ given_keywords = mail.keywords.map(&:first)
48
+ unknown_keywords = given_keywords - known_keywords
49
+ if unknown_keywords.present?
50
+ error_messages = unknown_keywords.map do |keyword|
51
+ I18n.t('errors.unknown_keyword', keyword: keyword)
52
+ end
53
+ return error_messages
54
+ end
55
+ end
56
+
57
+ def run_handler(mail, list, type, keyword, arguments)
58
+ list.logger.debug "run_handler() with keyword '#{keyword}'"
59
+
60
+ if list.admin_only?(keyword) && !list.from_admin?(mail)
61
+ return Schleuder::Errors::KeywordAdminOnly.new(keyword).to_s
62
+ end
63
+
64
+ keyword_data = REGISTERED_KEYWORDS[type.to_sym][keyword]
65
+ handler_class = keyword_data[:klass]
66
+ handler_method = keyword_data[:method]
67
+ output = handler_class.new(mail: mail, arguments: arguments).send(handler_method)
68
+
69
+ if list.keywords_admin_notify.include?(keyword)
70
+ notify_admins(type, mail, list, keyword, arguments, output)
71
+ end
72
+ return output
73
+ rescue => exc
74
+ # Log to system, this information is probably more useful for
75
+ # system-admins than for list-admins.
76
+ Schleuder.logger.error(exc.message_with_backtrace)
77
+ I18n.t('keyword_handlers.handler_failed', keyword: keyword)
78
+ end
79
+
80
+ def notify_admins(type, mail, list, keyword, arguments, response)
81
+ msg = I18n.t("keyword_handlers.keyword_admin_notify.#{type}",
82
+ sender: mail.signer,
83
+ keyword: keyword,
84
+ arguments: arguments.join(' '),
85
+ response: Array(response).join("\n\n")
86
+ )
87
+ list.logger.notify_admin(msg, nil, 'Notice')
88
+ end
89
+
90
+ def load_additional_keyword_handlers
91
+ Dir["#{Schleuder::Conf.keyword_handlers_dir}/*.rb"].each do |file|
92
+ load file
93
+ end
94
+ end
95
+
96
+ def check_mandatory_keywords(mail, list)
97
+ return nil if mail.keywords.blank?
98
+
99
+ listname_keyword = mail.keywords.assoc('list-name')
100
+ if listname_keyword.blank?
101
+ return I18n.t(:missing_listname_keyword_error)
102
+ else
103
+ listname_args = listname_keyword.last
104
+ if ! [list.email, list.request_address].include?(listname_args.first)
105
+ return I18n.t(:wrong_listname_keyword_error)
106
+ end
107
+ end
108
+ end
109
+
110
+ def is_reserved_keyword?(keyword)
111
+ RESERVED_KEYWORDS.include?(keyword)
112
+ end
113
+
114
+ def assert_valid_input!(type:, keyword:, handler_class:, handler_method:)
115
+ assert_valid_type!(type)
116
+ assert_valid_keyword!(keyword)
117
+ assert_valid_handler_class!(handler_class)
118
+ assert_valid_handler_method!(handler_method)
119
+ end
120
+
121
+ def assert_valid_type!(type)
122
+ if ! REGISTERED_KEYWORDS.keys.include?(type)
123
+ raise ArgumentError.new("Argument must be one of #{REGISTERED_KEYWORDS.keys.inspect}, got: #{type.inspect}")
124
+ end
125
+ end
126
+
127
+ def assert_valid_keyword!(keyword)
128
+ if keyword.blank?
129
+ raise ArgumentError.new("Invalid keyword: #{keyword.inspect}")
130
+ end
131
+ end
132
+
133
+ def assert_valid_handler_class!(handler_class)
134
+ if ! handler_class.is_a?(Class)
135
+ raise ArgumentError.new("Invalid input for handler_class: #{handler_class.inspect} is not a class")
136
+ end
137
+ end
138
+
139
+ def assert_valid_handler_method!(handler_method)
140
+ if handler_method.blank?
141
+ raise ArgumentError.new("Invalid input for handler_method: #{handler_method.inspect} is not a valid method name")
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
@@ -29,14 +29,14 @@ module Schleuder
29
29
  :keywords_admin_notify do |record, attrib, value|
30
30
  value.each do |word|
31
31
  if word !~ /\A[a-z_-]+\z/i
32
- record.errors.add(attrib, I18n.t("errors.invalid_characters"))
32
+ record.errors.add(attrib, I18n.t('errors.invalid_characters'))
33
33
  end
34
34
  end
35
35
  end
36
36
  validates_each :bounces_drop_on_headers do |record, attrib, value|
37
37
  value.each do |key, val|
38
38
  if key.to_s !~ /\A[a-z-]+\z/i || val.to_s !~ /\A[[:graph:]]+\z/i
39
- record.errors.add(attrib, I18n.t("errors.invalid_characters"))
39
+ record.errors.add(attrib, I18n.t('errors.invalid_characters'))
40
40
  end
41
41
  end
42
42
  end
@@ -67,6 +67,22 @@ module Schleuder
67
67
  with: /\A[[:graph:]\s]*\z/i,
68
68
  }
69
69
 
70
+ # Some users find it quite confusing when they click "reply-to" and the mail client
71
+ # doesn't reply to the sender of the mail but the whole mailing list. For those lists it can be
72
+ # considered to set this value to true. The recipients will then receive e-mails
73
+ # where the "reply-to" header will contain the reply-to address
74
+ # of the sender and thus reply to the sender when clicking "reply-to" in a client.
75
+ # If no "reply-to" is set, the "from"-header of the original sender will be used.
76
+ # The default is off.
77
+ validates :set_reply_to_to_sender, boolean: true
78
+
79
+ # Some users find it confusing when the "from" does not contain the original sender
80
+ # but the list address. For those lists it can be considered to set the munged header.
81
+ # This will result in a "from"-header like this: "originalsender@original.com via list@list.com"
82
+ # The default is off.
83
+ validates :munge_from, boolean: true
84
+
85
+
70
86
  default_scope { order(:email) }
71
87
 
72
88
  def self.configurable_attributes
@@ -92,10 +108,6 @@ module Schleuder
92
108
  subscriptions.where(admin: true)
93
109
  end
94
110
 
95
- def subscriptions_without_fingerprint
96
- subscriptions.without_fingerprint
97
- end
98
-
99
111
  def key(fingerprint=self.fingerprint)
100
112
  keys(fingerprint).first
101
113
  end
@@ -108,17 +120,6 @@ module Schleuder
108
120
  gpg.find_keys(identifier, secret_only)
109
121
  end
110
122
 
111
- # TODO: find better name for this method. It does more than the current
112
- # name suggests (filtering for capability).
113
- def distinct_key(identifier)
114
- keys = keys(identifier).select { |key| key.usable_for?(:encrypt) }
115
- if keys.size == 1
116
- return keys.first
117
- else
118
- return nil
119
- end
120
- end
121
-
122
123
  def import_key(importable)
123
124
  gpg.keyimport(importable)
124
125
  end
@@ -177,19 +178,19 @@ module Schleuder
177
178
  end
178
179
 
179
180
  text = ''
180
- expiring.each do |key,days|
181
- text << I18n.t('key_expires', {
181
+ expiring.each do |key, days|
182
+ text << I18n.t('key_expires',
182
183
  days: days,
183
- key_oneline: key.oneline
184
- })
184
+ key_summary: key.summary
185
+ )
185
186
  text << "\n"
186
187
  end
187
188
 
188
- unusable.each do |key,usability_issue|
189
- text << I18n.t('key_unusable', {
189
+ unusable.each do |key, usability_issue|
190
+ text << I18n.t('key_unusable',
190
191
  usability_issue: usability_issue,
191
- key_oneline: key.oneline
192
- })
192
+ key_summary: key.summary
193
+ )
193
194
  text << "\n"
194
195
  end
195
196
  text
@@ -203,19 +204,6 @@ module Schleuder
203
204
  gpg.fetch_key(input)
204
205
  end
205
206
 
206
- def pin_keys
207
- updated_emails = subscriptions_without_fingerprint.collect do |subscription|
208
- key = distinct_key(subscription.email)
209
- if key
210
- subscription.update(fingerprint: key.fingerprint)
211
- "#{subscription.email}: #{key.fingerprint}"
212
- else
213
- nil
214
- end
215
- end
216
- updated_emails.compact.join("\n")
217
- end
218
-
219
207
  def self.by_recipient(recipient)
220
208
  listname = recipient.gsub(/-(sendkey|request|owner|bounce)@/, '@')
221
209
  where(email: listname).first
@@ -352,7 +340,7 @@ module Schleuder
352
340
  end
353
341
 
354
342
  def send_to_subscriptions(mail, incoming_mail=nil)
355
- logger.debug "Sending to subscriptions."
343
+ logger.debug 'Sending to subscriptions.'
356
344
  mail.add_internal_footer!
357
345
  self.subscriptions.each do |subscription|
358
346
  begin
@@ -367,7 +355,7 @@ module Schleuder
367
355
  next
368
356
  end
369
357
 
370
- subscription.send_mail(mail)
358
+ subscription.send_mail(mail, incoming_mail)
371
359
 
372
360
  rescue => exc
373
361
  msg = I18n.t('errors.delivery_error',