nexmo 4.5.0 → 4.6.0

Sign up to get free protection for your applications and to get access to all the features.
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