schleuder 3.4.1 → 3.5.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.
- checksums.yaml +4 -4
- data/README.md +5 -5
- data/Rakefile +2 -2
- data/db/migrate/20180723173900_add_deliver_selfsent_to_list.rb +11 -0
- data/db/migrate/20190906194820_add_autocrypt_header_to_list.rb +11 -0
- data/db/schema.rb +3 -1
- data/etc/list-defaults.yml +8 -0
- data/lib/schleuder.rb +10 -0
- data/lib/schleuder/cli.rb +1 -0
- data/lib/schleuder/gpgme/key.rb +4 -0
- data/lib/schleuder/list.rb +23 -4
- data/lib/schleuder/logger_notifications.rb +2 -0
- data/lib/schleuder/mail/message.rb +29 -20
- data/lib/schleuder/plugins/attach_listkey.rb +6 -10
- data/lib/schleuder/plugins/resend.rb +14 -11
- data/lib/schleuder/runner.rb +30 -2
- data/lib/schleuder/version.rb +1 -1
- data/locales/de.yml +4 -1
- data/locales/en.yml +4 -1
- metadata +25 -9
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 49f682bc409302cde8907906dbbbab0238d4e404748874b5c3b263806b70abbe
         | 
| 4 | 
            +
              data.tar.gz: c47b37fc7c1dede5b95bd396ceef0642cf5061af574a589b84497e01d1f7dcf8
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 42706627c3b2ea15d6e735cc28fcaa34a4bcd4cf58bb6789edd5ce83ba8033e10259a16cd61e06d5d2a25f01aa55a25f9a03073a5a03683cab2dc093a04e1103
         | 
| 7 | 
            +
              data.tar.gz: b5b784eafd81435118bac61ce089d36e45e0932c46816aa46ae3da199fa96f9cd9c4e31c9dea58eba93d37de707d121a3ee69949388096c8b4330b7498b9a4ad
         | 
    
        data/README.md
    CHANGED
    
    | @@ -47,15 +47,15 @@ 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.org/download/schleuder-3. | 
| 50 | 
            +
            1. Download [the gem](https://schleuder.org/download/schleuder-3.5.0.gem) and [the OpenPGP-signature](https://schleuder.org/download/schleuder-3.5.0.gem.sig) and verify:
         | 
| 51 51 | 
             
               ```
         | 
| 52 52 | 
             
               gpg --recv-key 0xB3D190D5235C74E1907EACFE898F2C91E2E6E1F3
         | 
| 53 | 
            -
               gpg --verify schleuder-3. | 
| 53 | 
            +
               gpg --verify schleuder-3.5.0.gem.sig
         | 
| 54 54 | 
             
               ```
         | 
| 55 55 |  | 
| 56 56 | 
             
            2. If all went well install the gem:
         | 
| 57 57 | 
             
               ```
         | 
| 58 | 
            -
               gem install schleuder-3. | 
| 58 | 
            +
               gem install schleuder-3.5.0.gem
         | 
| 59 59 | 
             
               ```
         | 
| 60 60 |  | 
| 61 61 | 
             
            3. Set up schleuder:
         | 
| @@ -65,7 +65,7 @@ Installing Schleuder | |
| 65 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.org/docs | 
| 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
         | 
| @@ -145,4 +145,4 @@ GNU GPL 3.0. Please see [LICENSE.txt](LICENSE.txt). | |
| 145 145 | 
             
            Alternative Download
         | 
| 146 146 | 
             
            --------------------
         | 
| 147 147 |  | 
| 148 | 
            -
            Alternatively to the gem-files you can download the latest release as [a tarball](https://schleuder.org/download/schleuder-3. | 
| 148 | 
            +
            Alternatively to the gem-files you can download the latest release as [a tarball](https://schleuder.org/download/schleuder-3.5.0.tar.gz) and [its OpenPGP-signature](https://schleuder.org/download/schleuder-3.5.0.tar.gz.sig).
         | 
    
        data/Rakefile
    CHANGED
    
    | @@ -110,7 +110,7 @@ end | |
| 110 110 | 
             
            desc 'Publish gem-file to rubygems.org'
         | 
| 111 111 | 
             
            task :publish_gem do
         | 
| 112 112 | 
             
              puts "Really push #{@filename_gem} to rubygems.org? [yN]"
         | 
| 113 | 
            -
              if gets.match(/^y/i)
         | 
| 113 | 
            +
              if $stdin.gets.match(/^y/i)
         | 
| 114 114 | 
             
                puts "Pushing..."
         | 
| 115 115 | 
             
                `gem push #{@filename_gem}`
         | 
| 116 116 | 
             
              else
         | 
| @@ -132,7 +132,7 @@ desc 'Check if version-tag already exists' | |
| 132 132 | 
             
            task :check_version do
         | 
| 133 133 | 
             
              # Check if Schleuder::VERSION has been updated since last release
         | 
| 134 134 | 
             
              if `git tag`.match?(/^#{@tagname}$/)
         | 
| 135 | 
            -
                $stderr.puts "Warning: Tag '#{@tagname}' already exists. Did you forget to update  | 
| 135 | 
            +
                $stderr.puts "Warning: Tag '#{@tagname}' already exists. Did you forget to update lib/#{project}/version.rb?"
         | 
| 136 136 | 
             
                $stderr.print "Delete tag to continue? [yN] "
         | 
| 137 137 | 
             
                if $stdin.gets.match(/^y/i)
         | 
| 138 138 | 
             
                  `git tag -d #{@tagname}`
         | 
| @@ -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
         | 
    
        data/db/schema.rb
    CHANGED
    
    | @@ -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:  | 
| 14 | 
            +
            ActiveRecord::Schema.define(version: 20190906194820) do
         | 
| 15 15 |  | 
| 16 16 | 
             
              create_table "lists", force: :cascade do |t|
         | 
| 17 17 | 
             
                t.datetime "created_at"
         | 
| @@ -37,6 +37,7 @@ ActiveRecord::Schema.define(version: 20180110203100) 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: 20180110203100) 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|
         | 
    
        data/etc/list-defaults.yml
    CHANGED
    
    | @@ -93,6 +93,9 @@ bounces_drop_on_headers: | |
| 93 93 | 
             
            # Send a notice to the list-admins whenever an email is bounced or dropped?
         | 
| 94 94 | 
             
            bounces_notify_admins: true
         | 
| 95 95 |  | 
| 96 | 
            +
            # Include Autocrypt header into emails?
         | 
| 97 | 
            +
            include_autocrypt_header: true
         | 
| 98 | 
            +
             | 
| 96 99 | 
             
            # Include RFC-compliant List-* Headers into emails?
         | 
| 97 100 | 
             
            include_list_headers: true
         | 
| 98 101 |  | 
| @@ -123,3 +126,8 @@ language: en | |
| 123 126 | 
             
            # Forward a raw copy of all incoming emails to the list-admins?
         | 
| 124 127 | 
             
            # Mainly useful for debugging.
         | 
| 125 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
         | 
    
        data/lib/schleuder.rb
    CHANGED
    
    | @@ -1,3 +1,10 @@ | |
| 1 | 
            +
            # default to ASCII-8BIT encoding as early as possible for external
         | 
| 2 | 
            +
            # data.
         | 
| 3 | 
            +
            #
         | 
| 4 | 
            +
            # this should ensure we are able to parse most incoming
         | 
| 5 | 
            +
            # plain text mails in different charsets.
         | 
| 6 | 
            +
            Encoding.default_external = Encoding::UTF_8
         | 
| 7 | 
            +
             | 
| 1 8 | 
             
            # Stdlib
         | 
| 2 9 | 
             
            require 'fileutils'
         | 
| 3 10 | 
             
            require 'singleton'
         | 
| @@ -61,6 +68,9 @@ ENV["SCHLEUDER_CONFIG"] ||= '/etc/schleuder/schleuder.yml' | |
| 61 68 | 
             
            ENV["SCHLEUDER_LIST_DEFAULTS"] ||= '/etc/schleuder/list-defaults.yml'
         | 
| 62 69 | 
             
            ENV["SCHLEUDER_ENV"] ||= 'production'
         | 
| 63 70 | 
             
            ENV["SCHLEUDER_ROOT"] = rootdir.to_s
         | 
| 71 | 
            +
            # Ensure that gnupg never-ever tries to ask for a passphrase.
         | 
| 72 | 
            +
            ENV["GPG_TTY"] = "/nonexistant-#{rand}"
         | 
| 73 | 
            +
            ENV["DISPLAY"] = nil
         | 
| 64 74 |  | 
| 65 75 | 
             
            GPGME::Ctx.set_gpg_path_from_env
         | 
| 66 76 | 
             
            GPGME::Ctx.check_gpg_version
         | 
    
        data/lib/schleuder/cli.rb
    CHANGED
    
    
    
        data/lib/schleuder/gpgme/key.rb
    CHANGED
    
    | @@ -57,6 +57,10 @@ module GPGME | |
| 57 57 | 
             
                  "#{self.to_s}\n\n#{export(armor: true).read}"
         | 
| 58 58 | 
             
                end
         | 
| 59 59 |  | 
| 60 | 
            +
                def minimal
         | 
| 61 | 
            +
                  export(minimal: true).to_s
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
             | 
| 60 64 | 
             
                # Force encoding, some databases save "ASCII-8BIT" as binary data.
         | 
| 61 65 | 
             
                alias_method :orig_fingerprint, :fingerprint
         | 
| 62 66 | 
             
                def fingerprint
         | 
    
        data/lib/schleuder/list.rb
    CHANGED
    
    | @@ -19,6 +19,7 @@ module Schleuder | |
| 19 19 | 
             
                    :receive_admin_only,
         | 
| 20 20 | 
             
                    :keep_msgid,
         | 
| 21 21 | 
             
                    :bounces_drop_all,
         | 
| 22 | 
            +
                    :deliver_selfsent,
         | 
| 22 23 | 
             
                    :bounces_notify_admins,
         | 
| 23 24 | 
             
                    :include_list_headers,
         | 
| 24 25 | 
             
                    :include_openpgp_header,
         | 
| @@ -146,6 +147,16 @@ module Schleuder | |
| 146 147 | 
             
                  key.armored
         | 
| 147 148 | 
             
                end
         | 
| 148 149 |  | 
| 150 | 
            +
                def key_minimal_base64_encoded(fingerprint=self.fingerprint)
         | 
| 151 | 
            +
                  key = keys(fingerprint).first
         | 
| 152 | 
            +
                  
         | 
| 153 | 
            +
                  if key.blank?
         | 
| 154 | 
            +
                    return false
         | 
| 155 | 
            +
                  end
         | 
| 156 | 
            +
                  
         | 
| 157 | 
            +
                  Base64.strict_encode64(key.minimal)
         | 
| 158 | 
            +
                end
         | 
| 159 | 
            +
             | 
| 149 160 | 
             
                def check_keys
         | 
| 150 161 | 
             
                  now = Time.now
         | 
| 151 162 | 
             
                  checkdate = now + (60 * 60 * 24 * 14) # two weeks
         | 
| @@ -340,16 +351,24 @@ module Schleuder | |
| 340 351 | 
             
                  true
         | 
| 341 352 | 
             
                end
         | 
| 342 353 |  | 
| 343 | 
            -
                def send_to_subscriptions(mail)
         | 
| 354 | 
            +
                def send_to_subscriptions(mail, incoming_mail=nil)
         | 
| 344 355 | 
             
                  logger.debug "Sending to subscriptions."
         | 
| 345 356 | 
             
                  mail.add_internal_footer!
         | 
| 346 357 | 
             
                  self.subscriptions.each do |subscription|
         | 
| 347 358 | 
             
                    begin
         | 
| 348 | 
            -
                       | 
| 349 | 
            -
             | 
| 350 | 
            -
                      else
         | 
| 359 | 
            +
                      
         | 
| 360 | 
            +
                      if ! subscription.delivery_enabled
         | 
| 351 361 | 
             
                        logger.info "Not sending to #{subscription.email}: delivery is disabled."
         | 
| 362 | 
            +
                        next
         | 
| 363 | 
            +
                      end
         | 
| 364 | 
            +
                      
         | 
| 365 | 
            +
                      if ! self.deliver_selfsent && incoming_mail.was_validly_signed? && ( subscription == incoming_mail.signer )
         | 
| 366 | 
            +
                        logger.info "Not sending to #{subscription.email}: delivery of self sent is disabled."
         | 
| 367 | 
            +
                        next
         | 
| 352 368 | 
             
                      end
         | 
| 369 | 
            +
                      
         | 
| 370 | 
            +
                      subscription.send_mail(mail)
         | 
| 371 | 
            +
                      
         | 
| 353 372 | 
             
                    rescue => exc
         | 
| 354 373 | 
             
                      msg = I18n.t('errors.delivery_error',
         | 
| 355 374 | 
             
                                   { email: subscription.email, error: exc.to_s })
         | 
| @@ -17,6 +17,7 @@ module Mail | |
| 17 17 | 
             
                attr_accessor :original_message
         | 
| 18 18 | 
             
                attr_accessor :list
         | 
| 19 19 | 
             
                attr_accessor :protected_headers_subject
         | 
| 20 | 
            +
                attr_writer :dynamic_pseudoheaders
         | 
| 20 21 |  | 
| 21 22 | 
             
                # TODO: This should be in initialize(), but I couldn't understand the
         | 
| 22 23 | 
             
                # strange errors about wrong number of arguments when overriding
         | 
| @@ -44,9 +45,7 @@ module Mail | |
| 44 45 | 
             
                  # might be gone (e.g. request-keywords that delete subscriptions or
         | 
| 45 46 | 
             
                  # keys).
         | 
| 46 47 | 
             
                  new.signer
         | 
| 47 | 
            -
                  self.dynamic_pseudoheaders. | 
| 48 | 
            -
                    new.add_pseudoheader(str)
         | 
| 49 | 
            -
                  end
         | 
| 48 | 
            +
                  new.dynamic_pseudoheaders = self.dynamic_pseudoheaders.dup
         | 
| 50 49 |  | 
| 51 50 | 
             
                  # Store previously protected subject for later access.
         | 
| 52 51 | 
             
                  # mail-gpg pulls headers from the decrypted mime parts "up" into the main
         | 
| @@ -206,11 +205,15 @@ module Mail | |
| 206 205 | 
             
                  @recipient.match(/-bounce@/).present? ||
         | 
| 207 206 | 
             
                      # Empty Return-Path
         | 
| 208 207 | 
             
                      self.return_path.to_s == '<>' ||
         | 
| 209 | 
            -
                      # Auto-Submitted exists and does not equal 'no' and | 
| 210 | 
            -
                      #  | 
| 208 | 
            +
                      # Auto-Submitted exists and does not equal 'no' and:
         | 
| 209 | 
            +
                      #  - no cron header is present
         | 
| 210 | 
            +
                      #  - no Jenkins job notification header is present
         | 
| 211 | 
            +
                      # as these emails have the auto-submitted header.
         | 
| 211 212 | 
             
                      ( self['Auto-Submitted'].present? && \
         | 
| 212 213 | 
             
                        self['Auto-Submitted'].to_s.downcase != 'no' && \
         | 
| 213 | 
            -
                        !self['X-Cron-Env'].present? | 
| 214 | 
            +
                        !self['X-Cron-Env'].present? && \
         | 
| 215 | 
            +
                        !self['X-Jenkins-Job'].present? && \
         | 
| 216 | 
            +
                        self.subject.to_s !~ /\A\*\*\* SECURITY information.*\*\*\*\Z/)
         | 
| 214 217 | 
             
                end
         | 
| 215 218 |  | 
| 216 219 | 
             
                def keywords
         | 
| @@ -244,11 +247,11 @@ module Mail | |
| 244 247 | 
             
                  # decide itself how to encode, it works. If we don't, some
         | 
| 245 248 | 
             
                  # character-sequences are not properly re-encoded.
         | 
| 246 249 | 
             
                  part.content_transfer_encoding = nil
         | 
| 247 | 
            -
             | 
| 248 | 
            -
                  #  | 
| 249 | 
            -
                   | 
| 250 | 
            -
                   | 
| 251 | 
            -
                  part.body =  | 
| 250 | 
            +
             | 
| 251 | 
            +
                  # Set the right charset on the now parsed body
         | 
| 252 | 
            +
                  new_body = lines.compact.join
         | 
| 253 | 
            +
                  part.charset = new_body.encoding.to_s
         | 
| 254 | 
            +
                  part.body = new_body
         | 
| 252 255 |  | 
| 253 256 | 
             
                  @keywords
         | 
| 254 257 | 
             
                end
         | 
| @@ -266,20 +269,17 @@ module Mail | |
| 266 269 | 
             
                end
         | 
| 267 270 |  | 
| 268 271 | 
             
                def add_pseudoheader(string_or_key, value=nil)
         | 
| 269 | 
            -
                   | 
| 270 | 
            -
                  if value.present?
         | 
| 271 | 
            -
                    @dynamic_pseudoheaders << make_pseudoheader(string_or_key, value)
         | 
| 272 | 
            -
                  else
         | 
| 273 | 
            -
                    @dynamic_pseudoheaders << string_or_key.to_s
         | 
| 274 | 
            -
                  end
         | 
| 272 | 
            +
                  dynamic_pseudoheaders << make_pseudoheader(string_or_key, value)
         | 
| 275 273 | 
             
                end
         | 
| 276 274 |  | 
| 277 275 | 
             
                def make_pseudoheader(key, value)
         | 
| 278 | 
            -
                  "#{key.to_s.camelize}: #{value.to_s}"
         | 
| 276 | 
            +
                  output = "#{key.to_s.camelize}: #{value.to_s}"
         | 
| 277 | 
            +
                  # wrap lines after 76 with 2 indents
         | 
| 278 | 
            +
                  output.gsub(/(.{1,76})( +|$)\n?/, "  \\1\n").chomp.lstrip
         | 
| 279 279 | 
             
                end
         | 
| 280 280 |  | 
| 281 281 | 
             
                def dynamic_pseudoheaders
         | 
| 282 | 
            -
                  @dynamic_pseudoheaders  | 
| 282 | 
            +
                  @dynamic_pseudoheaders ||= []
         | 
| 283 283 | 
             
                end
         | 
| 284 284 |  | 
| 285 285 | 
             
                def signature_state
         | 
| @@ -330,7 +330,8 @@ module Mail | |
| 330 330 | 
             
                end
         | 
| 331 331 |  | 
| 332 332 | 
             
                def pseudoheaders(list)
         | 
| 333 | 
            -
                   | 
| 333 | 
            +
                  separator = '------------------------------------------------------------------------------'
         | 
| 334 | 
            +
                  (standard_pseudoheaders(list) + dynamic_pseudoheaders).flatten.join("\n") + "\n" + separator + "\n"
         | 
| 334 335 | 
             
                end
         | 
| 335 336 |  | 
| 336 337 | 
             
                def add_msgids(list, orig)
         | 
| @@ -345,6 +346,14 @@ module Mail | |
| 345 346 | 
             
                end
         | 
| 346 347 |  | 
| 347 348 | 
             
                def add_list_headers(list)
         | 
| 349 | 
            +
                  if list.include_autocrypt_header
         | 
| 350 | 
            +
                    # Inject whitespaces, to let Mail break the string at these points
         | 
| 351 | 
            +
                    # leading to correct wrapping.
         | 
| 352 | 
            +
                    keydata = list.key_minimal_base64_encoded.gsub(/(.{78})/, '\1 ')
         | 
| 353 | 
            +
                    
         | 
| 354 | 
            +
                    self['Autocrypt'] = "addr=#{list.email}; prefer-encrypt=mutual; keydata=#{keydata}"
         | 
| 355 | 
            +
                  end
         | 
| 356 | 
            +
             | 
| 348 357 | 
             
                  if list.include_list_headers
         | 
| 349 358 | 
             
                    self['List-Id'] = "<#{list.email.gsub('@', '.')}>"
         | 
| 350 359 | 
             
                    self['List-Owner'] = "<mailto:#{list.owner_address}> (Use list's public key)"
         | 
| @@ -1,16 +1,12 @@ | |
| 1 1 | 
             
            module Schleuder
         | 
| 2 2 | 
             
              module ListPlugins
         | 
| 3 3 | 
             
                def self.attach_listkey(arguments, list, mail)
         | 
| 4 | 
            -
                   | 
| 5 | 
            -
                   | 
| 6 | 
            -
                   | 
| 7 | 
            -
                   | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 10 | 
            -
                  })
         | 
| 11 | 
            -
                  mail.attachments[filename].content_type = 'application/pgp-keys'
         | 
| 12 | 
            -
                  mail.attachments[filename].content_description = "OpenPGP public key of #{list.email}"
         | 
| 13 | 
            -
                  mail.attachments[filename].content_disposition = "attachment; filename=#{filename}"
         | 
| 4 | 
            +
                  new_part = Mail::Part.new
         | 
| 5 | 
            +
                  new_part.body = list.export_key
         | 
| 6 | 
            +
                  new_part.content_type = 'application/pgp-keys'
         | 
| 7 | 
            +
                  new_part.content_description = "OpenPGP public key of #{list.email}"
         | 
| 8 | 
            +
                  new_part.content_disposition = "attachment; filename=#{list.fingerprint}.pgpkey"
         | 
| 9 | 
            +
                  mail.add_part new_part
         | 
| 14 10 | 
             
                  nil
         | 
| 15 11 | 
             
                end
         | 
| 16 12 | 
             
              end
         | 
| @@ -56,6 +56,9 @@ module Schleuder | |
| 56 56 |  | 
| 57 57 | 
             
                  # Only continue if all recipients are still here.
         | 
| 58 58 | 
             
                  if recip_map.size < arguments.size
         | 
| 59 | 
            +
                    recip_map.keys.each do |aborted_sender|
         | 
| 60 | 
            +
                      mail.add_pseudoheader(:error, I18n.t("plugins.resend.aborted", email: aborted_sender))
         | 
| 61 | 
            +
                    end
         | 
| 59 62 | 
             
                    return
         | 
| 60 63 | 
             
                  end
         | 
| 61 64 |  | 
| @@ -117,22 +120,22 @@ module Schleuder | |
| 117 120 | 
             
                  Array(recipients).inject({}) do |hash, email|
         | 
| 118 121 | 
             
                    keys = mail.list.keys(email)
         | 
| 119 122 | 
             
                    # Exclude unusable keys.
         | 
| 120 | 
            -
                    keys.select | 
| 121 | 
            -
                    case  | 
| 123 | 
            +
                    usable_keys = keys.select { |key| key.usable_for?(:encrypt) }
         | 
| 124 | 
            +
                    case usable_keys.size
         | 
| 122 125 | 
             
                    when 1
         | 
| 123 | 
            -
                      hash[email] =  | 
| 126 | 
            +
                      hash[email] = usable_keys.first
         | 
| 124 127 | 
             
                    when 0
         | 
| 125 128 | 
             
                      if encrypted_only
         | 
| 126 129 | 
             
                        # Don't add the email to the result to exclude it from the
         | 
| 127 130 | 
             
                        # recipients.
         | 
| 128 | 
            -
                         | 
| 131 | 
            +
                        add_resend_msg(mail, email, :error, 'not_resent_no_keys', usable_keys.size, keys.size)
         | 
| 129 132 | 
             
                      else
         | 
| 130 133 | 
             
                        hash[email] = ''
         | 
| 131 134 | 
             
                      end
         | 
| 132 135 | 
             
                    else
         | 
| 133 136 | 
             
                      # Always report this situation, regardless of sending or not. It's
         | 
| 134 137 | 
             
                      # bad and should be fixed.
         | 
| 135 | 
            -
                       | 
| 138 | 
            +
                      add_resend_msg(mail, email, :notice, 'not_resent_encrypted_no_keys', usable_keys.size, keys.size)
         | 
| 136 139 | 
             
                      if ! encrypted_only
         | 
| 137 140 | 
             
                        hash[email] = ''
         | 
| 138 141 | 
             
                      end
         | 
| @@ -152,8 +155,8 @@ module Schleuder | |
| 152 155 | 
             
                  gpg_opts
         | 
| 153 156 | 
             
                end
         | 
| 154 157 |  | 
| 155 | 
            -
                def self. | 
| 156 | 
            -
                  mail.add_pseudoheader( | 
| 158 | 
            +
                def self.add_resend_msg(mail, email, severity, msg, usable_keys_size, all_keys_size)
         | 
| 159 | 
            +
                  mail.add_pseudoheader(severity, I18n.t("plugins.resend.#{msg}", email: email, usable_keys: usable_keys_size, all_keys: all_keys_size))
         | 
| 157 160 | 
             
                end
         | 
| 158 161 |  | 
| 159 162 | 
             
                def self.add_error_header(mail, recipients_map)
         | 
| @@ -163,15 +166,15 @@ module Schleuder | |
| 163 166 | 
             
                def self.add_resent_headers(mail, recipients_map, to_or_cc, sent_encrypted)
         | 
| 164 167 | 
             
                  if sent_encrypted
         | 
| 165 168 | 
             
                    prefix = I18n.t('plugins.resend.encrypted_to')
         | 
| 166 | 
            -
                    str = recipients_map.map do |email, key|
         | 
| 169 | 
            +
                    str = "\n" + recipients_map.map do |email, key|
         | 
| 167 170 | 
             
                      "#{email} (#{key.fingerprint})"
         | 
| 168 | 
            -
                    end.join( | 
| 171 | 
            +
                    end.join(",\n")
         | 
| 169 172 | 
             
                  else
         | 
| 170 173 | 
             
                    prefix = I18n.t('plugins.resend.unencrypted_to')
         | 
| 171 | 
            -
                    str = recipients_map.keys.join( | 
| 174 | 
            +
                    str = ' ' + recipients_map.keys.join(", ")
         | 
| 172 175 | 
             
                  end
         | 
| 173 176 | 
             
                  headername = resent_header_name(to_or_cc)
         | 
| 174 | 
            -
                  mail.add_pseudoheader(headername, "#{prefix} | 
| 177 | 
            +
                  mail.add_pseudoheader(headername, "#{prefix}#{str}")
         | 
| 175 178 | 
             
                end
         | 
| 176 179 |  | 
| 177 180 | 
             
                def self.resent_header_name(to_or_cc)
         | 
    
        data/lib/schleuder/runner.rb
    CHANGED
    
    | @@ -5,15 +5,43 @@ module Schleuder | |
| 5 5 | 
             
                  return error if error
         | 
| 6 6 |  | 
| 7 7 | 
             
                  logger.info "Parsing incoming email."
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  # is it valid utf-8?
         | 
| 10 | 
            +
                  msg_scrubbed = false
         | 
| 11 | 
            +
                  unless msg.valid_encoding?
         | 
| 12 | 
            +
                    logger.warn "Converting message due to invalid characters"
         | 
| 13 | 
            +
                    detection = CharlockHolmes::EncodingDetector.detect(msg)
         | 
| 14 | 
            +
                    begin
         | 
| 15 | 
            +
                      msg = CharlockHolmes::Converter.convert(msg, detection[:encoding], 'UTF-8')
         | 
| 16 | 
            +
                    rescue ArgumentError
         | 
| 17 | 
            +
                      # it looks like even icu wasn't able to convert
         | 
| 18 | 
            +
                      # so we scrub the invalid characters to be able to
         | 
| 19 | 
            +
                      # at least parse the message somehow. Though this might
         | 
| 20 | 
            +
                      # result in data loss.
         | 
| 21 | 
            +
                      logger.warn "Scrubbing message due to invalid characters"
         | 
| 22 | 
            +
                      msg = msg.scrub
         | 
| 23 | 
            +
                      msg_scrubbed = true
         | 
| 24 | 
            +
                    end
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
             | 
| 8 27 | 
             
                  @mail = Mail.create_message_to_list(msg, recipient, list)
         | 
| 9 28 |  | 
| 29 | 
            +
                  if msg_scrubbed
         | 
| 30 | 
            +
                    @mail.add_pseudoheader(:note, I18n.t("pseudoheaders.scrubbed_message"))
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
             | 
| 10 33 | 
             
                  error = run_filters('pre')
         | 
| 11 34 | 
             
                  return error if error
         | 
| 12 35 |  | 
| 13 36 | 
             
                  begin
         | 
| 14 37 | 
             
                    # This decrypts, verifies, etc.
         | 
| 15 38 | 
             
                    @mail = @mail.setup
         | 
| 16 | 
            -
             | 
| 39 | 
            +
             | 
| 40 | 
            +
                  rescue GPGME::Error::BadPassphrase,
         | 
| 41 | 
            +
                         GPGME::Error::DecryptFailed,
         | 
| 42 | 
            +
                         GPGME::Error::NoData,
         | 
| 43 | 
            +
                         GPGME::Error::NoSecretKey
         | 
| 44 | 
            +
             | 
| 17 45 | 
             
                    logger.warn "Decryption of incoming message failed."
         | 
| 18 46 | 
             
                    return Errors::DecryptionFailed.new(list)
         | 
| 19 47 | 
             
                  end
         | 
| @@ -46,7 +74,7 @@ module Schleuder | |
| 46 74 | 
             
                  # Subscriptions
         | 
| 47 75 | 
             
                  logger.debug "Creating clean copy of message"
         | 
| 48 76 | 
             
                  copy = @mail.clean_copy(list.headers_to_meta.any?)
         | 
| 49 | 
            -
                  list.send_to_subscriptions(copy)
         | 
| 77 | 
            +
                  list.send_to_subscriptions(copy, @mail)
         | 
| 50 78 | 
             
                  nil
         | 
| 51 79 | 
             
                end
         | 
| 52 80 |  | 
    
        data/lib/schleuder/version.rb
    CHANGED
    
    
    
        data/locales/de.yml
    CHANGED
    
    | @@ -121,7 +121,9 @@ de: | |
| 121 121 | 
             
                    Oder, um einen Schlüssel per HTTP von einem Server zu laden:
         | 
| 122 122 | 
             
                    X-FETCH-KEY: https://example.org/keys/mykey.asc
         | 
| 123 123 | 
             
                resend:
         | 
| 124 | 
            -
                  not_resent_no_keys: Resending an <%{email}> fehlgeschlagen (%{ | 
| 124 | 
            +
                  not_resent_no_keys: Resending an <%{email}> fehlgeschlagen (%{all_keys} Schlüssel gefunden, davon %{usable_keys} nutzbar. Unverschlüsseltes Senden verboten).
         | 
| 125 | 
            +
                  not_resent_encrypted_no_keys: Verschlüsseltes Resending an <%{email}> fehlgeschlagen (%{all_keys} Schlüssel gefunden, davon %{usable_keys} nutzbar).
         | 
| 126 | 
            +
                  aborted: Resending an <%{email}> abgebrochen aufgrund anderer Probleme.
         | 
| 125 127 | 
             
                  encrypted_to: Verschlüsselt an
         | 
| 126 128 | 
             
                  unencrypted_to: Unverschlüsselt an
         | 
| 127 129 | 
             
                  invalid_recipient: "Ungültige Emailadresse für resend: %{address}"
         | 
| @@ -250,6 +252,7 @@ de: | |
| 250 252 | 
             
              fetch_key:
         | 
| 251 253 | 
             
                invalid_input: "Ungültige Angabe. Gültig sind: URLs, OpenPGP-Fingerabdrücke, oder Emailadressen."
         | 
| 252 254 | 
             
              pseudoheaders:
         | 
| 255 | 
            +
                scrubbed_message: Diese Email enthielt ungültige Zeichen, die aus Verarbeitungsgründen möglicherweise entfernt wurden.
         | 
| 253 256 | 
             
                stripped_html_from_multialt: Diese Email enthielt einen alternativen HTML-Teil, der PGP-Daten beinhaltete. Der HTML-Teil wurde entfernt, um die Email sauberer analysieren zu können.
         | 
| 254 257 | 
             
                stripped_html_from_multialt_with_keywords: Diese Email enthielt Schlüsselwörter und einen alternativen HTML-Teil. Der HTML-Teil wurde entfernt, um zu verhindern dass diese Schlüsselwörter Aussenstehenden bekannt werden.
         | 
| 255 258 | 
             
              signature_states:
         | 
    
        data/locales/en.yml
    CHANGED
    
    | @@ -125,7 +125,9 @@ en: | |
| 125 125 | 
             
                    Or, to fetch a key keys by URL:
         | 
| 126 126 | 
             
                    X-FETCH-KEY: https://example.org/keys/mykey.asc
         | 
| 127 127 | 
             
                resend:
         | 
| 128 | 
            -
                  not_resent_no_keys: Resending to <%{email}> failed (%{ | 
| 128 | 
            +
                  not_resent_no_keys: Resending to <%{email}> failed (%{all_keys} keys found, of which %{usable_keys} can be used. Unencrypted sending not allowed).
         | 
| 129 | 
            +
                  not_resent_encrypted_no_keys: Resending as encrypted email to <%{email}> failed (%{all_keys} keys found, of which %{usable_keys} can be used).
         | 
| 130 | 
            +
                  aborted: Resending to <%{email}> aborted due to other errors.
         | 
| 129 131 | 
             
                  encrypted_to: Encrypted to
         | 
| 130 132 | 
             
                  unencrypted_to: Unencrypted to
         | 
| 131 133 | 
             
                  invalid_recipient: "Invalid email-address for resending: %{address}"
         | 
| @@ -254,6 +256,7 @@ en: | |
| 254 256 | 
             
              fetch_key:
         | 
| 255 257 | 
             
                invalid_input: "Invalid input. Allowed are: URLs, OpenPGP-fingerprints, or email-addresses."
         | 
| 256 258 | 
             
              pseudoheaders:
         | 
| 259 | 
            +
                scrubbed_message: This message included invalid characters, which might have been removed to be able to process the message properly.
         | 
| 257 260 | 
             
                stripped_html_from_multialt: This message included an alternating HTML-part that contained PGP-data. The HTML-part was removed to enable parsing the message more properly.
         | 
| 258 261 | 
             
                stripped_html_from_multialt_with_keywords: This message included keywords and an alternating HTML-part. The HTML-part was removed to prevent the disclosure of these keywords to third parties.
         | 
| 259 262 | 
             
              signature_states:
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: schleuder
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 3. | 
| 4 | 
            +
              version: 3.5.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - schleuder dev team
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date:  | 
| 11 | 
            +
            date: 2020-03-30 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: gpgme
         | 
| @@ -19,7 +19,7 @@ dependencies: | |
| 19 19 | 
             
                    version: '2.0'
         | 
| 20 20 | 
             
                - - ">="
         | 
| 21 21 | 
             
                  - !ruby/object:Gem::Version
         | 
| 22 | 
            -
                    version: 2.0. | 
| 22 | 
            +
                    version: 2.0.19
         | 
| 23 23 | 
             
              type: :runtime
         | 
| 24 24 | 
             
              prerelease: false
         | 
| 25 25 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| @@ -29,7 +29,7 @@ dependencies: | |
| 29 29 | 
             
                    version: '2.0'
         | 
| 30 30 | 
             
                - - ">="
         | 
| 31 31 | 
             
                  - !ruby/object:Gem::Version
         | 
| 32 | 
            -
                    version: 2.0. | 
| 32 | 
            +
                    version: 2.0.19
         | 
| 33 33 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 34 34 | 
             
              name: mail
         | 
| 35 35 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -51,9 +51,9 @@ dependencies: | |
| 51 51 | 
             
                - - "~>"
         | 
| 52 52 | 
             
                  - !ruby/object:Gem::Version
         | 
| 53 53 | 
             
                    version: '0.3'
         | 
| 54 | 
            -
                - - " | 
| 54 | 
            +
                - - "<"
         | 
| 55 55 | 
             
                  - !ruby/object:Gem::Version
         | 
| 56 | 
            -
                    version: 0. | 
| 56 | 
            +
                    version: 0.4.3
         | 
| 57 57 | 
             
              type: :runtime
         | 
| 58 58 | 
             
              prerelease: false
         | 
| 59 59 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| @@ -61,9 +61,9 @@ dependencies: | |
| 61 61 | 
             
                - - "~>"
         | 
| 62 62 | 
             
                  - !ruby/object:Gem::Version
         | 
| 63 63 | 
             
                    version: '0.3'
         | 
| 64 | 
            -
                - - " | 
| 64 | 
            +
                - - "<"
         | 
| 65 65 | 
             
                  - !ruby/object:Gem::Version
         | 
| 66 | 
            -
                    version: 0. | 
| 66 | 
            +
                    version: 0.4.3
         | 
| 67 67 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 68 68 | 
             
              name: activerecord
         | 
| 69 69 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -176,6 +176,20 @@ dependencies: | |
| 176 176 | 
             
                - - "~>"
         | 
| 177 177 | 
             
                  - !ruby/object:Gem::Version
         | 
| 178 178 | 
             
                    version: '1'
         | 
| 179 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 180 | 
            +
              name: charlock_holmes
         | 
| 181 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 182 | 
            +
                requirements:
         | 
| 183 | 
            +
                - - "~>"
         | 
| 184 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 185 | 
            +
                    version: 0.7.6
         | 
| 186 | 
            +
              type: :runtime
         | 
| 187 | 
            +
              prerelease: false
         | 
| 188 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 189 | 
            +
                requirements:
         | 
| 190 | 
            +
                - - "~>"
         | 
| 191 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 192 | 
            +
                    version: 0.7.6
         | 
| 179 193 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 180 194 | 
             
              name: rspec
         | 
| 181 195 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -275,6 +289,8 @@ files: | |
| 275 289 | 
             
            - db/migrate/20160501172700_fix_headers_to_meta_defaults.rb
         | 
| 276 290 | 
             
            - db/migrate/20170713215059_add_internal_footer_to_list.rb
         | 
| 277 291 | 
             
            - db/migrate/20180110203100_add_sig_enc_to_headers_to_meta_defaults.rb
         | 
| 292 | 
            +
            - db/migrate/20180723173900_add_deliver_selfsent_to_list.rb
         | 
| 293 | 
            +
            - db/migrate/20190906194820_add_autocrypt_header_to_list.rb
         | 
| 278 294 | 
             
            - db/schema.rb
         | 
| 279 295 | 
             
            - etc/init.d/schleuder-api-daemon
         | 
| 280 296 | 
             
            - etc/list-defaults.yml
         | 
| @@ -391,7 +407,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 391 407 | 
             
                - !ruby/object:Gem::Version
         | 
| 392 408 | 
             
                  version: '0'
         | 
| 393 409 | 
             
            requirements: []
         | 
| 394 | 
            -
            rubyforge_project:  | 
| 410 | 
            +
            rubyforge_project: 
         | 
| 395 411 | 
             
            rubygems_version: 2.7.6.2
         | 
| 396 412 | 
             
            signing_key: 
         | 
| 397 413 | 
             
            specification_version: 4
         |