schleuder 2.2.4 → 3.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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,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
|
data/lib/schleuder/list.rb
CHANGED
|
@@ -1,193 +1,384 @@
|
|
|
1
1
|
module Schleuder
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
|
32
|
-
@
|
|
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
|
-
|
|
36
|
-
|
|
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
|
-
|
|
45
|
-
|
|
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
|
|
51
|
-
|
|
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
|
|
60
|
-
|
|
61
|
-
find_by_key(members, key)
|
|
98
|
+
def key(fingerprint=self.fingerprint)
|
|
99
|
+
keys(fingerprint).first
|
|
62
100
|
end
|
|
63
101
|
|
|
64
|
-
def
|
|
65
|
-
|
|
66
|
-
find_by_key(config.admins, key)
|
|
102
|
+
def secret_key
|
|
103
|
+
keys(self.fingerprint, true).first
|
|
67
104
|
end
|
|
68
105
|
|
|
69
|
-
def
|
|
70
|
-
|
|
106
|
+
def keys(identifier=nil, secret_only=nil)
|
|
107
|
+
gpg.find_keys(identifier, secret_only)
|
|
71
108
|
end
|
|
72
109
|
|
|
73
|
-
|
|
74
|
-
|
|
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
|
-
|
|
78
|
-
|
|
79
|
-
@config ||= _load_config
|
|
121
|
+
def import_key(importable)
|
|
122
|
+
gpg.keyimport(importable)
|
|
80
123
|
end
|
|
81
124
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
-
|
|
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
|
-
|
|
92
|
-
|
|
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
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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
|
-
|
|
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
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
118
|
-
|
|
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
|
-
|
|
123
|
-
|
|
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
|
-
|
|
128
|
-
|
|
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
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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
|
-
|
|
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 ||=
|
|
268
|
+
@listdir ||= self.class.listdir(self.email)
|
|
142
269
|
end
|
|
143
270
|
|
|
144
|
-
|
|
145
|
-
|
|
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
|
|
149
|
-
|
|
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
|
|
153
|
-
|
|
311
|
+
def keywords_admin_notify
|
|
312
|
+
Array(read_attribute(:keywords_admin_notify))
|
|
154
313
|
end
|
|
155
314
|
|
|
156
|
-
def
|
|
157
|
-
|
|
158
|
-
@list_archiver.archive(mail)
|
|
315
|
+
def keywords_admin_only
|
|
316
|
+
Array(read_attribute(:keywords_admin_only))
|
|
159
317
|
end
|
|
160
318
|
|
|
161
|
-
|
|
319
|
+
def admin_only?(keyword)
|
|
320
|
+
keywords_admin_only.include?(keyword)
|
|
321
|
+
end
|
|
162
322
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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
|
|
170
|
-
|
|
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
|
|
177
|
-
|
|
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
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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
|
-
|
|
189
|
-
|
|
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
|