nexmo 4.5.0 → 4.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 439a33a2772242ae8bd36c38485dba3e993c0e7e
4
- data.tar.gz: da75c2646fc649aa480d5fbf1a22765e59e8bfe6
3
+ metadata.gz: fcd725644e13c80c7c86b80e347c0bef98c8805d
4
+ data.tar.gz: 7c0eafc7558cb0d68c9faa93d1f3e9776ddf221c
5
5
  SHA512:
6
- metadata.gz: e3d829a39cf396a2ce3186abae44ce8b1ebc4037fcf29c9a3fee212a1b17373d8970e2ab83002a000c23c146141c49b7244fc675cf6a6530f33f63c67a3bfaf7
7
- data.tar.gz: 828c598a241f0a02e2ffe762dd2f20f575fc7ebb870a4ec58a1685d24220b41c72e0ea20ce71304bd337d3bb17bf96679a71f4ad9cfed17c5fea4e86c803710f
6
+ metadata.gz: 29d45a64e0aeaec4c647c54d1db995b9c22a58b071a815f3e46d52648eff3a216c73dfb72e67777a19c9ae6499957a7e6d3900ae641a829fcef174884071d196
7
+ data.tar.gz: da8b6ec8aaaa5b55645940e2d6b0b59260c17bf717cf8191bf430687636a147e26b885a23ccdcff82fbfd1cbee20c084a553ed217be82ae42582fe6f36e481e9
data/README.md CHANGED
@@ -1,5 +1,4 @@
1
- Nexmo Client Library for Ruby
2
- =============================
1
+ # Nexmo Client Library for Ruby
3
2
 
4
3
  [![Gem Version](https://badge.fury.io/rb/nexmo.svg)](https://badge.fury.io/rb/nexmo) [![Build Status](https://api.travis-ci.org/Nexmo/nexmo-ruby.svg?branch=master)](https://travis-ci.org/Nexmo/nexmo-ruby)
5
4
 
@@ -16,8 +15,7 @@ need a Nexmo account. Sign up [for free at nexmo.com][signup].
16
15
  * [License](#license)
17
16
 
18
17
 
19
- Installation
20
- ------------
18
+ ## Installation
21
19
 
22
20
  To install the Ruby client library using Rubygems:
23
21
 
@@ -28,8 +26,7 @@ Alternatively you can clone the repository:
28
26
  git clone git@github.com:Nexmo/nexmo-ruby.git
29
27
 
30
28
 
31
- Usage
32
- -----
29
+ ## Usage
33
30
 
34
31
  Begin by requiring the nexmo library:
35
32
 
@@ -252,6 +249,30 @@ response = client.delete_application(uuid)
252
249
  Docs: [https://docs.nexmo.com/tools/application-api/api-reference#delete](https://docs.nexmo.com/tools/application-api/api-reference#delete?utm_source=DEV_REL&utm_medium=github&utm_campaign=ruby-client-library)
253
250
 
254
251
 
252
+ ## JWT authentication
253
+
254
+ By default the library generates a short lived JWT per request.
255
+
256
+ To generate a long lived JWT for multiple requests or to specify JWT claims
257
+ directly call Nexmo::JWT.auth_token to generate a token, and set the auth_token
258
+ attribute on the client object. For example:
259
+
260
+ ```ruby
261
+ claims = {
262
+ application_id: application_id,
263
+ nbf: 1483315200,
264
+ exp: 1514764800,
265
+ iat: 1483228800
266
+ }
267
+
268
+ private_key = File.read('path/to/private.key')
269
+
270
+ auth_token = Nexmo::JWT.auth_token(claims, private_key)
271
+
272
+ client.auth_token = auth_token
273
+ ````
274
+
275
+
255
276
  ## Validate webhook signatures
256
277
 
257
278
  ```ruby
@@ -270,8 +291,7 @@ Note: you'll need to contact support@nexmo.com to enable message signing on
270
291
  your account before you can validate webhook signatures.
271
292
 
272
293
 
273
- API Coverage
274
- ------------
294
+ ## API Coverage
275
295
 
276
296
  * Account
277
297
  * [X] Balance
@@ -313,8 +333,7 @@ API Coverage
313
333
  * [X] Text-To-Speech Prompt
314
334
 
315
335
 
316
- License
317
- -------
336
+ ## License
318
337
 
319
338
  This library is released under the [MIT License][license]
320
339
 
@@ -6,354 +6,4 @@ require 'nexmo/errors/error'
6
6
  require 'nexmo/errors/client_error'
7
7
  require 'nexmo/errors/server_error'
8
8
  require 'nexmo/errors/authentication_error'
9
- require 'net/http'
10
- require 'json'
11
-
12
- module Nexmo
13
- class Client
14
- attr_accessor :key, :secret
15
-
16
- def initialize(options = {})
17
- @key = options.fetch(:key) { ENV.fetch('NEXMO_API_KEY') }
18
-
19
- @secret = options.fetch(:secret) { ENV.fetch('NEXMO_API_SECRET') }
20
-
21
- @signature_secret = options.fetch(:signature_secret) { ENV['NEXMO_SIGNATURE_SECRET'] }
22
-
23
- @application_id = options[:application_id]
24
-
25
- @private_key = options[:private_key]
26
-
27
- @host = options.fetch(:host) { 'rest.nexmo.com' }
28
-
29
- @api_host = options.fetch(:api_host) { 'api.nexmo.com' }
30
-
31
- @sns_host = options.fetch(:sns_host) { 'sns.nexmo.com' }
32
-
33
- @user_agent = "nexmo-ruby/#{VERSION} ruby/#{RUBY_VERSION}"
34
-
35
- if options.key?(:app_name) && options.key?(:app_version)
36
- @user_agent << " #{options[:app_name]}/#{options[:app_version]}"
37
- end
38
- end
39
-
40
- def send_message(params)
41
- post(@host, '/sms/json', params)
42
- end
43
-
44
- def track_message_conversion(message_id, params = {})
45
- post(@api_host, '/conversions/sms', {'message-id' => message_id}.merge(params))
46
- end
47
-
48
- def track_voice_conversion(message_id, params = {})
49
- post(@api_host, '/conversions/voice', {'message-id' => message_id}.merge(params))
50
- end
51
-
52
- def get_balance
53
- get(@host, '/account/get-balance')
54
- end
55
-
56
- def get_country_pricing(country_code)
57
- get(@host, '/account/get-pricing/outbound', country: country_code)
58
- end
59
-
60
- def get_prefix_pricing(prefix)
61
- get(@host, '/account/get-prefix-pricing/outbound', prefix: prefix)
62
- end
63
-
64
- def get_sms_pricing(number)
65
- get(@host, '/account/get-phone-pricing/outbound/sms', phone: number)
66
- end
67
-
68
- def get_voice_pricing(number)
69
- get(@host, '/account/get-phone-pricing/outbound/voice', phone: number)
70
- end
71
-
72
- def update_settings(params)
73
- post(@host, '/account/settings', params)
74
- end
75
-
76
- def topup(params)
77
- post(@host, '/account/top-up', params)
78
- end
79
-
80
- def get_account_numbers(params)
81
- get(@host, '/account/numbers', params)
82
- end
83
-
84
- def get_available_numbers(country_code, params = {})
85
- get(@host, '/number/search', {country: country_code}.merge(params))
86
- end
87
-
88
- def buy_number(params)
89
- post(@host, '/number/buy', params)
90
- end
91
-
92
- def cancel_number(params)
93
- post(@host, '/number/cancel', params)
94
- end
95
-
96
- def update_number(params)
97
- post(@host, '/number/update', params)
98
- end
99
-
100
- def get_message(id)
101
- get(@host, '/search/message', id: id)
102
- end
103
-
104
- def get_message_rejections(params)
105
- get(@host, '/search/rejections', params)
106
- end
107
-
108
- def search_messages(params)
109
- get(@host, '/search/messages', Hash === params ? params : {ids: Array(params)})
110
- end
111
-
112
- def send_ussd_push_message(params)
113
- post(@host, '/ussd/json', params)
114
- end
115
-
116
- def send_ussd_prompt_message(params)
117
- post(@host, '/ussd-prompt/json', params)
118
- end
119
-
120
- def send_2fa_message(params)
121
- post(@host, '/sc/us/2fa/json', params)
122
- end
123
-
124
- def send_event_alert_message(params)
125
- post(@host, '/sc/us/alert/json', params)
126
- end
127
-
128
- def send_marketing_message(params)
129
- post(@host, '/sc/us/marketing/json', params)
130
- end
131
-
132
- def get_event_alert_numbers
133
- get(@host, '/sc/us/alert/opt-in/query/json')
134
- end
135
-
136
- def resubscribe_event_alert_number(params)
137
- post(@host, '/sc/us/alert/opt-in/manage/json', params)
138
- end
139
-
140
- def sns_publish(message, params)
141
- post(@sns_host, '/sns/json', {cmd: 'publish', message: message}.merge(params))
142
- end
143
-
144
- def sns_subscribe(recipient, params)
145
- post(@sns_host, '/sns/json', {cmd: 'subscribe', to: recipient}.merge(params))
146
- end
147
-
148
- def initiate_call(params)
149
- Kernel.warn "#{self.class}##{__method__} is deprecated (use the Voice API instead)."
150
-
151
- post(@host, '/call/json', params)
152
- end
153
-
154
- def initiate_tts_call(params)
155
- Kernel.warn "#{self.class}##{__method__} is deprecated (use the Voice API instead)."
156
-
157
- post(@api_host, '/tts/json', params)
158
- end
159
-
160
- def initiate_tts_prompt_call(params)
161
- Kernel.warn "#{self.class}##{__method__} is deprecated (use the Voice API instead)."
162
-
163
- post(@api_host, '/tts-prompt/json', params)
164
- end
165
-
166
- def start_verification(params)
167
- post(@api_host, '/verify/json', params)
168
- end
169
-
170
- def check_verification(request_id, params)
171
- post(@api_host, '/verify/check/json', params.merge(request_id: request_id))
172
- end
173
-
174
- def get_verification(request_id)
175
- get(@api_host, '/verify/search/json', request_id: request_id)
176
- end
177
-
178
- def cancel_verification(request_id)
179
- post(@api_host, '/verify/control/json', request_id: request_id, cmd: 'cancel')
180
- end
181
-
182
- def trigger_next_verification_event(request_id)
183
- post(@api_host, '/verify/control/json', request_id: request_id, cmd: 'trigger_next_event')
184
- end
185
-
186
- def get_basic_number_insight(params)
187
- get(@api_host, '/ni/basic/json', params)
188
- end
189
-
190
- def get_standard_number_insight(params)
191
- get(@api_host, '/ni/standard/json', params)
192
- end
193
-
194
- def get_number_insight(params)
195
- Kernel.warn "#{self.class}##{__method__} is deprecated (use #get_standard_number_insight instead)."
196
-
197
- get(@api_host, '/number/lookup/json', params)
198
- end
199
-
200
- def get_advanced_number_insight(params)
201
- get(@api_host, '/ni/advanced/json', params)
202
- end
203
-
204
- def get_advanced_async_number_insight(params)
205
- get(@api_host, '/ni/advanced/async/json', params)
206
- end
207
-
208
- def request_number_insight(params)
209
- post(@host, '/ni/json', params)
210
- end
211
-
212
- def get_applications(params = {})
213
- get(@api_host, '/v1/applications', params)
214
- end
215
-
216
- def get_application(id)
217
- get(@api_host, "/v1/applications/#{id}")
218
- end
219
-
220
- def create_application(params)
221
- post(@api_host, '/v1/applications', params)
222
- end
223
-
224
- def update_application(id, params)
225
- put(@api_host, "/v1/applications/#{id}", params)
226
- end
227
-
228
- def delete_application(id)
229
- delete(@api_host, "/v1/applications/#{id}")
230
- end
231
-
232
- def create_call(params)
233
- api_request(Net::HTTP::Post, '/v1/calls', params)
234
- end
235
-
236
- def get_calls(params = nil)
237
- api_request(Net::HTTP::Get, '/v1/calls', params)
238
- end
239
-
240
- def get_call(uuid)
241
- api_request(Net::HTTP::Get, "/v1/calls/#{uuid}")
242
- end
243
-
244
- def update_call(uuid, params)
245
- api_request(Net::HTTP::Put, "/v1/calls/#{uuid}", params)
246
- end
247
-
248
- def send_audio(uuid, params)
249
- api_request(Net::HTTP::Put, "/v1/calls/#{uuid}/stream", params)
250
- end
251
-
252
- def stop_audio(uuid)
253
- api_request(Net::HTTP::Delete, "/v1/calls/#{uuid}/stream")
254
- end
255
-
256
- def send_speech(uuid, params)
257
- api_request(Net::HTTP::Put, "/v1/calls/#{uuid}/talk", params)
258
- end
259
-
260
- def stop_speech(uuid)
261
- api_request(Net::HTTP::Delete, "/v1/calls/#{uuid}/talk")
262
- end
263
-
264
- def send_dtmf(uuid, params)
265
- api_request(Net::HTTP::Put, "/v1/calls/#{uuid}/dtmf", params)
266
- end
267
-
268
- def check_signature(params)
269
- Signature.check(params, @signature_secret)
270
- end
271
-
272
- private
273
-
274
- def get(host, request_uri, params = {})
275
- uri = URI('https://' + host + request_uri)
276
- uri.query = Params.encode(params.merge(api_key: @key, api_secret: @secret))
277
-
278
- message = Net::HTTP::Get.new(uri.request_uri)
279
-
280
- request(uri, message)
281
- end
282
-
283
- def post(host, request_uri, params)
284
- uri = URI('https://' + host + request_uri)
285
-
286
- message = Net::HTTP::Post.new(uri.request_uri)
287
- message.form_data = params.merge(api_key: @key, api_secret: @secret)
288
-
289
- request(uri, message)
290
- end
291
-
292
- def put(host, request_uri, params)
293
- uri = URI('https://' + host + request_uri)
294
-
295
- message = Net::HTTP::Put.new(uri.request_uri)
296
- message.form_data = params.merge(api_key: @key, api_secret: @secret)
297
-
298
- request(uri, message)
299
- end
300
-
301
- def delete(host, request_uri)
302
- uri = URI('https://' + host + request_uri)
303
- uri.query = Params.encode({api_key: @key, api_secret: @secret})
304
-
305
- message = Net::HTTP::Delete.new(uri.request_uri)
306
-
307
- request(uri, message)
308
- end
309
-
310
- def api_request(message_class, path, params = nil)
311
- uri = URI('https://' + @api_host + path)
312
-
313
- unless message_class::REQUEST_HAS_BODY || params.nil? || params.empty?
314
- uri.query = Params.encode(params)
315
- end
316
-
317
- message = message_class.new(uri.request_uri)
318
-
319
- if message_class::REQUEST_HAS_BODY
320
- message['Content-Type'] = 'application/json'
321
- message.body = JSON.generate(params)
322
- end
323
-
324
- auth_payload = {application_id: @application_id}
325
-
326
- message['Authorization'] = JWT.auth_header(auth_payload, @private_key)
327
-
328
- request(uri, message)
329
- end
330
-
331
- def request(uri, message)
332
- http = Net::HTTP.new(uri.host, Net::HTTP.https_default_port)
333
- http.use_ssl = true
334
-
335
- message['User-Agent'] = @user_agent
336
-
337
- http_response = http.request(message)
338
-
339
- case http_response
340
- when Net::HTTPNoContent
341
- :no_content
342
- when Net::HTTPSuccess
343
- if http_response['Content-Type'].split(';').first == 'application/json'
344
- JSON.parse(http_response.body)
345
- else
346
- http_response.body
347
- end
348
- when Net::HTTPUnauthorized
349
- raise AuthenticationError, "#{http_response.code} response from #{uri.host}"
350
- when Net::HTTPClientError
351
- raise ClientError, "#{http_response.code} response from #{uri.host}"
352
- when Net::HTTPServerError
353
- raise ServerError, "#{http_response.code} response from #{uri.host}"
354
- else
355
- raise Error, "#{http_response.code} response from #{uri.host}"
356
- end
357
- end
358
- end
359
- end
9
+ require 'nexmo/client'
@@ -0,0 +1,350 @@
1
+ require 'net/http'
2
+ require 'json'
3
+
4
+ module Nexmo
5
+ class Client
6
+ attr_accessor :key, :secret, :auth_token
7
+
8
+ def initialize(options = {})
9
+ @key = options.fetch(:key) { ENV.fetch('NEXMO_API_KEY') }
10
+
11
+ @secret = options.fetch(:secret) { ENV.fetch('NEXMO_API_SECRET') }
12
+
13
+ @signature_secret = options.fetch(:signature_secret) { ENV['NEXMO_SIGNATURE_SECRET'] }
14
+
15
+ @application_id = options[:application_id]
16
+
17
+ @private_key = options[:private_key]
18
+
19
+ @host = options.fetch(:host) { 'rest.nexmo.com' }
20
+
21
+ @api_host = options.fetch(:api_host) { 'api.nexmo.com' }
22
+
23
+ @sns_host = options.fetch(:sns_host) { 'sns.nexmo.com' }
24
+
25
+ @user_agent = "nexmo-ruby/#{VERSION} ruby/#{RUBY_VERSION}"
26
+
27
+ if options.key?(:app_name) && options.key?(:app_version)
28
+ @user_agent << " #{options[:app_name]}/#{options[:app_version]}"
29
+ end
30
+ end
31
+
32
+ def send_message(params)
33
+ post(@host, '/sms/json', params)
34
+ end
35
+
36
+ def track_message_conversion(message_id, params = {})
37
+ post(@api_host, '/conversions/sms', {'message-id' => message_id}.merge(params))
38
+ end
39
+
40
+ def track_voice_conversion(message_id, params = {})
41
+ post(@api_host, '/conversions/voice', {'message-id' => message_id}.merge(params))
42
+ end
43
+
44
+ def get_balance
45
+ get(@host, '/account/get-balance')
46
+ end
47
+
48
+ def get_country_pricing(country_code)
49
+ get(@host, '/account/get-pricing/outbound', country: country_code)
50
+ end
51
+
52
+ def get_prefix_pricing(prefix)
53
+ get(@host, '/account/get-prefix-pricing/outbound', prefix: prefix)
54
+ end
55
+
56
+ def get_sms_pricing(number)
57
+ get(@host, '/account/get-phone-pricing/outbound/sms', phone: number)
58
+ end
59
+
60
+ def get_voice_pricing(number)
61
+ get(@host, '/account/get-phone-pricing/outbound/voice', phone: number)
62
+ end
63
+
64
+ def update_settings(params)
65
+ post(@host, '/account/settings', params)
66
+ end
67
+
68
+ def topup(params)
69
+ post(@host, '/account/top-up', params)
70
+ end
71
+
72
+ def get_account_numbers(params)
73
+ get(@host, '/account/numbers', params)
74
+ end
75
+
76
+ def get_available_numbers(country_code, params = {})
77
+ get(@host, '/number/search', {country: country_code}.merge(params))
78
+ end
79
+
80
+ def buy_number(params)
81
+ post(@host, '/number/buy', params)
82
+ end
83
+
84
+ def cancel_number(params)
85
+ post(@host, '/number/cancel', params)
86
+ end
87
+
88
+ def update_number(params)
89
+ post(@host, '/number/update', params)
90
+ end
91
+
92
+ def get_message(id)
93
+ get(@host, '/search/message', id: id)
94
+ end
95
+
96
+ def get_message_rejections(params)
97
+ get(@host, '/search/rejections', params)
98
+ end
99
+
100
+ def search_messages(params)
101
+ get(@host, '/search/messages', Hash === params ? params : {ids: Array(params)})
102
+ end
103
+
104
+ def send_ussd_push_message(params)
105
+ post(@host, '/ussd/json', params)
106
+ end
107
+
108
+ def send_ussd_prompt_message(params)
109
+ post(@host, '/ussd-prompt/json', params)
110
+ end
111
+
112
+ def send_2fa_message(params)
113
+ post(@host, '/sc/us/2fa/json', params)
114
+ end
115
+
116
+ def send_event_alert_message(params)
117
+ post(@host, '/sc/us/alert/json', params)
118
+ end
119
+
120
+ def send_marketing_message(params)
121
+ post(@host, '/sc/us/marketing/json', params)
122
+ end
123
+
124
+ def get_event_alert_numbers
125
+ get(@host, '/sc/us/alert/opt-in/query/json')
126
+ end
127
+
128
+ def resubscribe_event_alert_number(params)
129
+ post(@host, '/sc/us/alert/opt-in/manage/json', params)
130
+ end
131
+
132
+ def sns_publish(message, params)
133
+ post(@sns_host, '/sns/json', {cmd: 'publish', message: message}.merge(params))
134
+ end
135
+
136
+ def sns_subscribe(recipient, params)
137
+ post(@sns_host, '/sns/json', {cmd: 'subscribe', to: recipient}.merge(params))
138
+ end
139
+
140
+ def initiate_call(params)
141
+ Kernel.warn "#{self.class}##{__method__} is deprecated (use the Voice API instead)."
142
+
143
+ post(@host, '/call/json', params)
144
+ end
145
+
146
+ def initiate_tts_call(params)
147
+ Kernel.warn "#{self.class}##{__method__} is deprecated (use the Voice API instead)."
148
+
149
+ post(@api_host, '/tts/json', params)
150
+ end
151
+
152
+ def initiate_tts_prompt_call(params)
153
+ Kernel.warn "#{self.class}##{__method__} is deprecated (use the Voice API instead)."
154
+
155
+ post(@api_host, '/tts-prompt/json', params)
156
+ end
157
+
158
+ def start_verification(params)
159
+ post(@api_host, '/verify/json', params)
160
+ end
161
+
162
+ def check_verification(request_id, params)
163
+ post(@api_host, '/verify/check/json', params.merge(request_id: request_id))
164
+ end
165
+
166
+ def get_verification(request_id)
167
+ get(@api_host, '/verify/search/json', request_id: request_id)
168
+ end
169
+
170
+ def cancel_verification(request_id)
171
+ post(@api_host, '/verify/control/json', request_id: request_id, cmd: 'cancel')
172
+ end
173
+
174
+ def trigger_next_verification_event(request_id)
175
+ post(@api_host, '/verify/control/json', request_id: request_id, cmd: 'trigger_next_event')
176
+ end
177
+
178
+ def get_basic_number_insight(params)
179
+ get(@api_host, '/ni/basic/json', params)
180
+ end
181
+
182
+ def get_standard_number_insight(params)
183
+ get(@api_host, '/ni/standard/json', params)
184
+ end
185
+
186
+ def get_advanced_number_insight(params)
187
+ get(@api_host, '/ni/advanced/json', params)
188
+ end
189
+
190
+ def get_advanced_async_number_insight(params)
191
+ get(@api_host, '/ni/advanced/async/json', params)
192
+ end
193
+
194
+ def request_number_insight(params)
195
+ post(@host, '/ni/json', params)
196
+ end
197
+
198
+ def get_applications(params = {})
199
+ get(@api_host, '/v1/applications', params)
200
+ end
201
+
202
+ def get_application(id)
203
+ get(@api_host, "/v1/applications/#{id}")
204
+ end
205
+
206
+ def create_application(params)
207
+ post(@api_host, '/v1/applications', params)
208
+ end
209
+
210
+ def update_application(id, params)
211
+ put(@api_host, "/v1/applications/#{id}", params)
212
+ end
213
+
214
+ def delete_application(id)
215
+ delete(@api_host, "/v1/applications/#{id}")
216
+ end
217
+
218
+ def create_call(params)
219
+ api_request(Net::HTTP::Post, '/v1/calls', params)
220
+ end
221
+
222
+ def get_calls(params = nil)
223
+ api_request(Net::HTTP::Get, '/v1/calls', params)
224
+ end
225
+
226
+ def get_call(uuid)
227
+ api_request(Net::HTTP::Get, "/v1/calls/#{uuid}")
228
+ end
229
+
230
+ def update_call(uuid, params)
231
+ api_request(Net::HTTP::Put, "/v1/calls/#{uuid}", params)
232
+ end
233
+
234
+ def send_audio(uuid, params)
235
+ api_request(Net::HTTP::Put, "/v1/calls/#{uuid}/stream", params)
236
+ end
237
+
238
+ def stop_audio(uuid)
239
+ api_request(Net::HTTP::Delete, "/v1/calls/#{uuid}/stream")
240
+ end
241
+
242
+ def send_speech(uuid, params)
243
+ api_request(Net::HTTP::Put, "/v1/calls/#{uuid}/talk", params)
244
+ end
245
+
246
+ def stop_speech(uuid)
247
+ api_request(Net::HTTP::Delete, "/v1/calls/#{uuid}/talk")
248
+ end
249
+
250
+ def send_dtmf(uuid, params)
251
+ api_request(Net::HTTP::Put, "/v1/calls/#{uuid}/dtmf", params)
252
+ end
253
+
254
+ def get_file(id)
255
+ api_request(Net::HTTP::Get, "/v1/files/#{id.split('/').last}")
256
+ end
257
+
258
+ def check_signature(params)
259
+ Signature.check(params, @signature_secret)
260
+ end
261
+
262
+ private
263
+
264
+ def get(host, request_uri, params = {})
265
+ uri = URI('https://' + host + request_uri)
266
+ uri.query = Params.encode(params.merge(api_key: @key, api_secret: @secret))
267
+
268
+ message = Net::HTTP::Get.new(uri.request_uri)
269
+
270
+ request(uri, message)
271
+ end
272
+
273
+ def post(host, request_uri, params)
274
+ uri = URI('https://' + host + request_uri)
275
+
276
+ message = Net::HTTP::Post.new(uri.request_uri)
277
+ message.form_data = params.merge(api_key: @key, api_secret: @secret)
278
+
279
+ request(uri, message)
280
+ end
281
+
282
+ def put(host, request_uri, params)
283
+ uri = URI('https://' + host + request_uri)
284
+
285
+ message = Net::HTTP::Put.new(uri.request_uri)
286
+ message['Content-Type'] = 'application/json'
287
+ message.body = JSON.generate(params.merge(api_key: @key, api_secret: @secret))
288
+
289
+ request(uri, message)
290
+ end
291
+
292
+ def delete(host, request_uri)
293
+ uri = URI('https://' + host + request_uri)
294
+ uri.query = Params.encode({api_key: @key, api_secret: @secret})
295
+
296
+ message = Net::HTTP::Delete.new(uri.request_uri)
297
+
298
+ request(uri, message)
299
+ end
300
+
301
+ def api_request(message_class, path, params = nil)
302
+ uri = URI('https://' + @api_host + path)
303
+
304
+ unless message_class::REQUEST_HAS_BODY || params.nil? || params.empty?
305
+ uri.query = Params.encode(params)
306
+ end
307
+
308
+ message = message_class.new(uri.request_uri)
309
+
310
+ if message_class::REQUEST_HAS_BODY
311
+ message['Content-Type'] = 'application/json'
312
+ message.body = JSON.generate(params)
313
+ end
314
+
315
+ token = auth_token || JWT.auth_token({application_id: @application_id}, @private_key)
316
+
317
+ message['Authorization'] = "Bearer #{token}"
318
+
319
+ request(uri, message)
320
+ end
321
+
322
+ def request(uri, message)
323
+ http = Net::HTTP.new(uri.host, Net::HTTP.https_default_port)
324
+ http.use_ssl = true
325
+
326
+ message['User-Agent'] = @user_agent
327
+
328
+ http_response = http.request(message)
329
+
330
+ case http_response
331
+ when Net::HTTPNoContent
332
+ :no_content
333
+ when Net::HTTPSuccess
334
+ if http_response['Content-Type'].split(';').first == 'application/json'
335
+ JSON.parse(http_response.body)
336
+ else
337
+ http_response.body
338
+ end
339
+ when Net::HTTPUnauthorized
340
+ raise AuthenticationError, "#{http_response.code} response from #{uri.host}"
341
+ when Net::HTTPClientError
342
+ raise ClientError, "#{http_response.code} response from #{uri.host}"
343
+ when Net::HTTPServerError
344
+ raise ServerError, "#{http_response.code} response from #{uri.host}"
345
+ else
346
+ raise Error, "#{http_response.code} response from #{uri.host}"
347
+ end
348
+ end
349
+ end
350
+ end
@@ -4,16 +4,14 @@ require 'jwt'
4
4
 
5
5
  module Nexmo
6
6
  module JWT
7
- def self.auth_header(payload, private_key)
8
- payload[:iat] = iat = Time.now.to_i
9
- payload[:exp] = iat + 60
10
- payload[:jti] = SecureRandom.uuid
7
+ def self.auth_token(payload, private_key)
8
+ payload[:iat] = iat = Time.now.to_i unless payload.key?(:iat) || payload.key?('iat')
9
+ payload[:exp] = iat + 60 unless payload.key?(:exp) || payload.key?('exp')
10
+ payload[:jti] = SecureRandom.uuid unless payload.key?(:jti) || payload.key?('jti')
11
11
 
12
12
  private_key = OpenSSL::PKey::RSA.new(private_key) unless private_key.respond_to?(:sign)
13
13
 
14
- token = ::JWT.encode(payload, private_key, 'RS256')
15
-
16
- "Bearer #{token}"
14
+ ::JWT.encode(payload, private_key, 'RS256')
17
15
  end
18
16
  end
19
17
  end
@@ -1,3 +1,3 @@
1
1
  module Nexmo
2
- VERSION = '4.5.0'
2
+ VERSION = '4.6.0'
3
3
  end
@@ -333,16 +333,6 @@ describe 'Nexmo::Client' do
333
333
  end
334
334
  end
335
335
 
336
- describe 'get_number_insight method' do
337
- it 'fetches the number lookup resource and returns the response object' do
338
- expect_get "#@api_base_url/number/lookup/json?api_key=#@api_key&api_secret=#@api_secret&number=447525856424"
339
-
340
- Kernel.stub :warn, proc { |message| message.must_match(/get_number_insight is deprecated/) } do
341
- @client.get_number_insight(number: '447525856424').must_equal(@response_object)
342
- end
343
- end
344
- end
345
-
346
336
  describe 'get_advanced_number_insight method' do
347
337
  it 'fetches the ni advanced resource and returns the response object' do
348
338
  expect_get "#@api_base_url/ni/advanced/json?api_key=#@api_key&api_secret=#@api_secret&number=447525856424"
@@ -485,6 +475,30 @@ describe 'Nexmo::Client' do
485
475
  end
486
476
  end
487
477
 
478
+ describe 'get_file method' do
479
+ before do
480
+ @url = "#@api_base_url/v1/files/xx-xx-xx-xx"
481
+
482
+ @request_headers = {'Authorization' => /\ABearer (.+)\.(.+)\.(.+)\z/}
483
+
484
+ @response_body = 'BODY'
485
+
486
+ @response = {body: @response_body, headers: {'Content-Type' => 'application/octet-stream'}}
487
+ end
488
+
489
+ it 'fetches the file resource with the given id and returns the response body' do
490
+ @request = stub_request(:get, @url).with(headers: @request_headers).to_return(@response)
491
+
492
+ @client.get_file('xx-xx-xx-xx').must_equal(@response_body)
493
+ end
494
+
495
+ it 'fetches the file resource with the given url and returns the response body' do
496
+ @request = stub_request(:get, @url).with(headers: @request_headers).to_return(@response)
497
+
498
+ @client.get_file(@url).must_equal(@response_body)
499
+ end
500
+ end
501
+
488
502
  describe 'check_signature method' do
489
503
  it 'returns true if the signature in the given params is correct' do
490
504
  params = {'a' => '1', 'b' => '2', 'timestamp' => '1461605396', 'sig' => '6af838ef94998832dbfc29020b564830'}
@@ -513,6 +527,18 @@ describe 'Nexmo::Client' do
513
527
  proc { @client.get_balance }.must_raise(Nexmo::ServerError)
514
528
  end
515
529
 
530
+ it 'provides an accessor to set the authorization token' do
531
+ auth_token = 'auth_token_xxx'
532
+
533
+ headers = {'Authorization' => "Bearer #{auth_token}"}
534
+
535
+ @request = stub_request(:get, "#@api_base_url/v1/calls").with(headers: headers).to_return(@response_body)
536
+
537
+ @client.auth_token = auth_token
538
+
539
+ @client.get_calls
540
+ end
541
+
516
542
  it 'includes a user-agent header with the library version number and ruby version number' do
517
543
  headers = {'User-Agent' => "nexmo-ruby/#{Nexmo::VERSION} ruby/#{RUBY_VERSION}"}
518
544
 
@@ -582,7 +608,7 @@ describe 'Nexmo::Client' do
582
608
  def expect_put(url, data)
583
609
  body = WebMock::Util::QueryMapper.query_to_values(data)
584
610
 
585
- headers = {'Content-Type' => 'application/x-www-form-urlencoded'}
611
+ headers = {'Content-Type' => 'application/json'}
586
612
 
587
613
  @request = stub_request(:put, url).with(body: body, headers: headers).to_return(@response_body)
588
614
  end
@@ -0,0 +1,53 @@
1
+ require 'minitest/autorun'
2
+ require 'nexmo'
3
+
4
+ describe 'Nexmo::JWT' do
5
+ describe 'auth_token method' do
6
+ it 'returns the payload encoded with the private key' do
7
+ time = Time.now.to_i
8
+
9
+ payload = {
10
+ 'application_id' => application_id,
11
+ 'iat' => time,
12
+ 'exp' => time + 3600,
13
+ 'jti' => 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
14
+ }
15
+
16
+ encoded_token = Nexmo::JWT.auth_token(payload, private_key)
17
+
18
+ decode(encoded_token).must_equal(payload)
19
+ end
20
+
21
+ it 'sets a default value for the iat parameter' do
22
+ encoded_token = Nexmo::JWT.auth_token({}, private_key)
23
+
24
+ decode(encoded_token).fetch('iat').must_be_kind_of(Integer)
25
+ end
26
+
27
+ it 'sets a default value for the exp parameter' do
28
+ encoded_token = Nexmo::JWT.auth_token({}, private_key)
29
+
30
+ decode(encoded_token).fetch('exp').must_be_kind_of(Integer)
31
+ end
32
+
33
+ it 'sets a default value for the jti parameter' do
34
+ encoded_token = Nexmo::JWT.auth_token({}, private_key)
35
+
36
+ decode(encoded_token).fetch('jti').must_match(/\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/)
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def decode(encoded_token)
43
+ JWT.decode(encoded_token, private_key, 'RS256').first
44
+ end
45
+
46
+ def application_id
47
+ @application_id ||= SecureRandom.uuid
48
+ end
49
+
50
+ def private_key
51
+ @private_key ||= OpenSSL::PKey::RSA.new(1024)
52
+ end
53
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nexmo
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.5.0
4
+ version: 4.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Craft
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-06 00:00:00.000000000 Z
11
+ date: 2017-04-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jwt
@@ -76,6 +76,7 @@ files:
76
76
  - LICENSE.txt
77
77
  - README.md
78
78
  - lib/nexmo.rb
79
+ - lib/nexmo/client.rb
79
80
  - lib/nexmo/errors/authentication_error.rb
80
81
  - lib/nexmo/errors/client_error.rb
81
82
  - lib/nexmo/errors/error.rb
@@ -85,7 +86,8 @@ files:
85
86
  - lib/nexmo/signature.rb
86
87
  - lib/nexmo/version.rb
87
88
  - nexmo.gemspec
88
- - spec/nexmo_spec.rb
89
+ - spec/nexmo/client_spec.rb
90
+ - spec/nexmo/jwt_spec.rb
89
91
  homepage: https://github.com/Nexmo/nexmo-ruby
90
92
  licenses:
91
93
  - MIT