schleuder 2.2.4 → 3.2.2
Sign up to get free protection for your applications and to get access to all the features.
- 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,28 @@
|
|
1
|
+
# Use this as a table for postfix to select addresses that schleuder
|
2
|
+
# thinks belong to it. This is useful when
|
3
|
+
# smtpd_reject_unlisted_recipient = yes (which is the default for
|
4
|
+
# modern Postfix)
|
5
|
+
|
6
|
+
# For example, you might dedicate Postfix's "virtual" domains to
|
7
|
+
# schleuder with the following set of configs in main.cf:
|
8
|
+
#
|
9
|
+
# virtual_domains = lists.example.org
|
10
|
+
# virtual_transport = schleuder
|
11
|
+
# virtual_alias_maps = hash:/etc/postfix/virtual_aliases
|
12
|
+
# virtual_mailbox_maps = sqlite:/etc/postfix/schleuder_sqlite.cf
|
13
|
+
# schleuder_destination_recipient_limit = 1
|
14
|
+
|
15
|
+
# it is not recommended to use this table for more powerful
|
16
|
+
# configuration options (e.g. transport_maps) because it could give
|
17
|
+
# the schleuder user (which can write the given sqlite database) the
|
18
|
+
# power to change settings for for other mail handled by this Postfix
|
19
|
+
# instance.
|
20
|
+
|
21
|
+
dbpath = /var/lib/schleuder/db.sqlite
|
22
|
+
|
23
|
+
query = select 'present' from lists
|
24
|
+
where email = '%s'
|
25
|
+
or email = replace('%s', '-bounce@', '@')
|
26
|
+
or email = replace('%s', '-owner@', '@')
|
27
|
+
or email = replace('%s', '-request@', '@')
|
28
|
+
or email = replace('%s', '-sendkey@', '@')
|
data/etc/schleuder.yml
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
# Where are the list-directories stored (contain log-files and GnuPG-keyrings).
|
2
|
+
lists_dir: /var/lib/schleuder/lists
|
3
|
+
|
4
|
+
# Where to write list-logs. The actual log-file will be <lists_logs_base_dir>/<hostname>/<listname>/list.log.
|
5
|
+
listlogs_dir: /var/lib/schleuder/lists
|
6
|
+
|
7
|
+
# Schleuder reads plugins also from this directory.
|
8
|
+
plugins_dir: /etc/schleuder/plugins
|
9
|
+
|
10
|
+
# How verbose should Schleuder log to syslog? (list-specific messages are written to the list's log-file).
|
11
|
+
log_level: warn
|
12
|
+
|
13
|
+
# Which keyserver to refresh keys from (used by `schleuder refresh_keys`, meant
|
14
|
+
# to be run from cron weekly).
|
15
|
+
# If you have gnupg 2.1, we strongly suggest to use a hkps-keyserver:
|
16
|
+
#keyserver: hkps://hkps.pool.sks-keyservers.net
|
17
|
+
# If you have gnupg 2.1 and TOR running locally, use a onion-keyserver:
|
18
|
+
#keyserver: hkp://jirk5u4osbsr34t5.onion
|
19
|
+
# If you have an OS-wide defined keyserver, specify a blank value to have that
|
20
|
+
# one used:
|
21
|
+
#keyserver:
|
22
|
+
# The default works for all supported versions of gnupg:
|
23
|
+
keyserver: pool.sks-keyservers.net
|
24
|
+
|
25
|
+
# Who is maintaining the overall schleuder installation and should be
|
26
|
+
# notified about severe problems with lists.
|
27
|
+
# This address should be a postmaster-like account, especially it should
|
28
|
+
# not be another schleuder list.
|
29
|
+
# Is also used as an envelope sender of admin notifications.
|
30
|
+
superadmin: root@localhost
|
31
|
+
|
32
|
+
# For these options see documentation for ActionMailer::smtp_settings, e.g. <http://api.rubyonrails.org/classes/ActionMailer/Base.html>.
|
33
|
+
smtp_settings:
|
34
|
+
address: localhost
|
35
|
+
port: 25
|
36
|
+
#domain:
|
37
|
+
#enable_starttls_auto:
|
38
|
+
#openssl_verify_mode:
|
39
|
+
#authentication:
|
40
|
+
#user_name:
|
41
|
+
#password:
|
42
|
+
|
43
|
+
# The database to use. Unless you want to run the tests you only need the `production`-section.
|
44
|
+
database:
|
45
|
+
production:
|
46
|
+
adapter: 'sqlite3'
|
47
|
+
database: /var/lib/schleuder/db.sqlite
|
48
|
+
timeout: 5000
|
49
|
+
|
50
|
+
api:
|
51
|
+
host: localhost
|
52
|
+
port: 4443
|
53
|
+
# Certificate and key to use. You can create new ones with `schleuder cert generate`.
|
54
|
+
tls_cert_file: /etc/schleuder/schleuder-certificate.pem
|
55
|
+
tls_key_file: /etc/schleuder/schleuder-private-key.pem
|
56
|
+
# List of api_keys to allow access to the API.
|
57
|
+
# Example:
|
58
|
+
# valid_api_keys:
|
59
|
+
# - abcdef...
|
60
|
+
# - zyxwvu...
|
61
|
+
valid_api_keys:
|
@@ -0,0 +1,420 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Make sinatra use production as default-environment
|
4
|
+
ENV['RACK_ENV'] ||= 'production'
|
5
|
+
|
6
|
+
require 'sinatra/base'
|
7
|
+
require 'sinatra/json'
|
8
|
+
require 'sinatra/namespace'
|
9
|
+
require 'thin'
|
10
|
+
require_relative '../lib/schleuder.rb'
|
11
|
+
|
12
|
+
|
13
|
+
%w[tls_cert_file tls_key_file].each do |config_key|
|
14
|
+
path = Conf.api[config_key]
|
15
|
+
if ! File.readable?(path)
|
16
|
+
$stderr.puts "Error: '#{path}' is not a readable file (from #{config_key} in config)."
|
17
|
+
exit 1
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class SchleuderApiDaemon < Sinatra::Base
|
22
|
+
register Sinatra::Namespace
|
23
|
+
|
24
|
+
configure do
|
25
|
+
set :server, :thin
|
26
|
+
set :port, Schleuder::Conf.api['port'] || 4443
|
27
|
+
set :bind, Schleuder::Conf.api['host'] || 'localhost'
|
28
|
+
if settings.development?
|
29
|
+
set :logging, Logger::DEBUG
|
30
|
+
else
|
31
|
+
set :logging, Logger::WARN
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
before do
|
36
|
+
authenticate!
|
37
|
+
cast_param_values
|
38
|
+
end
|
39
|
+
|
40
|
+
after do
|
41
|
+
# Return connection to pool after each request.
|
42
|
+
ActiveRecord::Base.connection.close
|
43
|
+
end
|
44
|
+
|
45
|
+
error do
|
46
|
+
exc = env['sinatra.error']
|
47
|
+
logger.error "Error: #{env['sinatra.error'].message}"
|
48
|
+
case exc
|
49
|
+
when Errno::EACCES
|
50
|
+
server_error(exc.message)
|
51
|
+
else
|
52
|
+
client_error(exc.to_s)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
error 404 do
|
57
|
+
'Not found'
|
58
|
+
end
|
59
|
+
|
60
|
+
get '/status.json' do
|
61
|
+
json status: :ok
|
62
|
+
end
|
63
|
+
|
64
|
+
get '/version.json' do
|
65
|
+
json version: Schleuder::VERSION
|
66
|
+
end
|
67
|
+
|
68
|
+
helpers do
|
69
|
+
def valid_credentials?
|
70
|
+
@auth ||= Rack::Auth::Basic::Request.new(request.env)
|
71
|
+
if @auth.provided? && @auth.basic? && @auth.credentials.present?
|
72
|
+
username, api_key = @auth.credentials
|
73
|
+
username == 'schleuder' && Conf.api_valid_api_keys.include?(api_key)
|
74
|
+
else
|
75
|
+
false
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def authenticate!
|
80
|
+
# Be careful to use path_info() — it can be changed by other filters!
|
81
|
+
return if request.path_info == '/status.json'
|
82
|
+
if ! valid_credentials?
|
83
|
+
headers['WWW-Authenticate'] = 'Basic realm="Schleuder API Daemon"'
|
84
|
+
halt 401, "Not authorized\n"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def list(id_or_email=nil)
|
89
|
+
if id_or_email.blank?
|
90
|
+
if params[:list_id].present?
|
91
|
+
id_or_email = params[:list_id]
|
92
|
+
else
|
93
|
+
client_error "Parameter list_id is required"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
if is_an_integer?(id_or_email)
|
97
|
+
list = List.where(id: id_or_email).first
|
98
|
+
else
|
99
|
+
# list_id is actually an email address
|
100
|
+
list = List.where(email: id_or_email).first
|
101
|
+
end
|
102
|
+
list || halt(404)
|
103
|
+
end
|
104
|
+
|
105
|
+
def subscription(id_or_email)
|
106
|
+
if is_an_integer?(id_or_email)
|
107
|
+
sub = Subscription.where(id: id_or_email.to_i).first
|
108
|
+
else
|
109
|
+
# Email
|
110
|
+
if params[:list_id].blank?
|
111
|
+
client_error "Parameter list_id is required when using email as identifier for subscriptions."
|
112
|
+
else
|
113
|
+
sub = list.subscriptions.where(email: id_or_email).first
|
114
|
+
end
|
115
|
+
end
|
116
|
+
sub || halt(404)
|
117
|
+
end
|
118
|
+
|
119
|
+
def requested_list_id
|
120
|
+
# ActiveResource doesn't want to use query-params with create(), so here
|
121
|
+
# list_id might be included in the request-body.
|
122
|
+
params['list_id'] || parsed_body['list_id'] || client_error('Need list_id')
|
123
|
+
end
|
124
|
+
|
125
|
+
def parsed_body
|
126
|
+
@parsed_body ||= begin
|
127
|
+
b = JSON.parse(request.body.read)
|
128
|
+
logger.debug "parsed body: #{b.inspect}"
|
129
|
+
b
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def server_error(msg)
|
134
|
+
logger.warn msg
|
135
|
+
halt(500, json(error: msg))
|
136
|
+
end
|
137
|
+
|
138
|
+
# 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>.
|
139
|
+
def client_error(obj_or_msg, http_code=400)
|
140
|
+
text = case obj_or_msg
|
141
|
+
when String, Symbol
|
142
|
+
obj_or_msg.to_s
|
143
|
+
when ActiveRecord::Base
|
144
|
+
obj_or_msg.errors.full_messages
|
145
|
+
else
|
146
|
+
obj_or_msg
|
147
|
+
end
|
148
|
+
logger.error "Sending error to client: #{text.inspect}"
|
149
|
+
halt(http_code, json(errors: text))
|
150
|
+
end
|
151
|
+
|
152
|
+
# poor persons type casting
|
153
|
+
def cast_param_values
|
154
|
+
params.each do |key, value|
|
155
|
+
params[key] =
|
156
|
+
case value
|
157
|
+
when 'true' then true
|
158
|
+
when 'false' then false
|
159
|
+
when '0' then 0
|
160
|
+
when is_an_integer?(value) then value.to_i
|
161
|
+
else value
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def key_to_hash(key, include_keydata=false)
|
167
|
+
hash = {
|
168
|
+
fingerprint: key.fingerprint,
|
169
|
+
email: key.email,
|
170
|
+
expiry: key.expires,
|
171
|
+
generated_at: key.generated_at,
|
172
|
+
primary_uid: key.primary_uid.uid,
|
173
|
+
oneline: key.oneline,
|
174
|
+
trust_issues: key.usability_issue
|
175
|
+
}
|
176
|
+
if include_keydata
|
177
|
+
hash[:description] = key.to_s
|
178
|
+
hash[:ascii] = key.armored
|
179
|
+
end
|
180
|
+
hash
|
181
|
+
end
|
182
|
+
|
183
|
+
def set_x_messages(messages)
|
184
|
+
if messages.present?
|
185
|
+
headers 'X-Messages' => Array(messages).join(' // ').gsub(/\n/, ' // ')
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def find_key_material
|
190
|
+
key_material = parsed_body['key_material'].presence
|
191
|
+
# By convention key_material is either ASCII or base64-encoded.
|
192
|
+
if key_material && ! key_material.match('BEGIN PGP')
|
193
|
+
key_material = Base64.decode64(key_material)
|
194
|
+
end
|
195
|
+
key_material
|
196
|
+
end
|
197
|
+
|
198
|
+
def find_attributes_from_body(attribs)
|
199
|
+
Array(attribs).inject({}) do |memo, attrib|
|
200
|
+
if parsed_body.has_key?(attrib)
|
201
|
+
memo[attrib] = parsed_body[attrib]
|
202
|
+
end
|
203
|
+
memo
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def is_an_integer?(input)
|
208
|
+
input.to_s.match(/^[0-9]+$/).present?
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
namespace '/lists' do
|
213
|
+
get '.json' do
|
214
|
+
json List.all, include: :subscriptions
|
215
|
+
end
|
216
|
+
|
217
|
+
post '.json' do
|
218
|
+
listname = parsed_body['email']
|
219
|
+
fingerprint = parsed_body['fingerprint']
|
220
|
+
adminaddress = parsed_body['adminaddress']
|
221
|
+
adminfingerprint = parsed_body['adminfingerprint']
|
222
|
+
adminkey = parsed_body['adminkey']
|
223
|
+
list, messages = ListBuilder.new({email: listname, fingerprint: fingerprint}, adminaddress, adminfingerprint, adminkey).run
|
224
|
+
if list.nil?
|
225
|
+
client_error(messages, 422)
|
226
|
+
elsif ! list.valid?
|
227
|
+
client_error(list, 422)
|
228
|
+
else
|
229
|
+
set_x_messages(messages)
|
230
|
+
body json(list)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
get '/configurable_attributes.json' do
|
235
|
+
json(List.configurable_attributes) + "\n"
|
236
|
+
end
|
237
|
+
|
238
|
+
post '/send_list_key_to_subscriptions.json' do
|
239
|
+
json(result: list.send_list_key_to_subscriptions)
|
240
|
+
end
|
241
|
+
|
242
|
+
get '/new.json' do
|
243
|
+
json List.new
|
244
|
+
end
|
245
|
+
|
246
|
+
get '/:id.json' do |id|
|
247
|
+
json list(id)
|
248
|
+
end
|
249
|
+
|
250
|
+
put '/:id.json' do |id|
|
251
|
+
list = list(id)
|
252
|
+
if list.update(parsed_body)
|
253
|
+
204
|
254
|
+
else
|
255
|
+
client_error(list)
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
patch '/:id.json' do |id|
|
260
|
+
list = list(id)
|
261
|
+
if list.update(parsed_body)
|
262
|
+
204
|
263
|
+
else
|
264
|
+
client_error(list)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
delete '/:id.json' do |id|
|
269
|
+
list = list(id)
|
270
|
+
if list.destroy
|
271
|
+
200
|
272
|
+
else
|
273
|
+
client_error(list)
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
namespace '/subscriptions' do
|
279
|
+
get '.json' do
|
280
|
+
filterkeys = Subscription.configurable_attributes + [:list_id, :email]
|
281
|
+
filter = params.select do |param|
|
282
|
+
filterkeys.include?(param.to_sym)
|
283
|
+
end
|
284
|
+
|
285
|
+
logger.debug "Subscription filter: #{filter.inspect}"
|
286
|
+
if filter['list_id'] && ! is_an_integer?(filter['list_id'])
|
287
|
+
# Value is an email-address
|
288
|
+
if list = List.where(email: filter['list_id']).first
|
289
|
+
filter['list_id'] = list.id
|
290
|
+
else
|
291
|
+
status 404
|
292
|
+
return json(errors: 'No such list')
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
json Subscription.where(filter)
|
297
|
+
end
|
298
|
+
|
299
|
+
post '.json' do
|
300
|
+
begin
|
301
|
+
list = list(requested_list_id)
|
302
|
+
# We don't have to care about nil-values, subscribe() does that for us.
|
303
|
+
sub, msgs = list.subscribe(
|
304
|
+
parsed_body['email'],
|
305
|
+
parsed_body['fingerprint'],
|
306
|
+
parsed_body['admin'],
|
307
|
+
parsed_body['delivery_enabled'],
|
308
|
+
find_key_material
|
309
|
+
)
|
310
|
+
set_x_messages(msgs)
|
311
|
+
logger.debug "subcription: #{sub.inspect}"
|
312
|
+
if sub.valid?
|
313
|
+
logger.debug "Subscribed: #{sub.inspect}"
|
314
|
+
# TODO: why redirect instead of respond with result?
|
315
|
+
redirect to("/subscriptions/#{sub.id}.json"), 201
|
316
|
+
else
|
317
|
+
client_error(sub, 422)
|
318
|
+
end
|
319
|
+
rescue ActiveRecord::RecordNotUnique
|
320
|
+
logger.error "Already subscribed"
|
321
|
+
status 422
|
322
|
+
json errors: {email: ['is already subscribed']}
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
get '/configurable_attributes.json' do
|
327
|
+
json(Subscription.configurable_attributes) + "\n"
|
328
|
+
end
|
329
|
+
|
330
|
+
get '/new.json' do
|
331
|
+
json Subscription.new
|
332
|
+
end
|
333
|
+
|
334
|
+
get '/:id.json' do |id|
|
335
|
+
json subscription(id)
|
336
|
+
end
|
337
|
+
|
338
|
+
put '/:id.json' do |id|
|
339
|
+
sub = subscription(id)
|
340
|
+
list = sub.list
|
341
|
+
args = find_attributes_from_body(%w[email fingerprint admin delivery_enabled])
|
342
|
+
fingerprint, messages = list.import_key_and_find_fingerprint(find_key_material)
|
343
|
+
set_x_messages(messages)
|
344
|
+
# For an already existing subscription, only update fingerprint if a
|
345
|
+
# new one has been selected from the upload.
|
346
|
+
if fingerprint.present?
|
347
|
+
args["fingerprint"] = fingerprint
|
348
|
+
end
|
349
|
+
if sub.update(args)
|
350
|
+
200
|
351
|
+
else
|
352
|
+
client_error(sub, 422)
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
patch '/:id.json' do |id|
|
357
|
+
sub = subscription(id)
|
358
|
+
if sub.update(parsed_body)
|
359
|
+
200
|
360
|
+
else
|
361
|
+
client_error(sub)
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
delete '/:id.json' do |id|
|
366
|
+
if sub = subscription(id).destroy
|
367
|
+
200
|
368
|
+
else
|
369
|
+
client_error(sub)
|
370
|
+
end
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
namespace '/keys' do
|
375
|
+
get '.json' do
|
376
|
+
keys = list.keys.sort_by(&:email).map do |key|
|
377
|
+
key_to_hash(key)
|
378
|
+
end
|
379
|
+
json keys
|
380
|
+
end
|
381
|
+
|
382
|
+
post '.json' do
|
383
|
+
input = parsed_body['keymaterial']
|
384
|
+
if ! input.match('BEGIN PGP')
|
385
|
+
input = Base64.decode64(input)
|
386
|
+
end
|
387
|
+
json list(requested_list_id).import_key(input)
|
388
|
+
end
|
389
|
+
|
390
|
+
get '/check_keys.json' do
|
391
|
+
json result: list.check_keys
|
392
|
+
end
|
393
|
+
|
394
|
+
get '/:fingerprint.json' do |fingerprint|
|
395
|
+
if key = list.key(fingerprint)
|
396
|
+
json key_to_hash(key, true)
|
397
|
+
else
|
398
|
+
404
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
delete '/:fingerprint.json' do |fingerprint|
|
403
|
+
if list.delete_key(fingerprint)
|
404
|
+
200
|
405
|
+
else
|
406
|
+
404
|
407
|
+
end
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
411
|
+
def self.run!
|
412
|
+
super do |server|
|
413
|
+
server.ssl = true
|
414
|
+
server.ssl_options = {
|
415
|
+
:cert_chain_file => Conf.api['tls_cert_file'],
|
416
|
+
:private_key_file => Conf.api['tls_key_file']
|
417
|
+
}
|
418
|
+
end
|
419
|
+
end
|
420
|
+
end
|