schleuder 3.2.2 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
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