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.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +21 -11
  3. data/Rakefile +18 -10
  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/migrate/20180723173900_add_deliver_selfsent_to_list.rb +11 -0
  8. data/db/migrate/20190906194820_add_autocrypt_header_to_list.rb +11 -0
  9. data/db/schema.rb +4 -2
  10. data/etc/list-defaults.yml +13 -3
  11. data/etc/schleuder.yml +11 -0
  12. data/lib/schleuder-api-daemon.rb +9 -354
  13. data/lib/schleuder-api-daemon/helpers/schleuder-api-daemon-helper.rb +143 -0
  14. data/lib/schleuder-api-daemon/routes/key.rb +40 -0
  15. data/lib/schleuder-api-daemon/routes/list.rb +69 -0
  16. data/lib/schleuder-api-daemon/routes/status.rb +5 -0
  17. data/lib/schleuder-api-daemon/routes/subscription.rb +99 -0
  18. data/lib/schleuder-api-daemon/routes/version.rb +5 -0
  19. data/lib/schleuder.rb +12 -3
  20. data/lib/schleuder/cli.rb +33 -3
  21. data/lib/schleuder/cli/subcommand_fix.rb +1 -1
  22. data/lib/schleuder/conf.rb +7 -1
  23. data/lib/schleuder/errors/active_model_error.rb +2 -5
  24. data/lib/schleuder/errors/decryption_failed.rb +2 -7
  25. data/lib/schleuder/errors/key_adduid_failed.rb +1 -5
  26. data/lib/schleuder/errors/key_generation_failed.rb +1 -8
  27. data/lib/schleuder/errors/keyword_admin_only.rb +1 -5
  28. data/lib/schleuder/errors/list_not_found.rb +1 -5
  29. data/lib/schleuder/errors/listdir_problem.rb +2 -7
  30. data/lib/schleuder/errors/loading_list_settings_failed.rb +2 -5
  31. data/lib/schleuder/errors/message_empty.rb +1 -5
  32. data/lib/schleuder/errors/message_not_from_admin.rb +2 -5
  33. data/lib/schleuder/errors/message_sender_not_subscribed.rb +2 -5
  34. data/lib/schleuder/errors/message_too_big.rb +2 -5
  35. data/lib/schleuder/errors/message_unauthenticated.rb +1 -4
  36. data/lib/schleuder/errors/message_unencrypted.rb +2 -5
  37. data/lib/schleuder/errors/message_unsigned.rb +2 -5
  38. data/lib/schleuder/errors/too_many_keys.rb +1 -8
  39. data/lib/schleuder/filters/{request_filter.rb → post_decryption/10_request.rb} +0 -0
  40. data/lib/schleuder/filters/{max_message_size.rb → post_decryption/20_max_message_size.rb} +0 -0
  41. data/lib/schleuder/filters/{forward_filter.rb → post_decryption/30_forward_to_owner.rb} +0 -0
  42. data/lib/schleuder/filters/post_decryption/40_receive_admin_only.rb +10 -0
  43. data/lib/schleuder/filters/post_decryption/50_receive_authenticated_only.rb +10 -0
  44. data/lib/schleuder/filters/post_decryption/60_receive_signed_only.rb +10 -0
  45. data/lib/schleuder/filters/post_decryption/70_receive_encrypted_only.rb +10 -0
  46. data/lib/schleuder/filters/post_decryption/80_receive_from_subscribed_emailaddresses_only.rb +10 -0
  47. data/lib/schleuder/filters/post_decryption/90_strip_html_from_alternative_if_keywords_present.rb +21 -0
  48. data/lib/schleuder/filters/{bounces_filter.rb → pre_decryption/10_forward_bounce_to_admins.rb} +0 -0
  49. data/lib/schleuder/filters/{forward_incoming.rb → pre_decryption/20_forward_all_incoming_to_admins.rb} +0 -0
  50. data/lib/schleuder/filters/{send_key_filter.rb → pre_decryption/30_send_key.rb} +0 -0
  51. data/lib/schleuder/filters/{hotmail_message_filter.rb → pre_decryption/40_fix_exchange_messages.rb} +5 -3
  52. data/lib/schleuder/filters/{strip_alternative_filter.rb → pre_decryption/50_strip_html_from_alternative.rb} +1 -1
  53. data/lib/schleuder/filters_runner.rb +41 -31
  54. data/lib/schleuder/gpgme/ctx.rb +24 -3
  55. data/lib/schleuder/gpgme/import_status.rb +13 -7
  56. data/lib/schleuder/gpgme/key.rb +8 -0
  57. data/lib/schleuder/list.rb +26 -4
  58. data/lib/schleuder/logger_notifications.rb +8 -1
  59. data/lib/schleuder/mail/encrypted_part.rb +14 -0
  60. data/lib/schleuder/mail/gpg.rb +15 -0
  61. data/lib/schleuder/mail/message.rb +97 -49
  62. data/lib/schleuder/plugins/attach_listkey.rb +6 -10
  63. data/lib/schleuder/plugins/key_management.rb +34 -26
  64. data/lib/schleuder/plugins/resend.rb +14 -11
  65. data/lib/schleuder/plugins/subscription_management.rb +70 -3
  66. data/lib/schleuder/runner.rb +49 -10
  67. data/lib/schleuder/subscription.rb +5 -9
  68. data/lib/schleuder/validators/fingerprint_validator.rb +1 -1
  69. data/lib/schleuder/version.rb +1 -1
  70. data/locales/de.yml +101 -9
  71. data/locales/en.yml +107 -11
  72. metadata +72 -34
  73. data/lib/schleuder/errors/file_not_found.rb +0 -14
  74. data/lib/schleuder/errors/invalid_listname.rb +0 -13
  75. data/lib/schleuder/errors/list_exists.rb +0 -13
  76. data/lib/schleuder/errors/unknown_list_option.rb +0 -14
  77. 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: 8e820f173303f3322674fe67b3bf7fc6468b376d15afa959feca090de32381f3
4
+ data.tar.gz: 5747036650daa9ad1a3d67fd8597d084fa6f78ddefd063293c7e61ce53431805
5
5
  SHA512:
6
- metadata.gz: 25adeec03329d06994b3ebada2d8b0dd9f9e50ee8c83e5349496decacf9877e8388f2122656f984516f3b1d8f3872748d8b91366131cd6f21b4c2eef5caa915f
7
- data.tar.gz: 83b6170572c99168c6b49471d2a34823b49e878f6d1c03ea5f65f7c9a7d999f80996c92813892942e1940822615ba17c4b8da9c864cc59c46b88f8730d5ebfed
6
+ metadata.gz: 206b404982bec910328d1fb9b90eaa1c3f6b088da5acdaf2f7825a45401bc334938a71b6afb639f0a75b2e8e1b18a7af675213d05b1d60ea539d904fe4da9987
7
+ data.tar.gz: 3f4224d41d1b1de88e3b2648c378b7c09b5762d15ee38f9f45331317d749f0266c1cc9a11ffdec65f2907b8da340d20f6e1c3442f2a8dc7ce625c2b732ff3a2f
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,11 +16,11 @@ 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 buster or CentOS 7, please have a look at the [installation docs](https://schleuder.org/schleuder/docs/server-admins.html#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
- On systems that base on Debian 9 ("stretch"), install the dependencies via
23
+ On systems that base on Debian 10 ("buster"), install the dependencies via
24
24
 
25
25
  apt-get install ruby-dev gnupg2 libgpgme-dev libsqlite3-dev libssl-dev build-essential
26
26
 
@@ -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.5.2.gem) and [the OpenPGP-signature](https://schleuder.org/download/schleuder-3.5.2.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.5.2.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.5.2.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/schleuder/docs/server-admins.html>.
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 10 ("buster") 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.5.2.tar.gz) and [its OpenPGP-signature](https://schleuder.org/download/schleuder-3.5.2.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 = 'B3D190D5235C74E1907EACFE898F2C91E2E6E1F3'
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,18 +89,28 @@ 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'
100
111
  task :publish_gem do
101
112
  puts "Really push #{@filename_gem} to rubygems.org? [yN]"
102
- if gets.match(/^y/i)
113
+ if $stdin.gets.match(/^y/i)
103
114
  puts "Pushing..."
104
115
  `gem push #{@filename_gem}`
105
116
  else
@@ -114,17 +125,14 @@ 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'
124
132
  task :check_version do
125
133
  # Check if Schleuder::VERSION has been updated since last release
126
134
  if `git tag`.match?(/^#{@tagname}$/)
127
- $stderr.puts "Warning: Tag '#{@tagname}' already exists. Did you forget to update #{project}/version.rb?"
135
+ $stderr.puts "Warning: Tag '#{@tagname}' already exists. Did you forget to update lib/#{project}/version.rb?"
128
136
  $stderr.print "Delete tag to continue? [yN] "
129
137
  if $stdin.gets.match(/^y/i)
130
138
  `git tag -d #{@tagname}`
@@ -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
@@ -0,0 +1,11 @@
1
+ class AddDeliverSelfsentToList < ActiveRecord::Migration
2
+ def up
3
+ if ! column_exists?(:lists, :deliver_selfsent)
4
+ add_column :lists, :deliver_selfsent, :boolean, default: true
5
+ end
6
+ end
7
+
8
+ def down
9
+ remove_column(:lists, :deliver_selfsent)
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ class AddAutocryptHeaderToList < ActiveRecord::Migration
2
+ def up
3
+ if ! column_exists?(:lists, :include_autocrypt_header)
4
+ add_column :lists, :include_autocrypt_header, :boolean, default: true
5
+ end
6
+ end
7
+
8
+ def down
9
+ remove_column(:lists, :include_autocrypt_header)
10
+ end
11
+ 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: 20190906194820) 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\"]"
@@ -37,6 +37,7 @@ ActiveRecord::Schema.define(version: 20170713215059) do
37
37
  t.boolean "keep_msgid", default: true
38
38
  t.boolean "bounces_drop_all", default: false
39
39
  t.boolean "bounces_notify_admins", default: true
40
+ t.boolean "deliver_selfsent", default: true
40
41
  t.boolean "include_list_headers", default: true
41
42
  t.boolean "include_openpgp_header", default: true
42
43
  t.integer "max_message_size_kb", default: 10240
@@ -44,6 +45,7 @@ ActiveRecord::Schema.define(version: 20170713215059) do
44
45
  t.boolean "forward_all_incoming_to_admins", default: false
45
46
  t.integer "logfiles_to_keep", default: 2
46
47
  t.text "internal_footer", default: ""
48
+ t.boolean "include_autocrypt_header", default: true
47
49
  end
48
50
 
49
51
  create_table "subscriptions", force: :cascade do |t|
@@ -6,7 +6,7 @@
6
6
  #
7
7
  # Options are listed with the behaviour encoded in the database schema.
8
8
 
9
- # Only send out enrypted emails to subscriptions?
9
+ # Only send out encrypted emails to subscriptions?
10
10
  # (This setting does not affect resend-messages.)
11
11
  send_encrypted_only: true
12
12
 
@@ -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
@@ -91,13 +93,16 @@ bounces_drop_on_headers:
91
93
  # Send a notice to the list-admins whenever an email is bounced or dropped?
92
94
  bounces_notify_admins: true
93
95
 
96
+ # Include Autocrypt header into emails?
97
+ include_autocrypt_header: true
98
+
94
99
  # Include RFC-compliant List-* Headers into emails?
95
100
  include_list_headers: true
96
101
 
97
102
  # Include OpenPGP-Header into emails?
98
103
  include_openpgp_header: true
99
104
 
100
- # Prefered way to receive emails to note in OpenPGP-Header
105
+ # Preferred way to receive emails to note in OpenPGP-Header
101
106
  # ('sign'|'encrypt'|'signencrypt'|'unprotected'|'none')
102
107
  openpgp_header_preference: signencrypt
103
108
 
@@ -121,3 +126,8 @@ language: en
121
126
  # Forward a raw copy of all incoming emails to the list-admins?
122
127
  # Mainly useful for debugging.
123
128
  forward_all_incoming_to_admins: false
129
+
130
+ # Should e-mails be delivered to the original subscribed sender?
131
+ # Disabling this only works for signed e-mails; any e-mail that is unsigned
132
+ # sent to the list is treated as coming from an unknown source
133
+ deliver_selfsent: true
@@ -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