ribbon-intercom 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/lib/ribbon/intercom/client/mock_sdk.rb +13 -0
  3. data/lib/ribbon/intercom/client/sdk/adapters/adapter/response.rb +38 -0
  4. data/lib/ribbon/intercom/client/sdk/adapters/adapter.rb +51 -0
  5. data/lib/ribbon/intercom/client/sdk/adapters/http_adapter/connection.rb +34 -0
  6. data/lib/ribbon/intercom/client/sdk/adapters/http_adapter.rb +26 -0
  7. data/lib/ribbon/intercom/client/sdk/adapters/local_adapter.rb +54 -0
  8. data/lib/ribbon/intercom/client/sdk/adapters/mock_adapter.rb +40 -0
  9. data/lib/ribbon/intercom/client/sdk/adapters.rb +10 -0
  10. data/lib/ribbon/intercom/client/sdk.rb +71 -26
  11. data/lib/ribbon/intercom/client.rb +35 -7
  12. data/lib/ribbon/intercom/errors.rb +34 -6
  13. data/lib/ribbon/intercom/package.rb +64 -0
  14. data/lib/ribbon/intercom/packageable/mixin.rb +35 -0
  15. data/lib/ribbon/intercom/packageable.rb +6 -0
  16. data/lib/ribbon/intercom/service/channel/stores/mock_store.rb +40 -0
  17. data/lib/ribbon/intercom/service/channel/stores/redis_store.rb +186 -0
  18. data/lib/ribbon/intercom/service/{channel_stores/base.rb → channel/stores/store.rb} +13 -5
  19. data/lib/ribbon/intercom/service/channel/stores.rb +9 -0
  20. data/lib/ribbon/intercom/service/channel.rb +106 -4
  21. data/lib/ribbon/intercom/service.rb +156 -95
  22. data/lib/ribbon/intercom/utils/mixins/mock_safe.rb +26 -0
  23. data/lib/ribbon/intercom/utils/mixins.rb +5 -0
  24. data/lib/ribbon/intercom/utils/signer.rb +71 -0
  25. data/lib/ribbon/intercom/utils.rb +40 -13
  26. data/lib/ribbon/intercom/version.rb +1 -1
  27. data/lib/ribbon/intercom.rb +10 -7
  28. data/lib/tasks/intercom.rake +3 -3
  29. metadata +20 -20
  30. data/lib/ribbon/intercom/client/sdk/connection.rb +0 -35
  31. data/lib/ribbon/intercom/client/sdk/response.rb +0 -59
  32. data/lib/ribbon/intercom/service/channel_stores/redis_store.rb +0 -60
@@ -6,31 +6,21 @@ module Ribbon::Intercom
6
6
  class Service
7
7
  autoload(:Channel, 'ribbon/intercom/service/channel')
8
8
 
9
- module ChannelStores
10
- autoload(:Base, 'ribbon/intercom/service/channel_stores/base')
11
- autoload(:RedisStore, 'ribbon/intercom/service/channel_stores/redis_store')
12
- end
9
+ # Used to signify an empty body
10
+ class EmptyResponse; end
13
11
 
14
12
  class << self
15
13
  def instance
16
14
  @instance ||= new(store: _load_store)
17
15
  end
18
16
 
19
- def default_store(store_name, params={})
20
- @_store_name = store_name
21
- @_store_params = params
22
- end
23
-
24
- def permissions(*perms)
25
- @_next_permissions = perms.map(&:to_sym).to_set
17
+ def mock
18
+ Client::MockSDK.new(self)
26
19
  end
27
20
 
28
- def method_permissions
29
- if (ancestor = ancestors.find { |a| a <= Service && a != self })
30
- ancestor.method_permissions
31
- else
32
- {}
33
- end.merge(@_method_permissions).dup
21
+ def store(store_name, params={})
22
+ @_store_name = store_name
23
+ @_store_params = params
34
24
  end
35
25
 
36
26
  # The call method is needed here because Rails checks to see if a mounted
@@ -40,19 +30,20 @@ module Ribbon::Intercom
40
30
  end
41
31
 
42
32
  def method_missing(meth, *args, &block)
43
- instance.send(meth, *args, &block)
33
+ instance.public_send(meth, *args, &block)
44
34
  end
45
35
 
46
36
  def _load_store
47
37
  raise "Store name missing" unless (store_name = @_store_name.to_s)
48
38
 
49
39
  store = Utils.classify(store_name) + "Store"
50
- Intercom::Service::ChannelStores.const_get(store).new(@_store_params)
40
+ Intercom::Service::Channel::Stores.const_get(store).new(@_store_params)
51
41
  end
52
42
  end # Class methods
53
43
 
54
44
  attr_reader :request
55
45
  attr_reader :channel
46
+ attr_reader :subject
56
47
  attr_reader :env
57
48
 
58
49
  def initialize(opts={})
@@ -65,36 +56,17 @@ module Ribbon::Intercom
65
56
 
66
57
  def open_channel(params={})
67
58
  # Accept either an array of permissions or a string
68
- store.open_channel(params)
59
+ store.open_channel(params).tap { |channel|
60
+ channel.may(Utils.method_identifier(self, :rotate_secret))
61
+ }
69
62
  end
70
63
 
71
64
  def lookup_channel(token)
72
65
  store.lookup_channel(token)
73
66
  end
74
67
 
75
- def method_permissions(method_name)
76
- self.class.method_permissions[method_name.to_sym]
77
- end
78
-
79
- def method_permissions!(method_name)
80
- method_permissions(method_name) or
81
- _respond!(404, {}, "Method requested not found.")
82
- end
83
-
84
68
  def sufficient_permissions?(intercom_method)
85
- permissions = method_permissions!(intercom_method)
86
- channel.may?(*permissions)
87
- end
88
-
89
- def sufficient_permissions!(intercom_method)
90
- sufficient_permissions?(intercom_method) or
91
- _respond!(
92
- 403,
93
- {
94
- "X-Intercom-Permissions-Missing" => _missing_permissions(intercom_method).to_a.join(',')
95
- },
96
- "Permissions missing."
97
- )
69
+ channel.may?(Utils.method_identifier(subject, intercom_method))
98
70
  end
99
71
 
100
72
  def call(env)
@@ -105,46 +77,122 @@ module Ribbon::Intercom
105
77
  @env = env
106
78
 
107
79
  response = catch(:response) {
108
- _setup_request
109
- intercom_method, args = _process_request
110
- _call_method(intercom_method, *args)
80
+ begin
81
+ intercom_method, args = _process_request
82
+ _call_method(intercom_method, *args)
83
+ rescue Exception => error
84
+ _respond_with_error!(error)
85
+ end
111
86
  }
112
87
 
113
88
  response.finish
114
- rescue Exception => e
115
- _response(500, {}, e.message).finish
116
89
  end
117
90
 
118
- def validate!(assertion, error_msg="")
119
- assertion.tap { _respond!(400, {}, error_msg) unless assertion }
91
+ def rotate_secret
92
+ channel.rotate_secret!
120
93
  end
121
94
 
122
95
  private
123
96
 
124
- def _setup_request
97
+ def _process_request
98
+ _init_request
99
+ _authenticate_request!
100
+ _load_subject
101
+ [_load_method, _load_args]
102
+ end
103
+
104
+ def _init_request
125
105
  @request = Rack::Request.new(env)
126
- _respond!(405) unless request.put?
106
+
107
+ unless request.put?
108
+ _error!(Errors::MethodNotAllowedError, 'only PUT allowed')
109
+ end
127
110
  end
128
111
 
129
- def _process_request
130
- _request_authenticated!
112
+ def _authenticate_request!
113
+ unless _request_authenticated?
114
+ _error!(Errors::AuthenticationError, "invalid channel credentials")
115
+ end
116
+ end
131
117
 
132
- # Load the method name and args from the request
133
- intercom_method = _load_method_name
134
- args = _load_args
118
+ def _load_subject
119
+ if (encoded_subject=env['HTTP_X_INTERCOM_SUBJECT']) && !encoded_subject.empty?
120
+ @subject = _decode_subject(encoded_subject)
121
+ _error!(Errors::InvalidSubjectSignatureError) unless @subject
122
+ else
123
+ @subject = self
124
+ end
125
+ end
135
126
 
136
- [intercom_method, args]
127
+ def _load_method
128
+ env['HTTP_X_INTERCOM_METHOD'].to_sym.tap { |intercom_method|
129
+ _sufficient_permissions!(intercom_method)
130
+ }
137
131
  end
138
132
 
139
- def _call_method(intercom_method, *args)
140
- body = Utils.sanitize(send(intercom_method, *args))
141
- _respond!(200, {}, body)
133
+ def _load_args
134
+ _decode_args(request.body.read)
142
135
  rescue Errors::UnsafeValueError
143
- _respond!(500, {}, "Return value type is invalid")
136
+ _error!(Errors::UnsafeArgumentError, "One or more argument type is invalid.")
144
137
  end
145
138
 
146
- def _request_authenticated!
147
- _respond!(401) unless _request_authenticated?
139
+ ##
140
+ # Call the method on the subject with the args.
141
+ def _call_method(intercom_method, *args)
142
+ body = _package(subject.public_send(intercom_method, *args))
143
+
144
+ headers = {}
145
+ unless subject == self
146
+ # Need to send subject back in case it was modified by the method.
147
+ headers['X-Intercom-Subject'] = _encode_subject(subject)
148
+
149
+ if subject.is_a?(Packageable::Mixin)
150
+ # Need to send the package data back in case it changed, too.
151
+ headers['X-Intercom-Package-Data'] = subject.encoded_package_data
152
+ end
153
+ end
154
+
155
+ _respond!(200, headers, body)
156
+ rescue NoMethodError => error
157
+ # Want to respond with a 404 here.
158
+ _error!(Errors::InvalidMethodError, intercom_method)
159
+ end
160
+
161
+ ##
162
+ # Package up any non-basic objects that include Packageable::Mixin.
163
+ def _package(object)
164
+ Utils.walk(object) { |object, context|
165
+ if Utils.basic_type?(object)
166
+ object
167
+ elsif context == :hash_key
168
+ # Hash keys must be basic types.
169
+ _error!(Errors::UnsafeResponseError, object.inspect)
170
+ elsif object.is_a?(Packageable::Mixin)
171
+ _package_obj(object, object.package_data)
172
+ elsif object.is_a?(Class) && object < Packageable::Mixin
173
+ _package_obj(object)
174
+ else
175
+ _error!(Errors::UnsafeResponseError, object.inspect)
176
+ end
177
+ }
178
+ end
179
+
180
+ def _package_obj(object, data=nil)
181
+ Package.new(_encode_subject(object), data)
182
+ end
183
+
184
+ ##
185
+ # Marshal dumps the subject and signs the resulting bytes with the channel.
186
+ def _encode_subject(subject)
187
+ Base64.strict_encode64(channel.sign(Marshal.dump(subject)))
188
+ end
189
+
190
+ ##
191
+ # Decodes the subject sent from the client.
192
+ def _decode_subject(encoded_subject)
193
+ signed_subject = Base64.strict_decode64(encoded_subject)
194
+ marshalled_subject = channel.verify(signed_subject)
195
+ marshalled_subject && Marshal.load(marshalled_subject)
148
196
  end
149
197
 
150
198
  def _request_authenticated?
@@ -160,56 +208,69 @@ module Ribbon::Intercom
160
208
  end
161
209
  end
162
210
 
163
- def _load_method_name
164
- env['HTTP_X_INTERCOM_METHOD'].to_sym.tap { |intercom_method|
165
- # Check permissions
166
- sufficient_permissions!(intercom_method)
167
- }
211
+ def _sufficient_permissions!(intercom_method)
212
+ unless sufficient_permissions?(intercom_method)
213
+ required = Utils.method_identifier(subject, intercom_method)
214
+ _error!(Errors::InsufficientPermissionsError, required)
215
+ end
168
216
  end
169
217
 
170
- def _load_args
171
- _decode_args(request.body.read)
172
- rescue Errors::UnsafeValueError
173
- _respond!(400, {}, "Arg types are invalid")
218
+ def _response(status, headers={}, body=EmptyResponse)
219
+ body = body == EmptyResponse ? [] : [_encode_body(body)]
220
+ headers = headers.merge("Content-Type" => "text/plain", "Transfer-Encoding" => "gzip")
221
+ Rack::Response.new(body, status, headers)
174
222
  end
175
223
 
176
- def _missing_permissions(intercom_method)
177
- method_permissions(intercom_method) - channel.permissions
224
+ def _respond!(status, headers={}, body=EmptyResponse)
225
+ throw :response, _response(status, headers, body)
178
226
  end
179
227
 
180
- def _response(status, headers={}, body="")
181
- body = [_encode_body(body)]
182
- headers = headers.merge("Content-Type" => "text/plain", "Transfer-Encoding" => "gzip")
183
- Rack::Response.new(body, status, headers)
228
+ def _respond_with_error!(error, status=500)
229
+ _respond!(status, { 'X-Intercom-Error' => _encode_error(error) })
184
230
  end
185
231
 
186
- def _respond!(status, headers={}, body="")
187
- throw :response, _response(status, headers, body)
232
+ def _error!(klass, message=nil)
233
+ error = message ? klass.new(message) : klass.new
234
+ _respond_with_error!(error, _error_to_http_code(error))
235
+ end
236
+
237
+ def _error_to_http_code(error)
238
+ case error
239
+ when Errors::MethodNotAllowedError
240
+ 405
241
+ when Errors::NotFoundError
242
+ 404
243
+ when Errors::ForbiddenError
244
+ 403
245
+ when Errors::AuthenticationError
246
+ 401
247
+ when Errors::RequestError
248
+ 400
249
+ when Errors::ServerError
250
+ 500
251
+ else
252
+ 500
253
+ end
188
254
  end
189
255
 
190
256
  def _encode_body(body)
191
257
  Base64.strict_encode64(Marshal.dump(body))
192
258
  end
193
259
 
260
+ def _encode_error(error)
261
+ Base64.strict_encode64(Marshal.dump(error))
262
+ end
263
+
264
+ ##
265
+ # Decodes the arguments.
266
+ #
267
+ # It's very important that this happens *after* channel authentication is
268
+ # performed. Since `args` comes from the client it could contain malicious
269
+ # marshalled data.
194
270
  def _decode_args(args)
195
271
  Utils.sanitize(Marshal.load(Base64.strict_decode64(args))).tap { |args|
196
272
  raise Errors::UnsafeValueError unless args.is_a?(Array)
197
273
  }
198
274
  end
199
275
  end # Service
200
-
201
- # Re-opening the class so the above instance methods don't get added to the
202
- # permissions hash
203
- class Service
204
- class << self
205
- def method_added(method_name)
206
- (@_method_permissions ||= {})[method_name] = (@_next_permissions || [method_name].to_set).dup.freeze
207
- @_next_permissions = nil
208
- end
209
- end # Class Methods
210
-
211
- def rotate_secret
212
- channel.rotate_secret!
213
- end
214
- end # Service
215
276
  end # Ribbon::Intercom
@@ -0,0 +1,26 @@
1
+ module Ribbon::Intercom
2
+ module Utils::Mixins
3
+ module MockSafe
4
+ ##
5
+ # Return a mock safe version of this package.
6
+ def mock_safe
7
+ dup.tap { |obj| obj.mock_safe! }
8
+ end
9
+
10
+ ##
11
+ # Make this package mock safe.
12
+ def mock_safe!
13
+ unless mock_safe?
14
+ @_mock_safe = true
15
+
16
+ # For RSpec: Allow any method to be mocked on this instance.
17
+ define_singleton_method(:respond_to?) { |*args| true }
18
+ end
19
+ end
20
+
21
+ def mock_safe?
22
+ !!@_mock_safe
23
+ end
24
+ end # MockSafe
25
+ end # Utils::Mixin
26
+ end # Ribbon::Intercom
@@ -0,0 +1,5 @@
1
+ module Ribbon::Intercom
2
+ module Utils::Mixins
3
+ autoload(:MockSafe, 'ribbon/intercom/utils/mixins/mock_safe')
4
+ end # Utils::Mixin
5
+ end # Ribbon::Intercom
@@ -0,0 +1,71 @@
1
+ require 'securerandom'
2
+ require 'openssl'
3
+
4
+ module Ribbon::Intercom
5
+ module Utils
6
+ class Signer
7
+ class << self
8
+ def random_key
9
+ SecureRandom.random_bytes(32)
10
+ end
11
+
12
+ def random_salt
13
+ SecureRandom.random_bytes(8)
14
+ end
15
+ end
16
+
17
+ attr_reader :key
18
+
19
+ def initialize(key=self.class.random_key)
20
+ raise ArgumentError, "key must be defined" unless key
21
+ @key = key.dup.freeze
22
+ @_digest = OpenSSL::Digest::SHA256.new
23
+ end
24
+
25
+ def sign(data)
26
+ unless data.is_a?(String) && data.encoding == Encoding::BINARY
27
+ raise ArgumentError, "data must be a binary encoded string"
28
+ end
29
+
30
+ salt = self.class.random_salt
31
+ signature = _sign(salt, data)
32
+ _encode(signature, salt, data)
33
+ end
34
+
35
+ def verify(signed_data)
36
+ unless signed_data.is_a?(String) && signed_data.encoding == Encoding::BINARY
37
+ raise ArgumentError, "signed_data must be a binary encoded string"
38
+ end
39
+
40
+ signature, salt, data = _decode(signed_data)
41
+ data if _sign(salt, data) == signature
42
+ end
43
+
44
+ private
45
+
46
+ def _sign(salt, data)
47
+ OpenSSL::HMAC.digest(@_digest, key, salt + data)
48
+ end
49
+
50
+ def _encode(signature, salt, data)
51
+ "\x01" + signature + salt + data
52
+ end
53
+
54
+ def _decode(signed_data)
55
+ index = 0
56
+ version = signed_data[index]
57
+
58
+ index += version.length
59
+ signature = signed_data.slice(index, @_digest.length)
60
+
61
+ index += signature.length
62
+ salt = signed_data.slice(index, 8)
63
+
64
+ index += salt.length
65
+ data = signed_data.slice(index..-1)
66
+
67
+ [signature, salt, data]
68
+ end
69
+ end # Signer
70
+ end # Utils
71
+ end # Ribbon::Intercom
@@ -1,27 +1,47 @@
1
1
  require 'date'
2
2
 
3
3
  module Ribbon::Intercom
4
- class Utils
4
+ module Utils
5
+ autoload(:Signer, 'ribbon/intercom/utils/signer')
6
+ autoload(:Mixins, 'ribbon/intercom/utils/mixins')
7
+
8
+ BASIC_TYPES = [
9
+ String, Symbol, TrueClass, FalseClass, Integer, Float, NilClass, Date, Time, DateTime
10
+ ].freeze
11
+
5
12
  class << self
6
- def sanitize(object)
13
+ def basic_type?(object)
14
+ case object
15
+ when *BASIC_TYPES then true
16
+ else false
17
+ end
18
+ end
19
+
20
+ def walk(object, context=nil, &block)
7
21
  case object
8
- when String, Symbol, TrueClass, FalseClass, Integer, Float, NilClass, Date, Time, DateTime
9
- object
10
22
  when Hash
11
- sanitize_hash(object)
23
+ Hash[
24
+ object.map { |key, val|
25
+ [walk(key, :hash_key, &block), walk(val, :hash_value, &block)]
26
+ }
27
+ ]
12
28
  when Array
13
- sanitize_array(object)
29
+ object.map { |obj| walk(obj, :array_elem, &block) }
14
30
  else
15
- raise Errors::UnsafeValueError, object.inspect
31
+ yield object, context
16
32
  end
17
33
  end
18
34
 
19
- def sanitize_array(array)
20
- array.map { |obj| sanitize(obj) }
21
- end
22
-
23
- def sanitize_hash(hash)
24
- Hash[hash.map { |key, val| [sanitize(key), sanitize(val)] }]
35
+ ##
36
+ # Raises an error if the object is or contains any non-basic types.
37
+ def sanitize(object)
38
+ walk(object) { |object|
39
+ if basic_type?(object)
40
+ object
41
+ else
42
+ raise Errors::UnsafeValueError, object.inspect
43
+ end
44
+ }
25
45
  end
26
46
 
27
47
  def symbolize_keys(hash)
@@ -31,6 +51,13 @@ module Ribbon::Intercom
31
51
  def classify(str)
32
52
  str.split("_").map(&:capitalize).join
33
53
  end
54
+
55
+ ##
56
+ # Returns an identifier for the method (e.g., A::B::C#method_name)
57
+ def method_identifier(subject, method)
58
+ scope = subject.is_a?(Class) ? subject.name : subject.class.name
59
+ scope + (subject.is_a?(Class) ? '.' : '#') + method.to_s
60
+ end
34
61
  end # Class methods
35
62
  end # Utils
36
63
  end # Ribbon::Intercom
@@ -1,5 +1,5 @@
1
1
  module Ribbon
2
2
  module Intercom
3
- VERSION = '0.2.3'
3
+ VERSION = '0.3.0'
4
4
  end
5
5
  end
@@ -4,10 +4,12 @@ require 'rack'
4
4
  module Ribbon
5
5
  module Intercom
6
6
  require 'ribbon/intercom/railtie' if defined?(Rails)
7
- autoload(:Service, 'ribbon/intercom/service')
8
- autoload(:Errors, 'ribbon/intercom/errors')
9
- autoload(:Client, 'ribbon/intercom/client')
10
- autoload(:Utils, 'ribbon/intercom/utils')
7
+ autoload(:Service, 'ribbon/intercom/service')
8
+ autoload(:Errors, 'ribbon/intercom/errors')
9
+ autoload(:Client, 'ribbon/intercom/client')
10
+ autoload(:Package, 'ribbon/intercom/package')
11
+ autoload(:Packageable, 'ribbon/intercom/packageable')
12
+ autoload(:Utils, 'ribbon/intercom/utils')
11
13
 
12
14
  module_function
13
15
 
@@ -20,10 +22,11 @@ module Ribbon
20
22
  end
21
23
 
22
24
  def mock_safe
23
- primary_client = client
24
- @_client = @_client.dup
25
+ orig_client = client
26
+ @_client = @_client.mock_safe
25
27
  yield
26
- @_client = primary_client
28
+ ensure
29
+ @_client = orig_client
27
30
  end
28
31
  end # Intercom
29
32
  end # Ribbon
@@ -4,9 +4,9 @@ require 'json'
4
4
 
5
5
  namespace :intercom do
6
6
  namespace :client do
7
- task :rotate_secret, [:remote] => :environment do |t, args|
8
- remote = args[:remote]
9
- puts "New #{remote} secret: #{Intercom[remote].rotate_secret}"
7
+ task :rotate_secret, [:service] => :environment do |t, args|
8
+ service = args[:service]
9
+ puts "New #{service} secret: #{Intercom[service].rotate_secret}"
10
10
  end
11
11
  end
12
12
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ribbon-intercom
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Honer
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-04-20 00:00:00.000000000 Z
12
+ date: 2015-05-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -65,20 +65,6 @@ dependencies:
65
65
  - - ">="
66
66
  - !ruby/object:Gem::Version
67
67
  version: '0'
68
- - !ruby/object:Gem::Dependency
69
- name: rest-client
70
- requirement: !ruby/object:Gem::Requirement
71
- requirements:
72
- - - "~>"
73
- - !ruby/object:Gem::Version
74
- version: 1.7.2
75
- type: :runtime
76
- prerelease: false
77
- version_requirements: !ruby/object:Gem::Requirement
78
- requirements:
79
- - - "~>"
80
- - !ruby/object:Gem::Version
81
- version: 1.7.2
82
68
  - !ruby/object:Gem::Dependency
83
69
  name: ribbon-config
84
70
  requirement: !ruby/object:Gem::Requirement
@@ -173,16 +159,30 @@ extra_rdoc_files: []
173
159
  files:
174
160
  - lib/ribbon/intercom.rb
175
161
  - lib/ribbon/intercom/client.rb
162
+ - lib/ribbon/intercom/client/mock_sdk.rb
176
163
  - lib/ribbon/intercom/client/sdk.rb
177
- - lib/ribbon/intercom/client/sdk/connection.rb
178
- - lib/ribbon/intercom/client/sdk/response.rb
164
+ - lib/ribbon/intercom/client/sdk/adapters.rb
165
+ - lib/ribbon/intercom/client/sdk/adapters/adapter.rb
166
+ - lib/ribbon/intercom/client/sdk/adapters/adapter/response.rb
167
+ - lib/ribbon/intercom/client/sdk/adapters/http_adapter.rb
168
+ - lib/ribbon/intercom/client/sdk/adapters/http_adapter/connection.rb
169
+ - lib/ribbon/intercom/client/sdk/adapters/local_adapter.rb
170
+ - lib/ribbon/intercom/client/sdk/adapters/mock_adapter.rb
179
171
  - lib/ribbon/intercom/errors.rb
172
+ - lib/ribbon/intercom/package.rb
173
+ - lib/ribbon/intercom/packageable.rb
174
+ - lib/ribbon/intercom/packageable/mixin.rb
180
175
  - lib/ribbon/intercom/railtie.rb
181
176
  - lib/ribbon/intercom/service.rb
182
177
  - lib/ribbon/intercom/service/channel.rb
183
- - lib/ribbon/intercom/service/channel_stores/base.rb
184
- - lib/ribbon/intercom/service/channel_stores/redis_store.rb
178
+ - lib/ribbon/intercom/service/channel/stores.rb
179
+ - lib/ribbon/intercom/service/channel/stores/mock_store.rb
180
+ - lib/ribbon/intercom/service/channel/stores/redis_store.rb
181
+ - lib/ribbon/intercom/service/channel/stores/store.rb
185
182
  - lib/ribbon/intercom/utils.rb
183
+ - lib/ribbon/intercom/utils/mixins.rb
184
+ - lib/ribbon/intercom/utils/mixins/mock_safe.rb
185
+ - lib/ribbon/intercom/utils/signer.rb
186
186
  - lib/ribbon/intercom/version.rb
187
187
  - lib/tasks/intercom.rake
188
188
  homepage: http://github.com/ribbon/intercom
@@ -1,35 +0,0 @@
1
- require 'rest-client'
2
-
3
- module Ribbon::Intercom
4
- class Client
5
- class SDK
6
- class Connection
7
- def initialize(url, token, secret)
8
- @client = RestClient::Resource.new(
9
- url,
10
- user: token,
11
- password: secret,
12
- ) { |response, request, result| response }
13
- end
14
-
15
- def put(path, method_name, args)
16
- path = _build_path(path)
17
- headers = { "X-Intercom-Method" => method_name }
18
- payload = _encode_args(args)
19
-
20
- Response.new(@client[path].put(payload, headers))
21
- end
22
-
23
- private
24
-
25
- def _build_path(path)
26
- path[0] == '/' ? path : '/' + path
27
- end
28
-
29
- def _encode_args(args)
30
- Base64.strict_encode64(Marshal.dump(Utils.sanitize(args)))
31
- end
32
- end # Connection
33
- end # SDK
34
- end # Client
35
- end # Ribbon::Intercom