schleuder 3.2.2 → 3.3.0

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.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +20 -10
  3. data/Rakefile +16 -8
  4. data/bin/schleuder +2 -1
  5. data/bin/schleuder-api-daemon +3 -2
  6. data/db/migrate/20180110203100_add_sig_enc_to_headers_to_meta_defaults.rb +30 -0
  7. data/db/schema.rb +2 -2
  8. data/etc/list-defaults.yml +4 -2
  9. data/etc/schleuder.yml +11 -0
  10. data/lib/schleuder-api-daemon.rb +9 -354
  11. data/lib/schleuder-api-daemon/helpers/schleuder-api-daemon-helper.rb +143 -0
  12. data/lib/schleuder-api-daemon/routes/key.rb +40 -0
  13. data/lib/schleuder-api-daemon/routes/list.rb +69 -0
  14. data/lib/schleuder-api-daemon/routes/status.rb +5 -0
  15. data/lib/schleuder-api-daemon/routes/subscription.rb +99 -0
  16. data/lib/schleuder-api-daemon/routes/version.rb +5 -0
  17. data/lib/schleuder.rb +2 -3
  18. data/lib/schleuder/cli.rb +24 -0
  19. data/lib/schleuder/cli/subcommand_fix.rb +1 -1
  20. data/lib/schleuder/conf.rb +7 -1
  21. data/lib/schleuder/errors/active_model_error.rb +2 -5
  22. data/lib/schleuder/errors/decryption_failed.rb +2 -7
  23. data/lib/schleuder/errors/key_adduid_failed.rb +1 -5
  24. data/lib/schleuder/errors/key_generation_failed.rb +1 -8
  25. data/lib/schleuder/errors/keyword_admin_only.rb +1 -5
  26. data/lib/schleuder/errors/list_not_found.rb +1 -5
  27. data/lib/schleuder/errors/listdir_problem.rb +2 -7
  28. data/lib/schleuder/errors/loading_list_settings_failed.rb +2 -5
  29. data/lib/schleuder/errors/message_empty.rb +1 -5
  30. data/lib/schleuder/errors/message_not_from_admin.rb +2 -5
  31. data/lib/schleuder/errors/message_sender_not_subscribed.rb +2 -5
  32. data/lib/schleuder/errors/message_too_big.rb +2 -5
  33. data/lib/schleuder/errors/message_unauthenticated.rb +1 -4
  34. data/lib/schleuder/errors/message_unencrypted.rb +2 -5
  35. data/lib/schleuder/errors/message_unsigned.rb +2 -5
  36. data/lib/schleuder/errors/too_many_keys.rb +1 -8
  37. data/lib/schleuder/filters/{request_filter.rb → post_decryption/10_request.rb} +0 -0
  38. data/lib/schleuder/filters/{max_message_size.rb → post_decryption/20_max_message_size.rb} +0 -0
  39. data/lib/schleuder/filters/{forward_filter.rb → post_decryption/30_forward_to_owner.rb} +0 -0
  40. data/lib/schleuder/filters/post_decryption/40_receive_admin_only.rb +10 -0
  41. data/lib/schleuder/filters/post_decryption/50_receive_authenticated_only.rb +10 -0
  42. data/lib/schleuder/filters/post_decryption/60_receive_signed_only.rb +10 -0
  43. data/lib/schleuder/filters/post_decryption/70_receive_encrypted_only.rb +10 -0
  44. data/lib/schleuder/filters/post_decryption/80_receive_from_subscribed_emailaddresses_only.rb +10 -0
  45. data/lib/schleuder/filters/{bounces_filter.rb → pre_decryption/10_forward_bounce_to_admins.rb} +0 -0
  46. data/lib/schleuder/filters/{forward_incoming.rb → pre_decryption/20_forward_all_incoming_to_admins.rb} +0 -0
  47. data/lib/schleuder/filters/{send_key_filter.rb → pre_decryption/30_send_key.rb} +0 -0
  48. data/lib/schleuder/filters/{hotmail_message_filter.rb → pre_decryption/40_fix_exchange_messages.rb} +5 -3
  49. data/lib/schleuder/filters/{strip_alternative_filter.rb → pre_decryption/50_strip_html_from_alternative.rb} +1 -1
  50. data/lib/schleuder/filters_runner.rb +41 -31
  51. data/lib/schleuder/gpgme/ctx.rb +1 -1
  52. data/lib/schleuder/gpgme/import_status.rb +13 -7
  53. data/lib/schleuder/gpgme/key.rb +4 -0
  54. data/lib/schleuder/list.rb +7 -4
  55. data/lib/schleuder/mail/encrypted_part.rb +14 -0
  56. data/lib/schleuder/mail/gpg.rb +15 -0
  57. data/lib/schleuder/mail/message.rb +70 -30
  58. data/lib/schleuder/plugins/key_management.rb +32 -7
  59. data/lib/schleuder/plugins/subscription_management.rb +70 -3
  60. data/lib/schleuder/runner.rb +19 -8
  61. data/lib/schleuder/subscription.rb +5 -9
  62. data/lib/schleuder/validators/fingerprint_validator.rb +1 -1
  63. data/lib/schleuder/version.rb +1 -1
  64. data/locales/de.yml +96 -8
  65. data/locales/en.yml +102 -10
  66. metadata +48 -27
  67. data/lib/schleuder/errors/file_not_found.rb +0 -14
  68. data/lib/schleuder/errors/invalid_listname.rb +0 -13
  69. data/lib/schleuder/errors/list_exists.rb +0 -13
  70. data/lib/schleuder/errors/unknown_list_option.rb +0 -14
  71. data/lib/schleuder/filters/auth_filter.rb +0 -39
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: edc9a5383dea2704c0ea9cfaa947e657221b89a83ff693cc221c5649026711f5
4
- data.tar.gz: 8c4117d91098a20ccb9d4f12146524eb8e7d701f60d9a77ce0573510b1dbeb42
3
+ metadata.gz: 637d9f0b81f2cb7aaee30a9761eeb0f09f49d95649a00d735ce13ecd008abdad
4
+ data.tar.gz: ca41b305951ef8ac0fb7edfb42e87521cf1d2ce5e51be6ceaa3c57c933846067
5
5
  SHA512:
6
- metadata.gz: 25adeec03329d06994b3ebada2d8b0dd9f9e50ee8c83e5349496decacf9877e8388f2122656f984516f3b1d8f3872748d8b91366131cd6f21b4c2eef5caa915f
7
- data.tar.gz: 83b6170572c99168c6b49471d2a34823b49e878f6d1c03ea5f65f7c9a7d999f80996c92813892942e1940822615ba17c4b8da9c864cc59c46b88f8730d5ebfed
6
+ metadata.gz: 3b7f8cd46761314484df53f64ba3d929c75eccdfd4c7a2c7ce87d76720b6fa1025d59f370126b107b08a19b9916fe7e160563739a1058dc88a537acd744af212
7
+ data.tar.gz: 149620dc7fc6549391af197396b68c8cf42b990e037d2224e337db57af00f90edb293e23120a8f2f8156e40cbfadcd35bca1009d066ba2126f98c4b7c90ae29a
data/README.md CHANGED
@@ -6,7 +6,7 @@ Schleuder is a gpg-enabled mailing list manager with resending-capabilities. Sub
6
6
  Version 3 of schleuder is a complete rewrite, which aims to be more robust, flexible, and internationalized. It
7
7
  also provides an API for the optional web interface called [schleuder-web](https://0xacab.org/schleuder/schleuder-web).
8
8
 
9
- For more details see <https://schleuder.nadir.org/docs/>.
9
+ For more details see <https://schleuder.org/docs/>.
10
10
 
11
11
  Requirements
12
12
  ------------
@@ -16,9 +16,9 @@ Requirements
16
16
  * sqlite3
17
17
  * openssl
18
18
 
19
- *If you use Debian stretch or CentOS 7, please have a look at the [installation docs](https://schleuder.nadir.org/docs/#installation). We do provide packages for those platforms, which simplify the installation a lot.*
19
+ *If you use Debian stretch or CentOS 7, please have a look at the [installation docs](https://schleuder.org/docs/#installation). We do provide packages for those platforms, which simplify the installation a lot.*
20
20
 
21
- *🛈 A note regarding Ubuntu: All released Ubuntu versions (including 17.10) don't meet the requirements with their packaged versions of gnupg! To run Schleuder on Ubuntu you currently have to install a more recent version of gnupg manually. A sufficient version of gnupg is included in "bionic-proposed", which might make 18.04 a usable Ubuntu release.*
21
+ *🛈 A note regarding Ubuntu: All Ubuntu versions up to and including 17.10 don't meet the requirements with their packaged versions of gnupg! To run Schleuder on Ubuntu you currently have to install a more recent version of gnupg manually. Only Ubuntu 18.04 ("bionic") provides modern enough versions of Schleuder's requirements.*
22
22
 
23
23
  On systems that base on Debian 9 ("stretch"), install the dependencies via
24
24
 
@@ -47,25 +47,25 @@ Additionally these **rubygems** are required (will be installed automatically un
47
47
  Installing Schleuder
48
48
  ------------
49
49
 
50
- 1. Download [the gem](https://schleuder.nadir.org/downloads/schleuder-3.2.2.gem) and [the OpenPGP-signature](https://schleuder.nadir.org/downloads/schleuder-3.2.2.gem.sig) and verify:
50
+ 1. Download [the gem](https://schleuder.org/download/schleuder-3.3.0.gem) and [the OpenPGP-signature](https://schleuder.org/download/schleuder-3.3.0.gem.sig) and verify:
51
51
  ```
52
52
  gpg --recv-key 0xB3D190D5235C74E1907EACFE898F2C91E2E6E1F3
53
- gpg --verify schleuder-3.2.2.gem.sig
53
+ gpg --verify schleuder-3.3.0.gem.sig
54
54
  ```
55
55
 
56
56
  2. If all went well install the gem:
57
57
  ```
58
- gem install schleuder-3.2.2.gem
58
+ gem install schleuder-3.3.0.gem
59
59
  ```
60
60
 
61
61
  3. Set up schleuder:
62
62
  ```
63
63
  schleuder install
64
64
  ```
65
- This creates neccessary directories, copies example configs, etc. If you see errors about missing write permissions please follow the advice given.
65
+ This creates necessary directories, copies example configs, etc. If you see errors about missing write permissions please follow the advice given.
66
66
 
67
67
 
68
- For further information on setup and configuration please read <https://schleuder.nadir.org/docs/#setup>.
68
+ For further information on setup and configuration please read <https://schleuder.org/docs/#setup>.
69
69
 
70
70
 
71
71
  Command line usage
@@ -92,7 +92,7 @@ manage lists from the command line.
92
92
  Optionally consider installing
93
93
  [schleuder-web](https://0xacab.org/schleuder/schleuder-web), the web
94
94
  interface for schleuder. It enables list-admins to manage their lists through
95
- the web instead of using [request-keywords](https://schleuder.nadir.org/docs/#subscription-and-key-management).
95
+ the web instead of using [request-keywords](https://schleuder.org/docs/#subscription-and-key-management).
96
96
 
97
97
 
98
98
 
@@ -112,6 +112,10 @@ To execute the test suite run:
112
112
 
113
113
  bundle exec rspec
114
114
 
115
+ Please note: Some of the specs use 'pgrep'. On systems that base on Debian 9 ("stretch") install it via
116
+
117
+ apt-get install procps
118
+
115
119
  We are working on extendig the test coverage.
116
120
 
117
121
  Contributing
@@ -120,6 +124,12 @@ Contributing
120
124
  Please see [CONTRIBUTING.md](CONTRIBUTING.md).
121
125
 
122
126
 
127
+ Mission statement
128
+ -----------------
129
+
130
+ Please see [MISSION_STATEMENT.md](MISSION_STATEMENT.md).
131
+
132
+
123
133
  Code of Conduct
124
134
  ---------------
125
135
 
@@ -135,4 +145,4 @@ GNU GPL 3.0. Please see [LICENSE.txt](LICENSE.txt).
135
145
  Alternative Download
136
146
  --------------------
137
147
 
138
- Alternatively to the gem-files you can download the latest release as [a tarball](https://schleuder.nadir.org/downloads/schleuder-3.2.2.tar.gz) and [its OpenPGP-signature](https://schleuder.nadir.org/downloads/schleuder-3.2.2.tar.gz.sig).
148
+ Alternatively to the gem-files you can download the latest release as [a tarball](https://schleuder.org/download/schleuder-3.3.0.tar.gz) and [its OpenPGP-signature](https://schleuder.org/download/schleuder-3.3.0.tar.gz.sig).
data/Rakefile CHANGED
@@ -3,7 +3,7 @@ require_relative "lib/#{project}.rb"
3
3
 
4
4
  @version = Schleuder::VERSION
5
5
  @tagname = "#{project}-#{@version}"
6
- @gpguid = 'schleuder@nadir.org'
6
+ @gpguid = 'team@schleuder.org'
7
7
  @filename_gem = "#{@tagname}.gem"
8
8
  @filename_tarball = "#{@tagname}.tar.gz"
9
9
 
@@ -52,6 +52,7 @@ task :new_version => [
52
52
  :sign_gem,
53
53
  :build_tarball,
54
54
  :sign_tarball,
55
+ :ensure_permissions,
55
56
  :git_tag
56
57
  ] do
57
58
  end
@@ -78,7 +79,7 @@ end
78
79
 
79
80
  desc "Commit changes as new version"
80
81
  task :git_commit do
81
- `git commit -m "Version #{@version} (README, gems, ...)"`
82
+ `git commit -m "Version #{@version}"`
82
83
  end
83
84
 
84
85
  desc 'Build, sign and commit a gem-file.'
@@ -88,12 +89,22 @@ end
88
89
 
89
90
  desc 'OpenPGP-sign gem and tarball'
90
91
  task :sign_tarball do
91
- `gpg -u #{@gpguid} -b #{@filename_gem}`
92
+ `gpg -u #{@gpguid} -b #{@filename_tarball}`
92
93
  end
93
94
 
94
95
  desc 'OpenPGP-sign gem'
95
96
  task :sign_gem do
96
- `gpg -u #{@gpguid} -b #{@filename_tarball}`
97
+ `gpg -u #{@gpguid} -b #{@filename_gem}`
98
+ end
99
+
100
+ desc 'Ensure download-files have correct permissions'
101
+ task :ensure_permissions do
102
+ File.chmod(0644, *Dir.glob("#{@tagname}*"))
103
+ end
104
+
105
+ desc 'Upload download-files (gem, tarball, signatures) to schleuder.org.'
106
+ task :upload_files do
107
+ puts `echo "put -p #{@tagname}* www/download/" | sftp schleuder.org@ftp.schleuder.org 2>&1`
97
108
  end
98
109
 
99
110
  desc 'Publish gem-file to rubygems.org'
@@ -114,10 +125,7 @@ end
114
125
 
115
126
  desc 'Describe manual release-tasks'
116
127
  task :website do
117
- puts "Please update the website:
118
- * Update changelog.
119
- * Publish release-announcement.
120
- "
128
+ puts "Please remember to publish the release-notes on the website and on schleuder-announce."
121
129
  end
122
130
 
123
131
  desc 'Check if version-tag already exists'
@@ -8,7 +8,8 @@ trap("INT") { exit 1 }
8
8
 
9
9
 
10
10
  begin
11
- require_relative '../lib/schleuder/cli'
11
+ $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
12
+ require 'schleuder/cli'
12
13
  Schleuder::Cli.start
13
14
  rescue => exc
14
15
  $stderr.puts "Technical Error: #{exc}\n#{exc.backtrace.first}"
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require_relative '../lib/schleuder-api-daemon'
4
- SchleuderApiDaemon.run!
3
+ $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
4
+ require 'schleuder-api-daemon'
5
+ SchleuderApiDaemon.run!
@@ -0,0 +1,30 @@
1
+ class AddSigEncToHeadersToMetaDefaults < ActiveRecord::Migration
2
+ def up
3
+ change_column_default :lists, :headers_to_meta, '["from", "to", "cc", "date", "sig", "enc"]'
4
+ list_klass = create_list_klass
5
+ list_klass.reset_column_information
6
+ list_klass.find_each do |list|
7
+ if (list.headers_to_meta & ['sig', 'enc']).empty?
8
+ list.update(headers_to_meta: list.headers_to_meta + ['sig', 'enc'])
9
+ end
10
+ end
11
+ end
12
+
13
+ def down
14
+ change_column_default :lists, :headers_to_meta, '["from", "to", "cc", "date"]'
15
+ list_klass = create_list_klass
16
+ list_klass.reset_column_information
17
+ list_klass.find_each do |list|
18
+ list.update(headers_to_meta: list.headers_to_meta - ['enc','sig'])
19
+ end
20
+ end
21
+
22
+ def create_list_klass
23
+ # Use a temporary class-definition to be independent of the
24
+ # complexities of the actual class.
25
+ Class.new(ActiveRecord::Base) do
26
+ self.table_name = 'lists'
27
+ self.serialize :headers_to_meta, JSON
28
+ end
29
+ end
30
+ end
@@ -11,7 +11,7 @@
11
11
  #
12
12
  # It's strongly recommended that you check this file into your version control system.
13
13
 
14
- ActiveRecord::Schema.define(version: 20170713215059) do
14
+ ActiveRecord::Schema.define(version: 20180110203100) do
15
15
 
16
16
  create_table "lists", force: :cascade do |t|
17
17
  t.datetime "created_at"
@@ -24,7 +24,7 @@ ActiveRecord::Schema.define(version: 20170713215059) do
24
24
  t.string "subject_prefix_out", limit: 255, default: ""
25
25
  t.string "openpgp_header_preference", limit: 255, default: "signencrypt"
26
26
  t.text "public_footer", default: ""
27
- t.text "headers_to_meta", default: "[\"from\", \"to\", \"date\", \"cc\"]"
27
+ t.text "headers_to_meta", default: "[\"from\", \"to\", \"cc\", \"date\", \"sig\", \"enc\"]"
28
28
  t.text "bounces_drop_on_headers", default: "{\"x-spam-flag\":\"yes\"}"
29
29
  t.text "keywords_admin_only", default: "[\"subscribe\", \"unsubscribe\", \"delete-key\"]"
30
30
  t.text "keywords_admin_notify", default: "[\"add-key\"]"
@@ -26,7 +26,7 @@ receive_authenticated_only: false
26
26
  # NOTE: This is a very weak restriction mechanism on which you should not rely,
27
27
  # as sending addresses can easily be faked! We recommend you to rather
28
28
  # rely on the `receive_authenticated_only` option. Setting the
29
- # `receive_authenticated_only` option to true, will authenticated senders
29
+ # `receive_authenticated_only` option to true, will authenticate senders
30
30
  # based on the signature on the mail, which is the strongest
31
31
  # authentication mechanism you can get.
32
32
  # This option could be useful, if you would like to have a closed
@@ -43,6 +43,8 @@ headers_to_meta:
43
43
  - to
44
44
  - cc
45
45
  - date
46
+ - sig
47
+ - enc
46
48
 
47
49
  # Preserve the Message-IDs (In-Reply-To, References) from the incoming email.
48
50
  # This setting can lead to information leakage, as replies are connectable
@@ -97,7 +99,7 @@ include_list_headers: true
97
99
  # Include OpenPGP-Header into emails?
98
100
  include_openpgp_header: true
99
101
 
100
- # Prefered way to receive emails to note in OpenPGP-Header
102
+ # Preferred way to receive emails to note in OpenPGP-Header
101
103
  # ('sign'|'encrypt'|'signencrypt'|'unprotected'|'none')
102
104
  openpgp_header_preference: signencrypt
103
105
 
@@ -7,6 +7,17 @@ listlogs_dir: /var/lib/schleuder/lists
7
7
  # Schleuder reads plugins also from this directory.
8
8
  plugins_dir: /etc/schleuder/plugins
9
9
 
10
+ # Schleuder reads filters also from this directory path,
11
+ # in the specific pre_decryption or post_decryption subdirectory.
12
+ # Filter files must follow the following convention for the
13
+ # filename: \d+_a_name.rb
14
+ # Where \d+ is any number, that defines the place in the
15
+ # list of filters and a_name must match the method name
16
+ # of the filter.
17
+ # The built-in filters are using round numbers for their
18
+ # positioning within the list. Increased by ten.
19
+ filters_dir: /usr/local/lib/schleuder/filters
20
+
10
21
  # How verbose should Schleuder log to syslog? (list-specific messages are written to the list's log-file).
11
22
  log_level: warn
12
23
 
@@ -3,12 +3,18 @@
3
3
  # Make sinatra use production as default-environment
4
4
  ENV['RACK_ENV'] ||= 'production'
5
5
 
6
+ $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
6
7
  require 'sinatra/base'
7
8
  require 'sinatra/json'
8
9
  require 'sinatra/namespace'
9
10
  require 'thin'
10
- require_relative '../lib/schleuder.rb'
11
-
11
+ require 'schleuder'
12
+ require 'schleuder-api-daemon/routes/status'
13
+ require 'schleuder-api-daemon/routes/version'
14
+ require 'schleuder-api-daemon/routes/list'
15
+ require 'schleuder-api-daemon/routes/subscription'
16
+ require 'schleuder-api-daemon/routes/key'
17
+ require 'schleuder-api-daemon/helpers/schleuder-api-daemon-helper'
12
18
 
13
19
  %w[tls_cert_file tls_key_file].each do |config_key|
14
20
  path = Conf.api[config_key]
@@ -19,7 +25,7 @@ require_relative '../lib/schleuder.rb'
19
25
  end
20
26
 
21
27
  class SchleuderApiDaemon < Sinatra::Base
22
- register Sinatra::Namespace
28
+ helpers SchleuderApiDaemonHelper
23
29
 
24
30
  configure do
25
31
  set :server, :thin
@@ -57,357 +63,6 @@ class SchleuderApiDaemon < Sinatra::Base
57
63
  'Not found'
58
64
  end
59
65
 
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
66
  def self.run!
412
67
  super do |server|
413
68
  server.ssl = true