ribbon-intercom 0.2.3 → 0.3.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.
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