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,13 @@
1
+ module GPGME
2
+ class SubKey
3
+ # Overwrite to specify the full fingerprint instead of the short key-ID.
4
+ def to_s
5
+ sprintf("%s %4d%s/%s %s\n",
6
+ secret? ? 'ssc' : 'sub',
7
+ length,
8
+ pubkey_algo_letter,
9
+ fingerprint,
10
+ timestamp.strftime('%Y-%m-%d'))
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,22 @@
1
+ module GPGME
2
+ class UserID
3
+ def name
4
+ sanitize_encoding(@name)
5
+ end
6
+ def comment
7
+ sanitize_encoding(@comment)
8
+ end
9
+ def uid
10
+ sanitize_encoding(@uid)
11
+ end
12
+
13
+ private
14
+ def sanitize_encoding(str)
15
+ if str.is_a?(String) && str.encoding != 'UTF-8'
16
+ str.encode(Encoding::UTF_8, invalid: :replace, undef: :replace, replace: '')
17
+ else
18
+ str
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,193 +1,384 @@
1
1
  module Schleuder
2
- # Represents a single list: name, config, members.
3
- class List
4
- # Name of this list. Must match the name of the subdirectory in
5
- # +SchleuderConfig::lists_dir+
6
- attr_reader :listname
7
-
8
- # Prepare some variables, set up the SchleuderLogger and set GNUPGHOME
9
- def initialize(listname,newlist=false)
10
- @listname = listname
11
- @config = ListConfig.new if newlist
12
- @log = ListLogger.new listname, listdir, config
13
-
14
- # setting GNUPGHOME to list's home, to make use of the keys there
15
- Schleuder.log.debug "setting ENV[GNUPGHOME] to #{listdir}"
16
- ENV["GNUPGHOME"] = listdir
17
- @members = nil
18
- end
19
-
20
- # Provides an array of Schleuder::Member's, read from +members.conf+
21
- def members
22
- unless @members
23
- Schleuder.log.debug("reading #{members_file}")
24
- @members = YAML::load_file(members_file).collect do |h|
25
- h.kind_of?(Schleuder::Member) ? h : Schleuder::Member.new(h)
2
+ class List < ActiveRecord::Base
3
+
4
+ has_many :subscriptions, dependent: :destroy
5
+ before_destroy :delete_listdirs
6
+
7
+ serialize :headers_to_meta, JSON
8
+ serialize :bounces_drop_on_headers, JSON
9
+ serialize :keywords_admin_only, JSON
10
+ serialize :keywords_admin_notify, JSON
11
+
12
+ validates :email, presence: true, uniqueness: true, email: true
13
+ validates :fingerprint, presence: true, fingerprint: true
14
+ validates :send_encrypted_only,
15
+ :receive_encrypted_only,
16
+ :receive_signed_only,
17
+ :receive_authenticated_only,
18
+ :receive_from_subscribed_emailaddresses_only,
19
+ :receive_admin_only,
20
+ :keep_msgid,
21
+ :bounces_drop_all,
22
+ :bounces_notify_admins,
23
+ :include_list_headers,
24
+ :include_openpgp_header,
25
+ :forward_all_incoming_to_admins, boolean: true
26
+ validates_each :headers_to_meta,
27
+ :keywords_admin_only,
28
+ :keywords_admin_notify do |record, attrib, value|
29
+ value.each do |word|
30
+ if word !~ /\A[a-z_-]+\z/i
31
+ record.errors.add(attrib, I18n.t("errors.invalid_characters"))
32
+ end
33
+ end
34
+ end
35
+ validates_each :bounces_drop_on_headers do |record, attrib, value|
36
+ value.each do |key, val|
37
+ if key.to_s !~ /\A[a-z-]+\z/i || val.to_s !~ /\A[[:graph:]]+\z/i
38
+ record.errors.add(attrib, I18n.t("errors.invalid_characters"))
39
+ end
40
+ end
26
41
  end
42
+ validates :subject_prefix,
43
+ :subject_prefix_in,
44
+ :subject_prefix_out,
45
+ no_line_breaks: true
46
+ validates :openpgp_header_preference,
47
+ presence: true,
48
+ inclusion: {
49
+ in: %w(sign encrypt signencrypt unprotected none),
50
+ }
51
+ validates :max_message_size_kb, :logfiles_to_keep, greater_than_zero: true
52
+ validates :log_level,
53
+ presence: true,
54
+ inclusion: {
55
+ in: %w(debug info warn error),
56
+ }
57
+ validates :language,
58
+ presence: true,
59
+ inclusion: {
60
+ # TODO: find out why we break translations and available_locales if we use I18n.available_locales here.
61
+ in: %w(de en),
62
+ }
63
+ validates :public_footer, :internal_footer,
64
+ allow_blank: true,
65
+ format: {
66
+ with: /\A[[:graph:]\s]*\z/i,
67
+ }
68
+
69
+ default_scope { order(:email) }
70
+
71
+ def self.configurable_attributes
72
+ @configurable_attributes ||= begin
73
+ all = self.validators.map(&:attributes).flatten.uniq.compact.sort
74
+ all - [:email, :fingerprint]
27
75
  end
28
- @members
29
76
  end
30
77
 
31
- def members_file
32
- @members_file ||= File.join(listdir, Schleuder.config.lists_memberfile)
78
+ def logfile
79
+ @logfile ||= File.join(Conf.listlogs_dir, self.email.split('@').reverse, 'list.log')
80
+ end
81
+
82
+ def logger
83
+ @logger ||= Listlogger.new(self)
33
84
  end
34
-
35
- # Saves an array of Schleuder::Member's into +members.conf++
36
- def members=(arr)
37
- Schleuder.log.debug 'writing members'
38
- Schleuder.log.info("writing #{members_file}")
39
- @members = arr.collect { |m| m.kind_of?(Hash) ? Member.new(m) : m }
40
- _write(YAML.dump(@members.collect { |m| m.to_hash }), members_file)
41
- @members
85
+
86
+ def to_s
87
+ email
42
88
  end
43
-
44
- # Finds a member by email address.
45
- def find_member_by_email(addresses)
46
- addresses = Array(addresses)
47
- members.detect { |m| addresses.include?(m.email) } || false
89
+
90
+ def admins
91
+ subscriptions.where(admin: true)
48
92
  end
49
93
 
50
- def find_admin_by_email(addresses)
51
- addresses = Array(addresses)
52
- if admin_email = self.config.admins.detect { |a| addresses.include?(a.email) }
53
- Member.new(:email => admin_email)
54
- else
55
- false
56
- end
94
+ def subscriptions_without_fingerprint
95
+ subscriptions.without_fingerprint
57
96
  end
58
97
 
59
- def find_member_by_key(key)
60
- Schleuder.log.debug "Looking for member for key #{key}"
61
- find_by_key(members, key)
98
+ def key(fingerprint=self.fingerprint)
99
+ keys(fingerprint).first
62
100
  end
63
101
 
64
- def find_admin_by_key(key)
65
- Schleuder.log.debug "Looking for admin for key #{key}"
66
- find_by_key(config.admins, key)
102
+ def secret_key
103
+ keys(self.fingerprint, true).first
67
104
  end
68
105
 
69
- def find_admin_by_address(address)
70
- config.admins.detect { |admin| admin.email == address }
106
+ def keys(identifier=nil, secret_only=nil)
107
+ gpg.find_keys(identifier, secret_only)
71
108
  end
72
109
 
73
- def find_member_by_address(address)
74
- members.detect { |member| member.email == address }
110
+ # TODO: find better name for this method. It does more than the current
111
+ # name suggests (filtering for capability).
112
+ def distinct_key(identifier)
113
+ keys = keys(identifier).select { |key| key.usable_for?(:encrypt) }
114
+ if keys.size == 1
115
+ return keys.first
116
+ else
117
+ return nil
118
+ end
75
119
  end
76
120
 
77
- # Provides the list config as Schleuder::ListConfig-object
78
- def config
79
- @config ||= _load_config
121
+ def import_key(importable)
122
+ gpg.keyimport(importable)
80
123
  end
81
124
 
82
- # Saves +data+ into the list-config-file (default: list.conf). +data+ must
83
- # be a Schleuder::ListConfig or valid input to +ListConfig.new+
84
- def config=(data)
85
- Schleuder.log.info("writing list-config for: #{listname}")
86
- if data.is_a?(ListConfig)
87
- @config = data
125
+ def import_key_and_find_fingerprint(key_material)
126
+ return nil if key_material.blank?
127
+
128
+ import_result = import_key(key_material)
129
+ gpg.interpret_import_result(import_result)
130
+ end
131
+
132
+ def delete_key(fingerprint)
133
+ if key = keys(fingerprint).first
134
+ key.delete!
135
+ true
88
136
  else
89
- @config = ListConfig.new(data)
137
+ false
138
+ end
139
+ end
140
+
141
+ def export_key(fingerprint=self.fingerprint)
142
+ key = keys(fingerprint).first
143
+ if key.blank?
144
+ return false
90
145
  end
91
- _write(YAML::dump(@config.to_hash), configfile)
92
- @config
146
+ key.armored
147
+ end
148
+
149
+ def check_keys
150
+ now = Time.now
151
+ checkdate = now + (60 * 60 * 24 * 14) # two weeks
152
+ unusable = []
153
+ expiring = []
154
+
155
+ keys.each do |key|
156
+ expiry = key.subkeys.first.expires
157
+ if expiry && expiry > now && expiry < checkdate
158
+ # key expires in the near future
159
+ expdays = ((expiry - now)/86400).to_i
160
+ expiring << [key, expdays]
161
+ end
162
+
163
+ if ! key.usable?
164
+ unusable << [key, key.usability_issue]
165
+ end
166
+ end
167
+
168
+ text = ''
169
+ expiring.each do |key,days|
170
+ text << I18n.t('key_expires', {
171
+ days: days,
172
+ key_oneline: key.oneline
173
+ })
174
+ text << "\n"
175
+ end
176
+
177
+ unusable.each do |key,usability_issue|
178
+ text << I18n.t('key_unusable', {
179
+ usability_issue: usability_issue,
180
+ key_oneline: key.oneline
181
+ })
182
+ text << "\n"
183
+ end
184
+ text
185
+ end
186
+
187
+ def refresh_keys
188
+ gpg.refresh_keys(self.keys)
189
+ end
190
+
191
+ def fetch_keys(input)
192
+ gpg.fetch_key(input)
93
193
  end
94
194
 
95
- # Returns path to the list configuration file
96
- def configfile
97
- # If `lists_configfile` ends with a '/', assume its pointing to a
98
- # directory where configuration files are named "$DOMAIN/$LISTNAME.conf".
99
- if Schleuder.config.lists_configfile.end_with?('/')
100
- local_part, domain = listname.split('@')
101
- if domain.nil?
102
- # pre 2.2 style
103
- File.join(Schleuder.config.lists_configfile, "#{local_part}.conf")
195
+ def pin_keys
196
+ updated_emails = subscriptions_without_fingerprint.collect do |subscription|
197
+ key = distinct_key(subscription.email)
198
+ if key
199
+ subscription.update(fingerprint: key.fingerprint)
200
+ "#{subscription.email}: #{key.fingerprint}"
104
201
  else
105
- File.join(Schleuder.config.lists_configfile, domain, "#{local_part}.conf")
202
+ nil
106
203
  end
107
- else
108
- File.join(@listdir, Schleuder.config.lists_configfile)
109
204
  end
205
+ updated_emails.compact.join("\n")
110
206
  end
111
207
 
112
- # Builds the bounce-address for the list
113
- def bounce_addr
114
- @bounce_addr ||= self.config.myaddr.gsub(/^(.*)@(.*)$/, '\1-bounce@\2')
208
+ def self.by_recipient(recipient)
209
+ listname = recipient.gsub(/-(sendkey|request|owner|bounce)@/, '@')
210
+ where(email: listname).first
115
211
  end
116
212
 
117
- # Builds the owner-address for the list
118
- def owner_addr
119
- @owner_addr ||= self.config.myaddr.gsub(/^(.*)@(.*)$/, '\1-owner@\2')
213
+ def sendkey_address
214
+ @sendkey_address ||= email.gsub('@', '-sendkey@')
120
215
  end
121
216
 
122
- # Builds the request-address for the list
123
- def request_addr
124
- @request_addr ||= self.config.myaddr.gsub(/^(.*)@(.*)$/, '\1-request@\2')
217
+ def request_address
218
+ @request_address ||= email.gsub('@', '-request@')
125
219
  end
126
220
 
127
- # builds the send-key-command-address for the list
128
- def sendkey_addr
129
- self.config.myaddr.gsub(/^(.*)@(.*)$/, '\1-sendkey@\2')
221
+ def owner_address
222
+ @owner_address ||= email.gsub('@', '-owner@')
130
223
  end
131
224
 
132
- def self.listdir(listname)
133
- name = listname.split('@')
134
- if name.size < 2
135
- Schleuder.log.warn 'Listname should be a full email-address, using only the local part is deprecated. Please fix this!'
225
+ def bounce_address
226
+ @bounce_address ||= email.gsub('@', '-bounce@')
227
+ end
228
+
229
+ def gpg
230
+ @gpg_ctx ||= begin
231
+ # TODO: figure out why set it again...
232
+ # Set GNUPGHOME when list is created.
233
+ set_gnupg_home
234
+ GPGME::Ctx.new armor: true
235
+ end
236
+ end
237
+
238
+ # TODO: place this somewhere sensible.
239
+ # Call cleanup when script finishes.
240
+ #Signal.trap(0, proc { @list.cleanup })
241
+ def cleanup
242
+ if @gpg_agent_pid
243
+ Process.kill('TERM', @gpg_agent_pid.to_i)
136
244
  end
137
- File.expand_path(File.join([Schleuder.config.lists_dir, name.reverse].flatten))
245
+ rescue => e
246
+ $stderr.puts "Failed to kill gpg-agent: #{e}"
247
+ end
248
+
249
+ def gpg_sign_options
250
+ {sign: true, sign_as: self.fingerprint}
251
+ end
252
+
253
+ def fingerprint=(arg)
254
+ # Strip whitespace from incoming arg.
255
+ if arg
256
+ write_attribute(:fingerprint, arg.gsub(/\s*/, '').chomp)
257
+ end
258
+ end
259
+
260
+ def self.listdir(listname)
261
+ File.join(
262
+ Conf.lists_dir,
263
+ listname.split('@').reverse
264
+ )
138
265
  end
139
266
 
140
267
  def listdir
141
- @listdir ||= List.listdir(@listname)
268
+ @listdir ||= self.class.listdir(self.email)
142
269
  end
143
270
 
144
- def listid
145
- @listid ||= config.myaddr.gsub(/@/, '.')
271
+ # A convenience-method to simplify other code.
272
+ def subscribe(email, fingerprint=nil, adminflag=nil, deliveryflag=nil, key_material=nil)
273
+ messages = nil
274
+ args = {
275
+ list_id: self.id,
276
+ email: email
277
+ }
278
+ if key_material.present?
279
+ fingerprint, messages = import_key_and_find_fingerprint(key_material)
280
+ end
281
+ args[:fingerprint] = fingerprint
282
+ # ActiveRecord does not treat nil as falsy for boolean columns, so we
283
+ # have to avoid that in order to not receive an invalid object. The
284
+ # database will use the column's default-value if no value is being
285
+ # given. (I'd rather not duplicate the defaults here.)
286
+ if ! adminflag.nil?
287
+ args[:admin] = adminflag
288
+ end
289
+ if ! deliveryflag.nil?
290
+ args[:delivery_enabled] = deliveryflag
291
+ end
292
+ subscription = Subscription.create(args)
293
+ [subscription, messages]
146
294
  end
147
295
 
148
- def key
149
- @key ||= lookup_list_key
296
+ def unsubscribe(email, delete_key=false)
297
+ sub = subscriptions.where(email: email).first
298
+ if sub.blank?
299
+ false
300
+ end
301
+
302
+ if ! sub.destroy
303
+ return sub
304
+ end
305
+
306
+ if delete_key
307
+ sub.delete_key
308
+ end
150
309
  end
151
310
 
152
- def key_fingerprint
153
- key.subkeys.first.fingerprint
311
+ def keywords_admin_notify
312
+ Array(read_attribute(:keywords_admin_notify))
154
313
  end
155
314
 
156
- def archive(mail)
157
- @list_archiver ||= Schleuder::Archiver.new
158
- @list_archiver.archive(mail)
315
+ def keywords_admin_only
316
+ Array(read_attribute(:keywords_admin_only))
159
317
  end
160
318
 
161
- private
319
+ def admin_only?(keyword)
320
+ keywords_admin_only.include?(keyword)
321
+ end
162
322
 
163
- # Loads the configuration
164
- def _load_config
165
- Schleuder.log.debug("reading list-config for: #{@listname}") unless Schleuder.log.nil?
166
- @config = ListConfig.new(configfile)
323
+ def from_admin?(mail)
324
+ return false if ! mail.was_validly_signed?
325
+ admins.find do |admin|
326
+ admin.fingerprint == mail.signing_key.fingerprint
327
+ end.presence || false
167
328
  end
168
329
 
169
- def find_by_key(ary, key)
170
- return false unless key.kind_of?(GPGME::Key)
171
- res = ary.detect { |elem| elem.kind_of?(Member) && elem.uses_key?(key) }
172
- Schleuder.log.debug "Found #{res} for #{key}" unless res.nil?
173
- res || false
330
+ def set_attribute(attrib, value)
331
+ self.send("#{attrib}=", value)
174
332
  end
175
333
 
176
- def _write(data,filename)
177
- File.open(filename, 'w') { |f| f << data }
334
+ def send_list_key_to_subscriptions
335
+ mail = Mail.new
336
+ mail.from = self.email
337
+ mail.subject = I18n.t('list_public_key_subject')
338
+ mail.body = I18n.t('list_public_key_attached')
339
+ mail.attach_list_key!(self)
340
+ send_to_subscriptions(mail)
341
+ true
178
342
  end
179
343
 
180
- def lookup_list_key
181
- key, msg = crypt.get_key(config.key_fingerprint||config.myaddr)
182
- unless key
183
- raise "Could not find a key for this List! Reason: #{msg}"
344
+ def send_to_subscriptions(mail)
345
+ logger.debug "Sending to subscriptions."
346
+ mail.add_internal_footer!
347
+ self.subscriptions.each do |subscription|
348
+ begin
349
+ subscription.send_mail(mail)
350
+ rescue => exc
351
+ msg = I18n.t('errors.delivery_error',
352
+ { email: subscription.email, error: exc.to_s })
353
+ logger.error msg
354
+ logger.error exc
355
+ end
184
356
  end
185
- key
186
357
  end
187
358
 
188
- def crypt
189
- @@crypt ||= Crypt.new(nil)
359
+ private
360
+
361
+ def set_gnupg_home
362
+ ENV['GNUPGHOME'] = listdir
190
363
  end
191
364
 
365
+ def delete_listdirs
366
+ if File.exists?(self.listdir)
367
+ FileUtils.rm_rf(self.listdir, secure: true)
368
+ Schleuder.logger.info "Deleted #{self.listdir}"
369
+ end
370
+ # If listlogs_dir is different from lists_dir, the logfile still exists
371
+ # and needs to be deleted, too.
372
+ logfile_dir = File.dirname(self.logfile)
373
+ if File.exists?(logfile_dir)
374
+ FileUtils.rm_rf(logfile_dir, secure: true)
375
+ Schleuder.logger.info "Deleted #{logfile_dir}"
376
+ end
377
+ true
378
+ rescue => exc
379
+ # Don't use list-logger here — if the list-dir isn't present we can't log to it!
380
+ Schleuder.logger.error "Error while deleting listdir: #{exc}"
381
+ return false
382
+ end
192
383
  end
193
384
  end