schleuder 3.2.2 → 3.5.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 +4 -4
- data/README.md +21 -11
- data/Rakefile +18 -10
- data/bin/schleuder +2 -1
- data/bin/schleuder-api-daemon +3 -2
- data/db/migrate/20180110203100_add_sig_enc_to_headers_to_meta_defaults.rb +30 -0
- data/db/migrate/20180723173900_add_deliver_selfsent_to_list.rb +11 -0
- data/db/migrate/20190906194820_add_autocrypt_header_to_list.rb +11 -0
- data/db/schema.rb +4 -2
- data/etc/list-defaults.yml +13 -3
- data/etc/schleuder.yml +11 -0
- data/lib/schleuder-api-daemon.rb +9 -354
- data/lib/schleuder-api-daemon/helpers/schleuder-api-daemon-helper.rb +143 -0
- data/lib/schleuder-api-daemon/routes/key.rb +40 -0
- data/lib/schleuder-api-daemon/routes/list.rb +69 -0
- data/lib/schleuder-api-daemon/routes/status.rb +5 -0
- data/lib/schleuder-api-daemon/routes/subscription.rb +99 -0
- data/lib/schleuder-api-daemon/routes/version.rb +5 -0
- data/lib/schleuder.rb +12 -3
- data/lib/schleuder/cli.rb +33 -3
- data/lib/schleuder/cli/subcommand_fix.rb +1 -1
- data/lib/schleuder/conf.rb +7 -1
- data/lib/schleuder/errors/active_model_error.rb +2 -5
- data/lib/schleuder/errors/decryption_failed.rb +2 -7
- data/lib/schleuder/errors/key_adduid_failed.rb +1 -5
- data/lib/schleuder/errors/key_generation_failed.rb +1 -8
- data/lib/schleuder/errors/keyword_admin_only.rb +1 -5
- data/lib/schleuder/errors/list_not_found.rb +1 -5
- data/lib/schleuder/errors/listdir_problem.rb +2 -7
- data/lib/schleuder/errors/loading_list_settings_failed.rb +2 -5
- data/lib/schleuder/errors/message_empty.rb +1 -5
- data/lib/schleuder/errors/message_not_from_admin.rb +2 -5
- data/lib/schleuder/errors/message_sender_not_subscribed.rb +2 -5
- data/lib/schleuder/errors/message_too_big.rb +2 -5
- data/lib/schleuder/errors/message_unauthenticated.rb +1 -4
- data/lib/schleuder/errors/message_unencrypted.rb +2 -5
- data/lib/schleuder/errors/message_unsigned.rb +2 -5
- data/lib/schleuder/errors/too_many_keys.rb +1 -8
- data/lib/schleuder/filters/{request_filter.rb → post_decryption/10_request.rb} +0 -0
- data/lib/schleuder/filters/{max_message_size.rb → post_decryption/20_max_message_size.rb} +0 -0
- data/lib/schleuder/filters/{forward_filter.rb → post_decryption/30_forward_to_owner.rb} +0 -0
- data/lib/schleuder/filters/post_decryption/40_receive_admin_only.rb +10 -0
- data/lib/schleuder/filters/post_decryption/50_receive_authenticated_only.rb +10 -0
- data/lib/schleuder/filters/post_decryption/60_receive_signed_only.rb +10 -0
- data/lib/schleuder/filters/post_decryption/70_receive_encrypted_only.rb +10 -0
- data/lib/schleuder/filters/post_decryption/80_receive_from_subscribed_emailaddresses_only.rb +10 -0
- data/lib/schleuder/filters/post_decryption/90_strip_html_from_alternative_if_keywords_present.rb +21 -0
- data/lib/schleuder/filters/{bounces_filter.rb → pre_decryption/10_forward_bounce_to_admins.rb} +0 -0
- data/lib/schleuder/filters/{forward_incoming.rb → pre_decryption/20_forward_all_incoming_to_admins.rb} +0 -0
- data/lib/schleuder/filters/{send_key_filter.rb → pre_decryption/30_send_key.rb} +0 -0
- data/lib/schleuder/filters/{hotmail_message_filter.rb → pre_decryption/40_fix_exchange_messages.rb} +5 -3
- data/lib/schleuder/filters/{strip_alternative_filter.rb → pre_decryption/50_strip_html_from_alternative.rb} +1 -1
- data/lib/schleuder/filters_runner.rb +41 -31
- data/lib/schleuder/gpgme/ctx.rb +24 -3
- data/lib/schleuder/gpgme/import_status.rb +13 -7
- data/lib/schleuder/gpgme/key.rb +8 -0
- data/lib/schleuder/list.rb +26 -4
- data/lib/schleuder/logger_notifications.rb +8 -1
- data/lib/schleuder/mail/encrypted_part.rb +14 -0
- data/lib/schleuder/mail/gpg.rb +15 -0
- data/lib/schleuder/mail/message.rb +97 -49
- data/lib/schleuder/plugins/attach_listkey.rb +6 -10
- data/lib/schleuder/plugins/key_management.rb +34 -26
- data/lib/schleuder/plugins/resend.rb +14 -11
- data/lib/schleuder/plugins/subscription_management.rb +70 -3
- data/lib/schleuder/runner.rb +49 -10
- data/lib/schleuder/subscription.rb +5 -9
- data/lib/schleuder/validators/fingerprint_validator.rb +1 -1
- data/lib/schleuder/version.rb +1 -1
- data/locales/de.yml +101 -9
- data/locales/en.yml +107 -11
- metadata +72 -34
- data/lib/schleuder/errors/file_not_found.rb +0 -14
- data/lib/schleuder/errors/invalid_listname.rb +0 -13
- data/lib/schleuder/errors/list_exists.rb +0 -13
- data/lib/schleuder/errors/unknown_list_option.rb +0 -14
- data/lib/schleuder/filters/auth_filter.rb +0 -39
@@ -0,0 +1,143 @@
|
|
1
|
+
module SchleuderApiDaemonHelper
|
2
|
+
def valid_credentials?
|
3
|
+
@auth ||= Rack::Auth::Basic::Request.new(request.env)
|
4
|
+
if @auth.provided? && @auth.basic? && @auth.credentials.present?
|
5
|
+
username, api_key = @auth.credentials
|
6
|
+
username == 'schleuder' && Conf.api_valid_api_keys.include?(api_key)
|
7
|
+
else
|
8
|
+
false
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def authenticate!
|
13
|
+
# Be careful to use path_info() — it can be changed by other filters!
|
14
|
+
return if request.path_info == '/status.json'
|
15
|
+
if ! valid_credentials?
|
16
|
+
headers['WWW-Authenticate'] = 'Basic realm="Schleuder API Daemon"'
|
17
|
+
halt 401, "Not authorized\n"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def list(id_or_email=nil)
|
22
|
+
if id_or_email.blank?
|
23
|
+
if params[:list_id].present?
|
24
|
+
id_or_email = params[:list_id]
|
25
|
+
else
|
26
|
+
client_error "Parameter list_id is required"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
if is_an_integer?(id_or_email)
|
30
|
+
list = List.where(id: id_or_email).first
|
31
|
+
else
|
32
|
+
# list_id is actually an email address
|
33
|
+
list = List.where(email: id_or_email).first
|
34
|
+
end
|
35
|
+
list || halt(404)
|
36
|
+
end
|
37
|
+
|
38
|
+
def subscription(id_or_email)
|
39
|
+
if is_an_integer?(id_or_email)
|
40
|
+
sub = Subscription.where(id: id_or_email.to_i).first
|
41
|
+
else
|
42
|
+
# Email
|
43
|
+
if params[:list_id].blank?
|
44
|
+
client_error "Parameter list_id is required when using email as identifier for subscriptions."
|
45
|
+
else
|
46
|
+
sub = list.subscriptions.where(email: id_or_email).first
|
47
|
+
end
|
48
|
+
end
|
49
|
+
sub || halt(404)
|
50
|
+
end
|
51
|
+
|
52
|
+
def requested_list_id
|
53
|
+
# ActiveResource doesn't want to use query-params with create(), so here
|
54
|
+
# list_id might be included in the request-body.
|
55
|
+
params['list_id'] || parsed_body['list_id'] || client_error('Need list_id')
|
56
|
+
end
|
57
|
+
|
58
|
+
def parsed_body
|
59
|
+
@parsed_body ||= begin
|
60
|
+
b = JSON.parse(request.body.read)
|
61
|
+
logger.debug "parsed body: #{b.inspect}"
|
62
|
+
b
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def server_error(msg)
|
67
|
+
logger.warn msg
|
68
|
+
halt(500, json(error: msg))
|
69
|
+
end
|
70
|
+
|
71
|
+
# TODO: unify error messages. This method currently sends an old error format. See <https://github.com/rails/activeresource/blob/d6a5186/lib/active_resource/base.rb#L227>.
|
72
|
+
def client_error(obj_or_msg, http_code=400)
|
73
|
+
text = case obj_or_msg
|
74
|
+
when String, Symbol
|
75
|
+
obj_or_msg.to_s
|
76
|
+
when ActiveRecord::Base
|
77
|
+
obj_or_msg.errors.full_messages
|
78
|
+
else
|
79
|
+
obj_or_msg
|
80
|
+
end
|
81
|
+
logger.error "Sending error to client: #{text.inspect}"
|
82
|
+
halt(http_code, json(errors: text))
|
83
|
+
end
|
84
|
+
|
85
|
+
# poor persons type casting
|
86
|
+
def cast_param_values
|
87
|
+
params.each do |key, value|
|
88
|
+
params[key] =
|
89
|
+
case value
|
90
|
+
when 'true' then true
|
91
|
+
when 'false' then false
|
92
|
+
when '0' then 0
|
93
|
+
when is_an_integer?(value) then value.to_i
|
94
|
+
else value
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def key_to_hash(key, include_keydata=false)
|
100
|
+
hash = {
|
101
|
+
fingerprint: key.fingerprint,
|
102
|
+
email: key.email,
|
103
|
+
expiry: key.expires,
|
104
|
+
generated_at: key.generated_at,
|
105
|
+
primary_uid: key.primary_uid.uid,
|
106
|
+
oneline: key.oneline,
|
107
|
+
trust_issues: key.usability_issue
|
108
|
+
}
|
109
|
+
if include_keydata
|
110
|
+
hash[:description] = key.to_s
|
111
|
+
hash[:ascii] = key.armored
|
112
|
+
end
|
113
|
+
hash
|
114
|
+
end
|
115
|
+
|
116
|
+
def set_x_messages(messages)
|
117
|
+
if messages.present?
|
118
|
+
headers 'X-Messages' => Array(messages).join(' // ').gsub(/\n/, ' // ')
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def find_key_material
|
123
|
+
key_material = parsed_body['key_material'].presence
|
124
|
+
# By convention key_material is either ASCII or base64-encoded.
|
125
|
+
if key_material && ! key_material.match('BEGIN PGP')
|
126
|
+
key_material = Base64.decode64(key_material)
|
127
|
+
end
|
128
|
+
key_material
|
129
|
+
end
|
130
|
+
|
131
|
+
def find_attributes_from_body(attribs)
|
132
|
+
Array(attribs).inject({}) do |memo, attrib|
|
133
|
+
if parsed_body.has_key?(attrib)
|
134
|
+
memo[attrib] = parsed_body[attrib]
|
135
|
+
end
|
136
|
+
memo
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def is_an_integer?(input)
|
141
|
+
input.to_s.match(/^[0-9]+$/).present?
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class SchleuderApiDaemon < Sinatra::Base
|
2
|
+
register Sinatra::Namespace
|
3
|
+
|
4
|
+
namespace '/keys' do
|
5
|
+
get '.json' do
|
6
|
+
keys = list.keys.sort_by(&:email).map do |key|
|
7
|
+
key_to_hash(key)
|
8
|
+
end
|
9
|
+
json keys
|
10
|
+
end
|
11
|
+
|
12
|
+
post '.json' do
|
13
|
+
input = parsed_body['keymaterial']
|
14
|
+
if ! input.match('BEGIN PGP')
|
15
|
+
input = Base64.decode64(input)
|
16
|
+
end
|
17
|
+
json list(requested_list_id).import_key(input)
|
18
|
+
end
|
19
|
+
|
20
|
+
get '/check_keys.json' do
|
21
|
+
json result: list.check_keys
|
22
|
+
end
|
23
|
+
|
24
|
+
get '/:fingerprint.json' do |fingerprint|
|
25
|
+
if key = list.key(fingerprint)
|
26
|
+
json key_to_hash(key, true)
|
27
|
+
else
|
28
|
+
404
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
delete '/:fingerprint.json' do |fingerprint|
|
33
|
+
if list.delete_key(fingerprint)
|
34
|
+
200
|
35
|
+
else
|
36
|
+
404
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
class SchleuderApiDaemon < Sinatra::Base
|
2
|
+
register Sinatra::Namespace
|
3
|
+
|
4
|
+
namespace '/lists' do
|
5
|
+
get '.json' do
|
6
|
+
json List.all, include: :subscriptions
|
7
|
+
end
|
8
|
+
|
9
|
+
post '.json' do
|
10
|
+
listname = parsed_body['email']
|
11
|
+
fingerprint = parsed_body['fingerprint']
|
12
|
+
adminaddress = parsed_body['adminaddress']
|
13
|
+
adminfingerprint = parsed_body['adminfingerprint']
|
14
|
+
adminkey = parsed_body['adminkey']
|
15
|
+
list, messages = ListBuilder.new({email: listname, fingerprint: fingerprint}, adminaddress, adminfingerprint, adminkey).run
|
16
|
+
if list.nil?
|
17
|
+
client_error(messages, 422)
|
18
|
+
elsif ! list.valid?
|
19
|
+
client_error(list, 422)
|
20
|
+
else
|
21
|
+
set_x_messages(messages)
|
22
|
+
body json(list)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
get '/configurable_attributes.json' do
|
27
|
+
json(List.configurable_attributes) + "\n"
|
28
|
+
end
|
29
|
+
|
30
|
+
post '/send_list_key_to_subscriptions.json' do
|
31
|
+
json(result: list.send_list_key_to_subscriptions)
|
32
|
+
end
|
33
|
+
|
34
|
+
get '/new.json' do
|
35
|
+
json List.new
|
36
|
+
end
|
37
|
+
|
38
|
+
get '/:id.json' do |id|
|
39
|
+
json list(id)
|
40
|
+
end
|
41
|
+
|
42
|
+
put '/:id.json' do |id|
|
43
|
+
list = list(id)
|
44
|
+
if list.update(parsed_body)
|
45
|
+
204
|
46
|
+
else
|
47
|
+
client_error(list)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
patch '/:id.json' do |id|
|
52
|
+
list = list(id)
|
53
|
+
if list.update(parsed_body)
|
54
|
+
204
|
55
|
+
else
|
56
|
+
client_error(list)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
delete '/:id.json' do |id|
|
61
|
+
list = list(id)
|
62
|
+
if list.destroy
|
63
|
+
200
|
64
|
+
else
|
65
|
+
client_error(list)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
class SchleuderApiDaemon < Sinatra::Base
|
2
|
+
register Sinatra::Namespace
|
3
|
+
|
4
|
+
namespace '/subscriptions' do
|
5
|
+
get '.json' do
|
6
|
+
filterkeys = Subscription.configurable_attributes + [:list_id, :email]
|
7
|
+
filter = params.select do |param|
|
8
|
+
filterkeys.include?(param.to_sym)
|
9
|
+
end
|
10
|
+
|
11
|
+
logger.debug "Subscription filter: #{filter.inspect}"
|
12
|
+
if filter['list_id'] && ! is_an_integer?(filter['list_id'])
|
13
|
+
# Value is an email-address
|
14
|
+
if list = List.where(email: filter['list_id']).first
|
15
|
+
filter['list_id'] = list.id
|
16
|
+
else
|
17
|
+
status 404
|
18
|
+
return json(errors: 'No such list')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
json Subscription.where(filter)
|
23
|
+
end
|
24
|
+
|
25
|
+
post '.json' do
|
26
|
+
begin
|
27
|
+
list = list(requested_list_id)
|
28
|
+
# We don't have to care about nil-values, subscribe() does that for us.
|
29
|
+
sub, msgs = list.subscribe(
|
30
|
+
parsed_body['email'],
|
31
|
+
parsed_body['fingerprint'],
|
32
|
+
parsed_body['admin'],
|
33
|
+
parsed_body['delivery_enabled'],
|
34
|
+
find_key_material
|
35
|
+
)
|
36
|
+
set_x_messages(msgs)
|
37
|
+
logger.debug "subcription: #{sub.inspect}"
|
38
|
+
if sub.valid?
|
39
|
+
logger.debug "Subscribed: #{sub.inspect}"
|
40
|
+
# TODO: why redirect instead of respond with result?
|
41
|
+
redirect to("/subscriptions/#{sub.id}.json"), 201
|
42
|
+
else
|
43
|
+
client_error(sub, 422)
|
44
|
+
end
|
45
|
+
rescue ActiveRecord::RecordNotUnique
|
46
|
+
logger.error "Already subscribed"
|
47
|
+
status 422
|
48
|
+
json errors: {email: ['is already subscribed']}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
get '/configurable_attributes.json' do
|
53
|
+
json(Subscription.configurable_attributes) + "\n"
|
54
|
+
end
|
55
|
+
|
56
|
+
get '/new.json' do
|
57
|
+
json Subscription.new
|
58
|
+
end
|
59
|
+
|
60
|
+
get '/:id.json' do |id|
|
61
|
+
json subscription(id)
|
62
|
+
end
|
63
|
+
|
64
|
+
put '/:id.json' do |id|
|
65
|
+
sub = subscription(id)
|
66
|
+
list = sub.list
|
67
|
+
args = find_attributes_from_body(%w[email fingerprint admin delivery_enabled])
|
68
|
+
fingerprint, messages = list.import_key_and_find_fingerprint(find_key_material)
|
69
|
+
set_x_messages(messages)
|
70
|
+
# For an already existing subscription, only update fingerprint if a
|
71
|
+
# new one has been selected from the upload.
|
72
|
+
if fingerprint.present?
|
73
|
+
args["fingerprint"] = fingerprint
|
74
|
+
end
|
75
|
+
if sub.update(args)
|
76
|
+
200
|
77
|
+
else
|
78
|
+
client_error(sub, 422)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
patch '/:id.json' do |id|
|
83
|
+
sub = subscription(id)
|
84
|
+
if sub.update(parsed_body)
|
85
|
+
200
|
86
|
+
else
|
87
|
+
client_error(sub)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
delete '/:id.json' do |id|
|
92
|
+
if sub = subscription(id).destroy
|
93
|
+
200
|
94
|
+
else
|
95
|
+
client_error(sub)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
data/lib/schleuder.rb
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
# default to UTF-8 encoding as early as possible for external
|
2
|
+
# data.
|
3
|
+
#
|
4
|
+
# this should ensure we are able to parse most incoming
|
5
|
+
# plain text mails in different charsets.
|
6
|
+
Encoding.default_external = Encoding::UTF_8
|
7
|
+
|
1
8
|
# Stdlib
|
2
9
|
require 'fileutils'
|
3
10
|
require 'singleton'
|
@@ -22,6 +29,8 @@ $:.unshift libdir
|
|
22
29
|
# Monkeypatches
|
23
30
|
require 'schleuder/mail/parts_list.rb'
|
24
31
|
require 'schleuder/mail/message.rb'
|
32
|
+
require 'schleuder/mail/gpg.rb'
|
33
|
+
require 'schleuder/mail/encrypted_part.rb'
|
25
34
|
require 'schleuder/gpgme/import_status.rb'
|
26
35
|
require 'schleuder/gpgme/key.rb'
|
27
36
|
require 'schleuder/gpgme/sub_key.rb'
|
@@ -46,9 +55,6 @@ Dir["#{libdir}/schleuder/plugins/*.rb"].each do |file|
|
|
46
55
|
require file
|
47
56
|
end
|
48
57
|
require 'schleuder/filters_runner'
|
49
|
-
Dir["#{libdir}/schleuder/filters/*.rb"].each do |file|
|
50
|
-
require file
|
51
|
-
end
|
52
58
|
Dir["#{libdir}/schleuder/validators/*.rb"].each do |file|
|
53
59
|
require file
|
54
60
|
end
|
@@ -62,6 +68,9 @@ ENV["SCHLEUDER_CONFIG"] ||= '/etc/schleuder/schleuder.yml'
|
|
62
68
|
ENV["SCHLEUDER_LIST_DEFAULTS"] ||= '/etc/schleuder/list-defaults.yml'
|
63
69
|
ENV["SCHLEUDER_ENV"] ||= 'production'
|
64
70
|
ENV["SCHLEUDER_ROOT"] = rootdir.to_s
|
71
|
+
# Ensure that gnupg never-ever tries to ask for a passphrase.
|
72
|
+
ENV["GPG_TTY"] = "/nonexistant-#{rand}"
|
73
|
+
ENV["DISPLAY"] = nil
|
65
74
|
|
66
75
|
GPGME::Ctx.set_gpg_path_from_env
|
67
76
|
GPGME::Ctx.check_gpg_version
|
data/lib/schleuder/cli.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'thor'
|
2
2
|
require 'yaml'
|
3
3
|
require 'gpgme'
|
4
|
+
require 'charlock_holmes'
|
4
5
|
|
5
6
|
require_relative '../schleuder'
|
6
7
|
require 'schleuder/cli/subcommand_fix'
|
@@ -62,11 +63,14 @@ module Schleuder
|
|
62
63
|
list.logger.notify_admin(msg, nil, I18n.t('check_keys'))
|
63
64
|
end
|
64
65
|
end
|
66
|
+
permission_notice
|
65
67
|
end
|
66
68
|
|
67
69
|
desc 'refresh_keys [list1@example.com]', "Refresh all keys of all list from the keyservers sequentially (one by one or on the passed list). (This is supposed to be run from cron weekly.)"
|
68
70
|
def refresh_keys(list=nil)
|
71
|
+
GPGME::Ctx.send_notice_if_gpg_does_not_know_import_filter
|
69
72
|
work_on_lists(:refresh_keys,list)
|
73
|
+
permission_notice
|
70
74
|
end
|
71
75
|
|
72
76
|
desc 'pin_keys [list1@example.com]', "Find keys for subscriptions without a pinned key and try to pin a certain key (one by one or based on the passed list)."
|
@@ -122,6 +126,7 @@ module Schleuder
|
|
122
126
|
end
|
123
127
|
|
124
128
|
say "Schleuder has been set up. You can now create a new list using `schleuder-cli`.\nWe hope you enjoy!"
|
129
|
+
permission_notice
|
125
130
|
rescue => exc
|
126
131
|
fatal exc.message
|
127
132
|
end
|
@@ -257,6 +262,7 @@ Please notify the users and admins of this list of these changes.
|
|
257
262
|
if messages.present?
|
258
263
|
say messages.gsub(' // ', "\n")
|
259
264
|
end
|
265
|
+
permission_notice
|
260
266
|
rescue => exc
|
261
267
|
fatal "#{exc}\n#{exc.backtrace.first}"
|
262
268
|
end
|
@@ -315,11 +321,15 @@ Please notify the users and admins of this list of these changes.
|
|
315
321
|
private
|
316
322
|
|
317
323
|
def work_on_lists(subj, list=nil)
|
318
|
-
|
319
|
-
List.all
|
324
|
+
if list.nil?
|
325
|
+
selected_lists = List.all
|
320
326
|
else
|
321
|
-
List.where(email: list)
|
327
|
+
selected_lists = List.where(email: list)
|
328
|
+
if selected_lists.blank?
|
329
|
+
error("No list with this address exists: #{list.inspect}")
|
330
|
+
end
|
322
331
|
end
|
332
|
+
|
323
333
|
selected_lists.each do |list|
|
324
334
|
I18n.locale = list.language
|
325
335
|
output = list.send(subj)
|
@@ -330,5 +340,25 @@ Please notify the users and admins of this list of these changes.
|
|
330
340
|
end
|
331
341
|
end
|
332
342
|
|
343
|
+
# Make this class exit with code 1 in case of an error. See <https://github.com/erikhuda/thor/issues/244>.
|
344
|
+
def self.exit_on_failure?
|
345
|
+
true
|
346
|
+
end
|
347
|
+
|
348
|
+
def permission_notice
|
349
|
+
if Process.euid == 0
|
350
|
+
dirs = [Conf.lists_dir, Conf.listlogs_dir]
|
351
|
+
if Conf.database['adapter'] == 'sqlite3'
|
352
|
+
dirs << Conf.database['database']
|
353
|
+
end
|
354
|
+
dirs_sentence = dirs.uniq.map { |dir| enquote(dir) }.to_sentence
|
355
|
+
say "Warning: this process was run as root -- please make sure that all files in #{dirs_sentence} have correct file system permissions for the user that is running both, schleuder from the MTA and `schleuder-api-daemon`."
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
def enquote(string)
|
360
|
+
"\`#{string}\`"
|
361
|
+
end
|
362
|
+
|
333
363
|
end
|
334
364
|
end
|