ably 0.6.2 → 0.7.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/.rspec +1 -0
 - data/.ruby-version.old +1 -0
 - data/.travis.yml +0 -2
 - data/Rakefile +22 -4
 - data/SPEC.md +1676 -0
 - data/ably.gemspec +1 -1
 - data/lib/ably.rb +0 -8
 - data/lib/ably/auth.rb +54 -46
 - data/lib/ably/exceptions.rb +19 -5
 - data/lib/ably/logger.rb +1 -1
 - data/lib/ably/models/error_info.rb +1 -1
 - data/lib/ably/models/idiomatic_ruby_wrapper.rb +11 -9
 - data/lib/ably/models/message.rb +15 -12
 - data/lib/ably/models/message_encoders/base.rb +6 -5
 - data/lib/ably/models/message_encoders/base64.rb +1 -0
 - data/lib/ably/models/message_encoders/cipher.rb +6 -3
 - data/lib/ably/models/message_encoders/json.rb +1 -0
 - data/lib/ably/models/message_encoders/utf8.rb +2 -9
 - data/lib/ably/models/nil_logger.rb +20 -0
 - data/lib/ably/models/paginated_resource.rb +5 -2
 - data/lib/ably/models/presence_message.rb +21 -12
 - data/lib/ably/models/protocol_message.rb +22 -6
 - data/lib/ably/modules/ably.rb +11 -0
 - data/lib/ably/modules/async_wrapper.rb +2 -0
 - data/lib/ably/modules/conversions.rb +23 -3
 - data/lib/ably/modules/encodeable.rb +2 -1
 - data/lib/ably/modules/enum.rb +2 -0
 - data/lib/ably/modules/event_emitter.rb +7 -1
 - data/lib/ably/modules/event_machine_helpers.rb +2 -0
 - data/lib/ably/modules/http_helpers.rb +2 -0
 - data/lib/ably/modules/model_common.rb +12 -2
 - data/lib/ably/modules/state_emitter.rb +76 -0
 - data/lib/ably/modules/state_machine.rb +53 -0
 - data/lib/ably/modules/statesman_monkey_patch.rb +33 -0
 - data/lib/ably/modules/uses_state_machine.rb +74 -0
 - data/lib/ably/realtime.rb +4 -2
 - data/lib/ably/realtime/channel.rb +51 -58
 - data/lib/ably/realtime/channel/channel_manager.rb +91 -0
 - data/lib/ably/realtime/channel/channel_state_machine.rb +68 -0
 - data/lib/ably/realtime/client.rb +70 -26
 - data/lib/ably/realtime/client/incoming_message_dispatcher.rb +31 -13
 - data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +1 -1
 - data/lib/ably/realtime/connection.rb +135 -92
 - data/lib/ably/realtime/connection/connection_manager.rb +216 -33
 - data/lib/ably/realtime/connection/connection_state_machine.rb +30 -73
 - data/lib/ably/realtime/models/nil_channel.rb +10 -1
 - data/lib/ably/realtime/presence.rb +336 -92
 - data/lib/ably/rest.rb +2 -2
 - data/lib/ably/rest/channel.rb +13 -4
 - data/lib/ably/rest/client.rb +138 -38
 - data/lib/ably/rest/middleware/logger.rb +24 -3
 - data/lib/ably/rest/presence.rb +12 -7
 - data/lib/ably/version.rb +1 -1
 - data/spec/acceptance/realtime/channel_history_spec.rb +101 -85
 - data/spec/acceptance/realtime/channel_spec.rb +461 -120
 - data/spec/acceptance/realtime/client_spec.rb +119 -0
 - data/spec/acceptance/realtime/connection_failures_spec.rb +499 -0
 - data/spec/acceptance/realtime/connection_spec.rb +571 -97
 - data/spec/acceptance/realtime/message_spec.rb +347 -333
 - data/spec/acceptance/realtime/presence_history_spec.rb +35 -40
 - data/spec/acceptance/realtime/presence_spec.rb +769 -239
 - data/spec/acceptance/realtime/stats_spec.rb +14 -22
 - data/spec/acceptance/realtime/time_spec.rb +16 -20
 - data/spec/acceptance/rest/auth_spec.rb +425 -364
 - data/spec/acceptance/rest/base_spec.rb +108 -176
 - data/spec/acceptance/rest/channel_spec.rb +89 -89
 - data/spec/acceptance/rest/channels_spec.rb +30 -32
 - data/spec/acceptance/rest/client_spec.rb +273 -0
 - data/spec/acceptance/rest/encoders_spec.rb +185 -0
 - data/spec/acceptance/rest/message_spec.rb +186 -163
 - data/spec/acceptance/rest/presence_spec.rb +150 -111
 - data/spec/acceptance/rest/stats_spec.rb +45 -40
 - data/spec/acceptance/rest/time_spec.rb +8 -10
 - data/spec/rspec_config.rb +10 -1
 - data/spec/shared/client_initializer_behaviour.rb +212 -0
 - data/spec/{support/model_helper.rb → shared/model_behaviour.rb} +6 -6
 - data/spec/{support/protocol_msgbus_helper.rb → shared/protocol_msgbus_behaviour.rb} +1 -1
 - data/spec/spec_helper.rb +9 -0
 - data/spec/support/api_helper.rb +11 -0
 - data/spec/support/event_machine_helper.rb +101 -3
 - data/spec/support/markdown_spec_formatter.rb +90 -0
 - data/spec/support/private_api_formatter.rb +36 -0
 - data/spec/support/protocol_helper.rb +32 -0
 - data/spec/support/random_helper.rb +15 -0
 - data/spec/support/test_app.rb +4 -0
 - data/spec/unit/auth_spec.rb +68 -0
 - data/spec/unit/logger_spec.rb +77 -66
 - data/spec/unit/models/error_info_spec.rb +1 -1
 - data/spec/unit/models/idiomatic_ruby_wrapper_spec.rb +2 -3
 - data/spec/unit/models/message_encoders/base64_spec.rb +2 -2
 - data/spec/unit/models/message_encoders/cipher_spec.rb +2 -2
 - data/spec/unit/models/message_encoders/utf8_spec.rb +2 -46
 - data/spec/unit/models/message_spec.rb +160 -15
 - data/spec/unit/models/paginated_resource_spec.rb +29 -27
 - data/spec/unit/models/presence_message_spec.rb +163 -20
 - data/spec/unit/models/protocol_message_spec.rb +43 -8
 - data/spec/unit/modules/async_wrapper_spec.rb +2 -3
 - data/spec/unit/modules/conversions_spec.rb +1 -1
 - data/spec/unit/modules/enum_spec.rb +2 -3
 - data/spec/unit/modules/event_emitter_spec.rb +62 -5
 - data/spec/unit/modules/state_emitter_spec.rb +283 -0
 - data/spec/unit/realtime/channel_spec.rb +107 -2
 - data/spec/unit/realtime/channels_spec.rb +1 -0
 - data/spec/unit/realtime/client_spec.rb +8 -48
 - data/spec/unit/realtime/connection_spec.rb +3 -3
 - data/spec/unit/realtime/incoming_message_dispatcher_spec.rb +2 -2
 - data/spec/unit/realtime/presence_spec.rb +13 -4
 - data/spec/unit/realtime/realtime_spec.rb +0 -11
 - data/spec/unit/realtime/websocket_transport_spec.rb +2 -2
 - data/spec/unit/rest/channel_spec.rb +109 -0
 - data/spec/unit/rest/channels_spec.rb +4 -3
 - data/spec/unit/rest/client_spec.rb +30 -125
 - data/spec/unit/rest/rest_spec.rb +10 -0
 - data/spec/unit/util/crypto_spec.rb +10 -5
 - data/spec/unit/util/pub_sub_spec.rb +5 -5
 - metadata +44 -12
 - data/spec/integration/modules/state_emitter_spec.rb +0 -80
 - data/spec/integration/rest/auth.rb +0 -9
 
    
        data/ably.gemspec
    CHANGED
    
    | 
         @@ -28,7 +28,7 @@ Gem::Specification.new do |spec| 
     | 
|
| 
       28 
28 
     | 
    
         
             
              spec.add_development_dependency 'bundler', '~> 1.3'
         
     | 
| 
       29 
29 
     | 
    
         
             
              spec.add_development_dependency 'rake'
         
     | 
| 
       30 
30 
     | 
    
         
             
              spec.add_development_dependency 'redcarpet'
         
     | 
| 
       31 
     | 
    
         
            -
              spec.add_development_dependency 'rspec', '~> 3.0'
         
     | 
| 
      
 31 
     | 
    
         
            +
              spec.add_development_dependency 'rspec', '~> 3.1.0' # version lock, see event_machine_helper.rb#patch_example_block_with_surrounding_eventmachine_reactor
         
     | 
| 
       32 
32 
     | 
    
         
             
              spec.add_development_dependency 'yard'
         
     | 
| 
       33 
33 
     | 
    
         
             
              spec.add_development_dependency 'webmock'
         
     | 
| 
       34 
34 
     | 
    
         
             
            end
         
     | 
    
        data/lib/ably.rb
    CHANGED
    
    | 
         @@ -10,11 +10,3 @@ require 'ably/logger' 
     | 
|
| 
       10 
10 
     | 
    
         
             
            require 'ably/realtime'
         
     | 
| 
       11 
11 
     | 
    
         
             
            require 'ably/rest'
         
     | 
| 
       12 
12 
     | 
    
         
             
            require 'ably/version'
         
     | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
       14 
     | 
    
         
            -
            # Ably is the base namespace for the Ably {Ably::Realtime Realtime} & {Ably::Rest Rest} client libraries.
         
     | 
| 
       15 
     | 
    
         
            -
            #
         
     | 
| 
       16 
     | 
    
         
            -
            # Please refer to the {file:README.md Readme} on getting started.
         
     | 
| 
       17 
     | 
    
         
            -
            #
         
     | 
| 
       18 
     | 
    
         
            -
            # @see file:README.md README
         
     | 
| 
       19 
     | 
    
         
            -
            module Ably
         
     | 
| 
       20 
     | 
    
         
            -
            end
         
     | 
    
        data/lib/ably/auth.rb
    CHANGED
    
    | 
         @@ -34,14 +34,15 @@ module Ably 
     | 
|
| 
       34 
34 
     | 
    
         
             
                # Creates an Auth object
         
     | 
| 
       35 
35 
     | 
    
         
             
                #
         
     | 
| 
       36 
36 
     | 
    
         
             
                # @param [Ably::Rest::Client] client  {Ably::Rest::Client} this Auth object uses
         
     | 
| 
       37 
     | 
    
         
            -
                # @param  
     | 
| 
       38 
     | 
    
         
            -
                # @ 
     | 
| 
       39 
     | 
    
         
            -
                 
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
      
 37 
     | 
    
         
            +
                # @param options (see Ably::Rest::Client#initialize)
         
     | 
| 
      
 38 
     | 
    
         
            +
                # @option (see Ably::Rest::Client#initialize)
         
     | 
| 
      
 39 
     | 
    
         
            +
                # @yield  (see Ably::Rest::Client#initialize)
         
     | 
| 
      
 40 
     | 
    
         
            +
                def initialize(client, options, &token_request_block)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  auth_options = options.dup
         
     | 
| 
       41 
42 
     | 
    
         | 
| 
       42 
     | 
    
         
            -
                  @client 
     | 
| 
       43 
     | 
    
         
            -
                  @options 
     | 
| 
       44 
     | 
    
         
            -
                  @ 
     | 
| 
      
 43 
     | 
    
         
            +
                  @client              = client
         
     | 
| 
      
 44 
     | 
    
         
            +
                  @options             = auth_options
         
     | 
| 
      
 45 
     | 
    
         
            +
                  @default_token_block = token_request_block if block_given?
         
     | 
| 
       45 
46 
     | 
    
         | 
| 
       46 
47 
     | 
    
         
             
                  unless auth_options.kind_of?(Hash)
         
     | 
| 
       47 
48 
     | 
    
         
             
                    raise ArgumentError, 'Expected auth_options to be a Hash'
         
     | 
| 
         @@ -54,16 +55,17 @@ module Ably 
     | 
|
| 
       54 
55 
     | 
    
         
             
                  if auth_options[:api_key]
         
     | 
| 
       55 
56 
     | 
    
         
             
                    api_key_parts = auth_options[:api_key].to_s.match(/(?<id>[\w_-]+\.[\w_-]+):(?<secret>[\w_-]+)/)
         
     | 
| 
       56 
57 
     | 
    
         
             
                    raise ArgumentError, 'api_key is invalid' unless api_key_parts
         
     | 
| 
       57 
     | 
    
         
            -
                    auth_options[:key_id] = api_key_parts[:id]
         
     | 
| 
       58 
     | 
    
         
            -
                    auth_options[:key_secret] = api_key_parts[:secret]
         
     | 
| 
      
 58 
     | 
    
         
            +
                    auth_options[:key_id] = api_key_parts[:id].encode(Encoding::UTF_8)
         
     | 
| 
      
 59 
     | 
    
         
            +
                    auth_options[:key_secret] = api_key_parts[:secret].encode(Encoding::UTF_8)
         
     | 
| 
       59 
60 
     | 
    
         
             
                  end
         
     | 
| 
       60 
61 
     | 
    
         | 
| 
       61 
62 
     | 
    
         
             
                  if using_basic_auth? && !api_key_present?
         
     | 
| 
       62 
63 
     | 
    
         
             
                    raise ArgumentError, 'api_key is missing. Either an API key, token, or token auth method must be provided'
         
     | 
| 
       63 
64 
     | 
    
         
             
                  end
         
     | 
| 
       64 
65 
     | 
    
         | 
| 
       65 
     | 
    
         
            -
                  if has_client_id? 
     | 
| 
       66 
     | 
    
         
            -
                    raise ArgumentError, 'client_id cannot be provided without a complete API key. Key ID & Secret is needed to authenticate with Ably and obtain a token'
         
     | 
| 
      
 66 
     | 
    
         
            +
                  if has_client_id?
         
     | 
| 
      
 67 
     | 
    
         
            +
                    raise ArgumentError, 'client_id cannot be provided without a complete API key. Key ID & Secret is needed to authenticate with Ably and obtain a token' unless api_key_present?
         
     | 
| 
      
 68 
     | 
    
         
            +
                    ensure_utf_8 :client_id, client_id
         
     | 
| 
       67 
69 
     | 
    
         
             
                  end
         
     | 
| 
       68 
70 
     | 
    
         | 
| 
       69 
71 
     | 
    
         
             
                  @options.freeze
         
     | 
| 
         @@ -74,25 +76,14 @@ module Ably 
     | 
|
| 
       74 
76 
     | 
    
         
             
                # In the event that a new token request is made, the specified options are used.
         
     | 
| 
       75 
77 
     | 
    
         
             
                #
         
     | 
| 
       76 
78 
     | 
    
         
             
                # @param [Hash] options the options for the token request
         
     | 
| 
       77 
     | 
    
         
            -
                # @option options  
     | 
| 
       78 
     | 
    
         
            -
                # @option options [ 
     | 
| 
       79 
     | 
    
         
            -
                # @option options [String]  :client_id    client ID identifying this connection to other clients (defaults to client client_id if configured)
         
     | 
| 
       80 
     | 
    
         
            -
                # @option options [String]  :auth_url     a URL to be used to GET or POST a set of token request params, to obtain a signed token request.
         
     | 
| 
       81 
     | 
    
         
            -
                # @option options [Hash]    :auth_headers a set of application-specific headers to be added to any request made to the authUrl
         
     | 
| 
       82 
     | 
    
         
            -
                # @option options [Hash]    :auth_params  a set of application-specific query params to be added to any request made to the authUrl
         
     | 
| 
       83 
     | 
    
         
            -
                # @option options [Symbol]  :auth_method  HTTP method to use with auth_url, must be either `:get` or `:post` (defaults to :get)
         
     | 
| 
       84 
     | 
    
         
            -
                # @option options [Integer] :ttl          validity time in seconds for the requested {Ably::Models::Token}.  Limits may apply, see {http://docs.ably.io/other/authentication/}
         
     | 
| 
       85 
     | 
    
         
            -
                # @option options [Hash]    :capability   canonicalised representation of the resource paths and associated operations
         
     | 
| 
       86 
     | 
    
         
            -
                # @option options [Boolean] :query_time   when true will query the {https://ably.io Ably} system for the current time instead of using the local time
         
     | 
| 
       87 
     | 
    
         
            -
                # @option options [Time]    :timestamp    the time of the of the request
         
     | 
| 
       88 
     | 
    
         
            -
                # @option options [String]  :nonce        an unquoted, unescaped random string of at least 16 characters
         
     | 
| 
       89 
     | 
    
         
            -
                # @option options [Boolean] :force        obtains a new token even if the current token is valid
         
     | 
| 
      
 79 
     | 
    
         
            +
                # @option options (see #request_token)
         
     | 
| 
      
 80 
     | 
    
         
            +
                # @option options [Boolean] :force   obtains a new token even if the current token is valid
         
     | 
| 
       90 
81 
     | 
    
         
             
                #
         
     | 
| 
       91 
     | 
    
         
            -
                # @yield  
     | 
| 
       92 
     | 
    
         
            -
                # @yieldparam [Hash] options options passed to  
     | 
| 
       93 
     | 
    
         
            -
                # @yieldreturn  
     | 
| 
      
 82 
     | 
    
         
            +
                # @yield (see #request_token)
         
     | 
| 
      
 83 
     | 
    
         
            +
                # @yieldparam [Hash] options options passed to {#authorise} will be in turn sent to the block in this argument
         
     | 
| 
      
 84 
     | 
    
         
            +
                # @yieldreturn (see #request_token)
         
     | 
| 
       94 
85 
     | 
    
         
             
                #
         
     | 
| 
       95 
     | 
    
         
            -
                # @return  
     | 
| 
      
 86 
     | 
    
         
            +
                # @return (see #request_token)
         
     | 
| 
       96 
87 
     | 
    
         
             
                #
         
     | 
| 
       97 
88 
     | 
    
         
             
                # @example
         
     | 
| 
       98 
89 
     | 
    
         
             
                #    # will issue a simple token request using basic auth
         
     | 
| 
         @@ -105,12 +96,15 @@ module Ably 
     | 
|
| 
       105 
96 
     | 
    
         
             
                #      token_request
         
     | 
| 
       106 
97 
     | 
    
         
             
                #    end
         
     | 
| 
       107 
98 
     | 
    
         
             
                #
         
     | 
| 
       108 
     | 
    
         
            -
                def authorise(options = {}, & 
     | 
| 
      
 99 
     | 
    
         
            +
                def authorise(options = {}, &token_request_block)
         
     | 
| 
       109 
100 
     | 
    
         
             
                  if !options[:force] && current_token
         
     | 
| 
       110 
101 
     | 
    
         
             
                    return current_token unless current_token.expired?
         
     | 
| 
       111 
102 
     | 
    
         
             
                  end
         
     | 
| 
       112 
103 
     | 
    
         | 
| 
       113 
     | 
    
         
            -
                  @ 
     | 
| 
      
 104 
     | 
    
         
            +
                  @options             = @options.merge(options)
         
     | 
| 
      
 105 
     | 
    
         
            +
                  @default_token_block = token_request_block if block_given?
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                  @current_token = request_token(options, &token_request_block)
         
     | 
| 
       114 
108 
     | 
    
         
             
                end
         
     | 
| 
       115 
109 
     | 
    
         | 
| 
       116 
110 
     | 
    
         
             
                # Request a {Ably::Models::Token} which can be used to make authenticated token based requests
         
     | 
| 
         @@ -129,9 +123,9 @@ module Ably 
     | 
|
| 
       129 
123 
     | 
    
         
             
                # @option options [Time]    :timestamp    the time of the of the request
         
     | 
| 
       130 
124 
     | 
    
         
             
                # @option options [String]  :nonce        an unquoted, unescaped random string of at least 16 characters
         
     | 
| 
       131 
125 
     | 
    
         
             
                #
         
     | 
| 
       132 
     | 
    
         
            -
                # @yield [options] (optional) if  
     | 
| 
       133 
     | 
    
         
            -
                # @yieldparam [Hash] options options passed to request_token will be in turn sent to the block in this argument
         
     | 
| 
       134 
     | 
    
         
            -
                # @yieldreturn [Hash] valid token request object, see { 
     | 
| 
      
 126 
     | 
    
         
            +
                # @yield [options] (optional) if a token request block is passed to this method, then this block will be called whenever a new token is required
         
     | 
| 
      
 127 
     | 
    
         
            +
                # @yieldparam [Hash] options options passed to {#request_token} will be in turn sent to the block in this argument
         
     | 
| 
      
 128 
     | 
    
         
            +
                # @yieldreturn [Hash] expects a valid token request object, see {#create_token_request}
         
     | 
| 
       135 
129 
     | 
    
         
             
                #
         
     | 
| 
       136 
130 
     | 
    
         
             
                # @return [Ably::Models::Token]
         
     | 
| 
       137 
131 
     | 
    
         
             
                #
         
     | 
| 
         @@ -146,14 +140,14 @@ module Ably 
     | 
|
| 
       146 
140 
     | 
    
         
             
                #      token_request
         
     | 
| 
       147 
141 
     | 
    
         
             
                #    end
         
     | 
| 
       148 
142 
     | 
    
         
             
                #
         
     | 
| 
       149 
     | 
    
         
            -
                def request_token(options = {}, & 
     | 
| 
      
 143 
     | 
    
         
            +
                def request_token(options = {}, &token_request_block)
         
     | 
| 
       150 
144 
     | 
    
         
             
                  token_options = self.auth_options.merge(options)
         
     | 
| 
       151 
145 
     | 
    
         | 
| 
       152 
146 
     | 
    
         
             
                  auth_url = token_options.delete(:auth_url)
         
     | 
| 
       153 
147 
     | 
    
         
             
                  token_request = if block_given?
         
     | 
| 
       154 
     | 
    
         
            -
                     
     | 
| 
       155 
     | 
    
         
            -
                  elsif  
     | 
| 
       156 
     | 
    
         
            -
                     
     | 
| 
      
 148 
     | 
    
         
            +
                    token_request_block.call(token_options)
         
     | 
| 
      
 149 
     | 
    
         
            +
                  elsif default_token_block
         
     | 
| 
      
 150 
     | 
    
         
            +
                    default_token_block.call(token_options)
         
     | 
| 
       157 
151 
     | 
    
         
             
                  elsif auth_url
         
     | 
| 
       158 
152 
     | 
    
         
             
                    token_request_from_auth_url(auth_url, token_options)
         
     | 
| 
       159 
153 
     | 
    
         
             
                  else
         
     | 
| 
         @@ -162,7 +156,7 @@ module Ably 
     | 
|
| 
       162 
156 
     | 
    
         | 
| 
       163 
157 
     | 
    
         
             
                  token_request = IdiomaticRubyWrapper(token_request)
         
     | 
| 
       164 
158 
     | 
    
         | 
| 
       165 
     | 
    
         
            -
                  response = client.post("/keys/#{token_request.fetch(:id)}/requestToken", token_request.hash, send_auth_header: false)
         
     | 
| 
      
 159 
     | 
    
         
            +
                  response = client.post("/keys/#{token_request.fetch(:id)}/requestToken", token_request.hash, send_auth_header: false, disable_automatic_reauthorise: true)
         
     | 
| 
       166 
160 
     | 
    
         
             
                  body = IdiomaticRubyWrapper(response.body)
         
     | 
| 
       167 
161 
     | 
    
         | 
| 
       168 
162 
     | 
    
         
             
                  Ably::Models::Token.new(body.fetch(:access_token))
         
     | 
| 
         @@ -220,8 +214,9 @@ module Ably 
     | 
|
| 
       220 
214 
     | 
    
         
             
                    token_request[:capability] = token_request[:capability].to_json
         
     | 
| 
       221 
215 
     | 
    
         
             
                  end
         
     | 
| 
       222 
216 
     | 
    
         | 
| 
       223 
     | 
    
         
            -
                  token_request[: 
     | 
| 
      
 217 
     | 
    
         
            +
                  ensure_utf_8 :nonce, token_request[:nonce], allow_nil: true
         
     | 
| 
       224 
218 
     | 
    
         | 
| 
      
 219 
     | 
    
         
            +
                  token_request[:mac] = sign_params(token_request, request_key_secret)
         
     | 
| 
       225 
220 
     | 
    
         
             
                  token_request
         
     | 
| 
       226 
221 
     | 
    
         
             
                end
         
     | 
| 
       227 
222 
     | 
    
         | 
| 
         @@ -244,6 +239,7 @@ module Ably 
     | 
|
| 
       244 
239 
     | 
    
         | 
| 
       245 
240 
     | 
    
         
             
                # True when Token Auth is being used to authenticate with Ably
         
     | 
| 
       246 
241 
     | 
    
         
             
                def using_token_auth?
         
     | 
| 
      
 242 
     | 
    
         
            +
                  return options[:use_token_auth] if options.has_key?(:use_token_auth)
         
     | 
| 
       247 
243 
     | 
    
         
             
                  token_id || current_token || has_client_id? || token_creatable_externally?
         
     | 
| 
       248 
244 
     | 
    
         
             
                end
         
     | 
| 
       249 
245 
     | 
    
         | 
| 
         @@ -280,26 +276,38 @@ module Ably 
     | 
|
| 
       280 
276 
     | 
    
         
             
                # True if prerequisites for creating a new token request are present
         
     | 
| 
       281 
277 
     | 
    
         
             
                #
         
     | 
| 
       282 
278 
     | 
    
         
             
                # One of the following criterion must be met:
         
     | 
| 
       283 
     | 
    
         
            -
                # * Valid key id and secret
         
     | 
| 
      
 279 
     | 
    
         
            +
                # * Valid key id and secret and token_id option not provided as token options cannot be determined
         
     | 
| 
       284 
280 
     | 
    
         
             
                # * Authentication callback for new token requests
         
     | 
| 
       285 
281 
     | 
    
         
             
                # * Authentication URL for new token requests
         
     | 
| 
       286 
282 
     | 
    
         
             
                #
         
     | 
| 
       287 
283 
     | 
    
         
             
                # @return [Boolean]
         
     | 
| 
       288 
284 
     | 
    
         
             
                def token_renewable?
         
     | 
| 
       289 
     | 
    
         
            -
                  token_creatable_externally? || api_key_present?
         
     | 
| 
      
 285 
     | 
    
         
            +
                  token_creatable_externally? || (api_key_present? && !token_id)
         
     | 
| 
      
 286 
     | 
    
         
            +
                end
         
     | 
| 
      
 287 
     | 
    
         
            +
             
     | 
| 
      
 288 
     | 
    
         
            +
                # Returns false when attempting to send an API Key over a non-secure connection
         
     | 
| 
      
 289 
     | 
    
         
            +
                # Token auth must be used for non-secure connections
         
     | 
| 
      
 290 
     | 
    
         
            +
                #
         
     | 
| 
      
 291 
     | 
    
         
            +
                # @return [Boolean]
         
     | 
| 
      
 292 
     | 
    
         
            +
                def authentication_security_requirements_met?
         
     | 
| 
      
 293 
     | 
    
         
            +
                  client.use_tls? || using_token_auth?
         
     | 
| 
       290 
294 
     | 
    
         
             
                end
         
     | 
| 
       291 
295 
     | 
    
         | 
| 
       292 
296 
     | 
    
         
             
                private
         
     | 
| 
       293 
     | 
    
         
            -
                attr_reader : 
     | 
| 
      
 297 
     | 
    
         
            +
                attr_reader :default_token_block
         
     | 
| 
      
 298 
     | 
    
         
            +
             
     | 
| 
      
 299 
     | 
    
         
            +
                def ensure_api_key_sent_over_secure_connection
         
     | 
| 
      
 300 
     | 
    
         
            +
                  raise Ably::Exceptions::InsecureRequestError, 'Cannot use Basic Auth over non-TLS connections' unless authentication_security_requirements_met?
         
     | 
| 
      
 301 
     | 
    
         
            +
                end
         
     | 
| 
       294 
302 
     | 
    
         | 
| 
       295 
303 
     | 
    
         
             
                # Basic Auth HTTP Authorization header value
         
     | 
| 
       296 
304 
     | 
    
         
             
                def basic_auth_header
         
     | 
| 
       297 
     | 
    
         
            -
                   
     | 
| 
      
 305 
     | 
    
         
            +
                  ensure_api_key_sent_over_secure_connection
         
     | 
| 
       298 
306 
     | 
    
         
             
                  "Basic #{encode64("#{api_key}")}"
         
     | 
| 
       299 
307 
     | 
    
         
             
                end
         
     | 
| 
       300 
308 
     | 
    
         | 
| 
       301 
309 
     | 
    
         
             
                def token_auth_id
         
     | 
| 
       302 
     | 
    
         
            -
                   
     | 
| 
      
 310 
     | 
    
         
            +
                  if token_id
         
     | 
| 
       303 
311 
     | 
    
         
             
                    token_id
         
     | 
| 
       304 
312 
     | 
    
         
             
                  else
         
     | 
| 
       305 
313 
     | 
    
         
             
                    authorise.id
         
     | 
| 
         @@ -313,7 +321,7 @@ module Ably 
     | 
|
| 
       313 
321 
     | 
    
         | 
| 
       314 
322 
     | 
    
         
             
                # Basic Auth params to authenticate the Realtime connection
         
     | 
| 
       315 
323 
     | 
    
         
             
                def basic_auth_params
         
     | 
| 
       316 
     | 
    
         
            -
                   
     | 
| 
      
 324 
     | 
    
         
            +
                  ensure_api_key_sent_over_secure_connection
         
     | 
| 
       317 
325 
     | 
    
         
             
                  # TODO: Change to key_secret when API is updated
         
     | 
| 
       318 
326 
     | 
    
         
             
                  {
         
     | 
| 
       319 
327 
     | 
    
         
             
                    key_id: key_id,
         
     | 
| 
         @@ -403,7 +411,7 @@ module Ably 
     | 
|
| 
       403 
411 
     | 
    
         
             
                end
         
     | 
| 
       404 
412 
     | 
    
         | 
| 
       405 
413 
     | 
    
         
             
                def token_callback_present?
         
     | 
| 
       406 
     | 
    
         
            -
                  !! 
     | 
| 
      
 414 
     | 
    
         
            +
                  !!default_token_block
         
     | 
| 
       407 
415 
     | 
    
         
             
                end
         
     | 
| 
       408 
416 
     | 
    
         | 
| 
       409 
417 
     | 
    
         
             
                def token_url_present?
         
     | 
    
        data/lib/ably/exceptions.rb
    CHANGED
    
    | 
         @@ -33,23 +33,37 @@ module Ably 
     | 
|
| 
       33 
33 
     | 
    
         
             
                # Encoding or decoding failure
         
     | 
| 
       34 
34 
     | 
    
         
             
                class EncoderError < BaseAblyException; end
         
     | 
| 
       35 
35 
     | 
    
         | 
| 
      
 36 
     | 
    
         
            +
                # Connection error from Realtime or REST service
         
     | 
| 
      
 37 
     | 
    
         
            +
                class ConnectionError < BaseAblyException
         
     | 
| 
      
 38 
     | 
    
         
            +
                  def initialize(message, status = nil, code = nil, base_error = nil)
         
     | 
| 
      
 39 
     | 
    
         
            +
                    super message, status, code
         
     | 
| 
      
 40 
     | 
    
         
            +
                    @base_error = base_error
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                # Connection Timeout accessing Realtime or REST service
         
     | 
| 
      
 45 
     | 
    
         
            +
                class ConnectionTimeoutError < ConnectionError; end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                # Invalid State Change error on a {https://github.com/gocardless/statesman Statesman State Machine}
         
     | 
| 
      
 48 
     | 
    
         
            +
                class StateChangeError < BaseAblyException; end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
       36 
50 
     | 
    
         
             
                # A generic Ably exception taht supports a status & code.
         
     | 
| 
       37 
51 
     | 
    
         
             
                # See https://github.com/ably/ably-common/blob/master/protocol/errors.json for a list of Ably errors
         
     | 
| 
       38 
52 
     | 
    
         
             
                class Standard < BaseAblyException; end
         
     | 
| 
       39 
53 
     | 
    
         | 
| 
       40 
54 
     | 
    
         
             
                # The HTTP request has returned a 500 error
         
     | 
| 
       41 
     | 
    
         
            -
                class ServerError <  
     | 
| 
      
 55 
     | 
    
         
            +
                class ServerError < BaseAblyException; end
         
     | 
| 
       42 
56 
     | 
    
         | 
| 
       43 
57 
     | 
    
         
             
                # PaginatedResource cannot retrieve the page
         
     | 
| 
       44 
     | 
    
         
            -
                class InvalidPageError <  
     | 
| 
      
 58 
     | 
    
         
            +
                class InvalidPageError < BaseAblyException; end
         
     | 
| 
       45 
59 
     | 
    
         | 
| 
       46 
60 
     | 
    
         
             
                # The expected response from the server was invalid
         
     | 
| 
       47 
     | 
    
         
            -
                class InvalidResponseBody <  
     | 
| 
      
 61 
     | 
    
         
            +
                class InvalidResponseBody < BaseAblyException; end
         
     | 
| 
       48 
62 
     | 
    
         | 
| 
       49 
63 
     | 
    
         
             
                # The request cannot be performed because it is insecure
         
     | 
| 
       50 
     | 
    
         
            -
                class InsecureRequestError <  
     | 
| 
      
 64 
     | 
    
         
            +
                class InsecureRequestError < BaseAblyException; end
         
     | 
| 
       51 
65 
     | 
    
         | 
| 
       52 
66 
     | 
    
         
             
                # The token request could not be created
         
     | 
| 
       53 
     | 
    
         
            -
                class TokenRequestError <  
     | 
| 
      
 67 
     | 
    
         
            +
                class TokenRequestError < BaseAblyException; end
         
     | 
| 
       54 
68 
     | 
    
         
             
              end
         
     | 
| 
       55 
69 
     | 
    
         
             
            end
         
     | 
    
        data/lib/ably/logger.rb
    CHANGED
    
    
| 
         @@ -19,7 +19,7 @@ module Ably::Models 
     | 
|
| 
       19 
19 
     | 
    
         
             
                  @hash_object     = IdiomaticRubyWrapper(hash_object.clone.freeze)
         
     | 
| 
       20 
20 
     | 
    
         
             
                end
         
     | 
| 
       21 
21 
     | 
    
         | 
| 
       22 
     | 
    
         
            -
                %w( 
     | 
| 
      
 22 
     | 
    
         
            +
                %w(message code status_code).each do |attribute|
         
     | 
| 
       23 
23 
     | 
    
         
             
                  define_method attribute do
         
     | 
| 
       24 
24 
     | 
    
         
             
                    hash[attribute.to_sym]
         
     | 
| 
       25 
25 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -50,7 +50,9 @@ module Ably::Models 
     | 
|
| 
       50 
50 
     | 
    
         
             
                # @attribute [Hash] mixedCaseHashObject mixed case Hash object
         
     | 
| 
       51 
51 
     | 
    
         
             
                # @attribute [Array<Symbol,String>] stop_at array of keys that this wrapper should stop wrapping at to preserve the underlying Hash as is
         
     | 
| 
       52 
52 
     | 
    
         
             
                #
         
     | 
| 
       53 
     | 
    
         
            -
                def initialize(mixedCaseHashObject,  
     | 
| 
      
 53 
     | 
    
         
            +
                def initialize(mixedCaseHashObject, options = {})
         
     | 
| 
      
 54 
     | 
    
         
            +
                  stop_at = options.fetch(:stop_at, [])
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
       54 
56 
     | 
    
         
             
                  if mixedCaseHashObject.kind_of?(IdiomaticRubyWrapper)
         
     | 
| 
       55 
57 
     | 
    
         
             
                    $stderr.puts "<IdiomaticRubyWrapper#initialize> WARNING: Wrapping a IdiomaticRubyWrapper with another IdiomaticRubyWrapper"
         
     | 
| 
       56 
58 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -203,14 +205,14 @@ module Ably::Models 
     | 
|
| 
       203 
205 
     | 
    
         
             
                # key is not found in mixedCase.
         
     | 
| 
       204 
206 
     | 
    
         
             
                def source_key_for(symbolized_key)
         
     | 
| 
       205 
207 
     | 
    
         
             
                  format_preferences = [
         
     | 
| 
       206 
     | 
    
         
            -
                     
     | 
| 
       207 
     | 
    
         
            -
                     
     | 
| 
       208 
     | 
    
         
            -
                     
     | 
| 
       209 
     | 
    
         
            -
                     
     | 
| 
       210 
     | 
    
         
            -
                     
     | 
| 
       211 
     | 
    
         
            -
                     
     | 
| 
       212 
     | 
    
         
            -
                     
     | 
| 
       213 
     | 
    
         
            -
                     
     | 
| 
      
 208 
     | 
    
         
            +
                    proc { |key_sym| convert_to_mixed_case(key_sym) },
         
     | 
| 
      
 209 
     | 
    
         
            +
                    proc { |key_sym| key_sym.to_sym },
         
     | 
| 
      
 210 
     | 
    
         
            +
                    proc { |key_sym| key_sym.to_s },
         
     | 
| 
      
 211 
     | 
    
         
            +
                    proc { |key_sym| convert_to_mixed_case(key_sym).to_sym },
         
     | 
| 
      
 212 
     | 
    
         
            +
                    proc { |key_sym| convert_to_lower_case(key_sym) },
         
     | 
| 
      
 213 
     | 
    
         
            +
                    proc { |key_sym| convert_to_lower_case(key_sym).to_sym },
         
     | 
| 
      
 214 
     | 
    
         
            +
                    proc { |key_sym| convert_to_mixed_case(key_sym, force_camel: true) },
         
     | 
| 
      
 215 
     | 
    
         
            +
                    proc { |key_sym| convert_to_mixed_case(key_sym, force_camel: true).to_sym }
         
     | 
| 
       214 
216 
     | 
    
         
             
                  ]
         
     | 
| 
       215 
217 
     | 
    
         | 
| 
       216 
218 
     | 
    
         
             
                  preferred_format = format_preferences.detect do |format|
         
     | 
    
        data/lib/ably/models/message.rb
    CHANGED
    
    | 
         @@ -32,12 +32,15 @@ module Ably::Models 
     | 
|
| 
       32 
32 
     | 
    
         
             
              #   @return [Time] Timestamp when the message was received by the Ably the real-time service
         
     | 
| 
       33 
33 
     | 
    
         
             
              # @!attribute [r] id
         
     | 
| 
       34 
34 
     | 
    
         
             
              #   @return [String] A globally unique message ID
         
     | 
| 
      
 35 
     | 
    
         
            +
              # @!attribute [r] connection_id
         
     | 
| 
      
 36 
     | 
    
         
            +
              #   @return [String] The connection_id of the publisher of the message
         
     | 
| 
       35 
37 
     | 
    
         
             
              # @!attribute [r] hash
         
     | 
| 
       36 
38 
     | 
    
         
             
              #   @return [Hash] Access the protocol message Hash object ruby'fied to use symbolized keys
         
     | 
| 
       37 
39 
     | 
    
         
             
              #
         
     | 
| 
       38 
40 
     | 
    
         
             
              class Message
         
     | 
| 
       39 
     | 
    
         
            -
                include Ably::Modules:: 
     | 
| 
      
 41 
     | 
    
         
            +
                include Ably::Modules::Conversions
         
     | 
| 
       40 
42 
     | 
    
         
             
                include Ably::Modules::Encodeable
         
     | 
| 
      
 43 
     | 
    
         
            +
                include Ably::Modules::ModelCommon
         
     | 
| 
       41 
44 
     | 
    
         
             
                include EventMachine::Deferrable
         
     | 
| 
       42 
45 
     | 
    
         | 
| 
       43 
46 
     | 
    
         
             
                # {Message} initializer
         
     | 
| 
         @@ -50,9 +53,13 @@ module Ably::Models 
     | 
|
| 
       50 
53 
     | 
    
         
             
                  @raw_hash_object  = hash_object
         
     | 
| 
       51 
54 
     | 
    
         | 
| 
       52 
55 
     | 
    
         
             
                  set_hash_object hash_object
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  ensure_utf_8 :name,      name,      allow_nil: true
         
     | 
| 
      
 58 
     | 
    
         
            +
                  ensure_utf_8 :client_id, client_id, allow_nil: true
         
     | 
| 
      
 59 
     | 
    
         
            +
                  ensure_utf_8 :encoding,  encoding,  allow_nil: true
         
     | 
| 
       53 
60 
     | 
    
         
             
                end
         
     | 
| 
       54 
61 
     | 
    
         | 
| 
       55 
     | 
    
         
            -
                %w( name client_id encoding ).each do |attribute|
         
     | 
| 
      
 62 
     | 
    
         
            +
                %w( name client_id encoding connection_id ).each do |attribute|
         
     | 
| 
       56 
63 
     | 
    
         
             
                  define_method attribute do
         
     | 
| 
       57 
64 
     | 
    
         
             
                    hash[attribute.to_sym]
         
     | 
| 
       58 
65 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -63,7 +70,11 @@ module Ably::Models 
     | 
|
| 
       63 
70 
     | 
    
         
             
                end
         
     | 
| 
       64 
71 
     | 
    
         | 
| 
       65 
72 
     | 
    
         
             
                def id
         
     | 
| 
       66 
     | 
    
         
            -
                  hash 
     | 
| 
      
 73 
     | 
    
         
            +
                  hash.fetch(:id) { "#{protocol_message.id!}:#{protocol_message_index}" }
         
     | 
| 
      
 74 
     | 
    
         
            +
                end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                def connection_id
         
     | 
| 
      
 77 
     | 
    
         
            +
                  hash.fetch(:connection_id) { protocol_message.connection_id if assigned_to_protocol_message? }
         
     | 
| 
       67 
78 
     | 
    
         
             
                end
         
     | 
| 
       68 
79 
     | 
    
         | 
| 
       69 
80 
     | 
    
         
             
                def timestamp
         
     | 
| 
         @@ -111,15 +122,7 @@ module Ably::Models 
     | 
|
| 
       111 
122 
     | 
    
         
             
                attr_reader :raw_hash_object
         
     | 
| 
       112 
123 
     | 
    
         | 
| 
       113 
124 
     | 
    
         
             
                def protocol_message_index
         
     | 
| 
       114 
     | 
    
         
            -
                  protocol_message.messages.index(self)
         
     | 
| 
       115 
     | 
    
         
            -
                end
         
     | 
| 
       116 
     | 
    
         
            -
             
     | 
| 
       117 
     | 
    
         
            -
                def connection_id
         
     | 
| 
       118 
     | 
    
         
            -
                  protocol_message.connection_id
         
     | 
| 
       119 
     | 
    
         
            -
                end
         
     | 
| 
       120 
     | 
    
         
            -
             
     | 
| 
       121 
     | 
    
         
            -
                def message_serial
         
     | 
| 
       122 
     | 
    
         
            -
                  protocol_message.message_serial
         
     | 
| 
      
 125 
     | 
    
         
            +
                  protocol_message.messages.map(&:object_id).index(self.object_id)
         
     | 
| 
       123 
126 
     | 
    
         
             
                end
         
     | 
| 
       124 
127 
     | 
    
         | 
| 
       125 
128 
     | 
    
         
             
                def set_hash_object(hash)
         
     | 
| 
         @@ -1,3 +1,5 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'ably/modules/conversions'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            # MessageEncoders are registered with the Ably client library and are responsible
         
     | 
| 
       2 
4 
     | 
    
         
             
            # for encoding & decoding messages.
         
     | 
| 
       3 
5 
     | 
    
         
             
            #
         
     | 
| 
         @@ -93,11 +95,6 @@ module Ably::Models::MessageEncoders 
     | 
|
| 
       93 
95 
     | 
    
         
             
              end
         
     | 
| 
       94 
96 
     | 
    
         | 
| 
       95 
97 
     | 
    
         
             
              def self.register_default_encoders(client)
         
     | 
| 
       96 
     | 
    
         
            -
                Dir.glob(File.expand_path("*.rb", File.dirname(__FILE__))).each do |file|
         
     | 
| 
       97 
     | 
    
         
            -
                  next if __FILE__ == file
         
     | 
| 
       98 
     | 
    
         
            -
                  require file
         
     | 
| 
       99 
     | 
    
         
            -
                end
         
     | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
       101 
98 
     | 
    
         
             
                client.register_encoder Ably::Models::MessageEncoders::Utf8
         
     | 
| 
       102 
99 
     | 
    
         
             
                client.register_encoder Ably::Models::MessageEncoders::Json
         
     | 
| 
       103 
100 
     | 
    
         
             
                client.register_encoder Ably::Models::MessageEncoders::Cipher
         
     | 
| 
         @@ -105,3 +102,7 @@ module Ably::Models::MessageEncoders 
     | 
|
| 
       105 
102 
     | 
    
         
             
              end
         
     | 
| 
       106 
103 
     | 
    
         
             
            end
         
     | 
| 
       107 
104 
     | 
    
         | 
| 
      
 105 
     | 
    
         
            +
            require 'ably/models/message_encoders/base64'
         
     | 
| 
      
 106 
     | 
    
         
            +
            require 'ably/models/message_encoders/cipher'
         
     | 
| 
      
 107 
     | 
    
         
            +
            require 'ably/models/message_encoders/json'
         
     | 
| 
      
 108 
     | 
    
         
            +
            require 'ably/models/message_encoders/utf8'
         
     | 
| 
         @@ -1,3 +1,7 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'ably/exceptions'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'ably/models/message_encoders/base'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'ably/util/crypto'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
       1 
5 
     | 
    
         
             
            module Ably::Models::MessageEncoders
         
     | 
| 
       2 
6 
     | 
    
         
             
              # Cipher Encoder & Decoder that automatically encrypts & decrypts messages using Ably::Util::Crypto
         
     | 
| 
       3 
7 
     | 
    
         
             
              # when a channel has option encrypted: true.
         
     | 
| 
         @@ -41,7 +45,6 @@ module Ably::Models::MessageEncoders 
     | 
|
| 
       41 
45 
     | 
    
         
             
                    end
         
     | 
| 
       42 
46 
     | 
    
         | 
| 
       43 
47 
     | 
    
         
             
                    message[:data] = crypto.decrypt(message[:data])
         
     | 
| 
       44 
     | 
    
         
            -
                    message[:data].force_encoding(Encoding::ASCII_8BIT) if is_binary?(message)
         
     | 
| 
       45 
48 
     | 
    
         
             
                    strip_current_encoding_part message
         
     | 
| 
       46 
49 
     | 
    
         
             
                  end
         
     | 
| 
       47 
50 
     | 
    
         
             
                rescue OpenSSL::Cipher::CipherError => e
         
     | 
| 
         @@ -70,11 +73,11 @@ module Ably::Models::MessageEncoders 
     | 
|
| 
       70 
73 
     | 
    
         
             
                end
         
     | 
| 
       71 
74 
     | 
    
         | 
| 
       72 
75 
     | 
    
         
             
                def cipher_algorithm(message)
         
     | 
| 
       73 
     | 
    
         
            -
                  current_encoding_part(message).to_s[/^#{ENCODING_ID}\+([\ 
     | 
| 
      
 76 
     | 
    
         
            +
                  current_encoding_part(message).to_s[/^#{ENCODING_ID}\+([\w_-]+)$/, 1]
         
     | 
| 
       74 
77 
     | 
    
         
             
                end
         
     | 
| 
       75 
78 
     | 
    
         | 
| 
       76 
79 
     | 
    
         
             
                def already_encrypted?(message)
         
     | 
| 
       77 
     | 
    
         
            -
                  message.fetch(:encoding, '').to_s.match(%r{(^|/)#{ENCODING_ID}\+([\ 
     | 
| 
      
 80 
     | 
    
         
            +
                  message.fetch(:encoding, '').to_s.match(%r{(^|/)#{ENCODING_ID}\+([\w_-]+)($|/)})
         
     | 
| 
       78 
81 
     | 
    
         
             
                end
         
     | 
| 
       79 
82 
     | 
    
         
             
              end
         
     | 
| 
       80 
83 
     | 
    
         
             
            end
         
     |