plivo 4.6.1 → 4.9.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: 4d52c001b00cc47d25bea87d44a4ce09ae8f922f
4
- data.tar.gz: 7938d6bd6d1d1d1612dd455132de25006c3fd30f
3
+ metadata.gz: bb94696da06990a70578e5b44e4eb14df13ff9ab
4
+ data.tar.gz: c8d2d47ddd432b5f15adc75a8fc09d3c0c8f7a82
5
5
  SHA512:
6
- metadata.gz: f886ee8aa69fe4228c300a4476082ba0c05e4e179972b33768d1a73f9ece04b5e071d3f6005510c17e92335e8c9bec97929e22a0253e8fe50bbecac6b166a096
7
- data.tar.gz: c3f02372894c4de3be0617b7c9727f54a9f681722c86e164212aba1585850d2f3568f9eca75ef038430e2d3ef186d4eea30b5453cc1700d8618de0c2aa7d05d8
6
+ metadata.gz: 1a08ee7057cae689aedd2608b23a2fc5184a94ac13786b9a43a47d588e8d987c86ad2a4a86487826a0f8056e0fcd44a2e362d38fb806c95b9ba4ac11751a068c
7
+ data.tar.gz: 1b8e9f01eaf93503fca9924c045455c7c18500d2a3e081259b3d6175e36ab33ae2f14d7b12ba4445d3c0c4920a457ef798ae6672fa1a1918047b21a0250acc88
@@ -1,5 +1,20 @@
1
1
  # Change Log
2
2
 
3
+ ## [4.9.0](https://github.com/plivo/plivo-ruby/releases/tag/v4.9.0) (2020-07-23)
4
+ - Add retries to multiple regions for voice requests.
5
+
6
+ ## [4.8.1](https://github.com/plivo/plivo-ruby/releases/tag/v4.8.1) (2020-06-05)
7
+ - Fix Record a Conference API response.
8
+
9
+ ## [4.8.0](https://github.com/plivo/plivo-ruby/releases/tag/v4.8.0) (2020-05-28)
10
+ - Add JWT helper functions.
11
+
12
+ ## [4.7.1](https://github.com/plivo/plivo-ruby/releases/tag/v4.7.1) (2020-05-06)
13
+ - Fix Send MMS with existing media_ids.
14
+
15
+ ## [4.7.0](https://github.com/plivo/plivo-ruby/releases/tag/v4.7.0) (2020-04-29)
16
+ - Add V3 signature helper functions.
17
+
3
18
  ## [4.6.1](https://github.com/plivo/plivo-ruby/releases/tag/v4.6.1) (2020-04-02)
4
19
  - Add nil check for API requests.
5
20
 
data/README.md CHANGED
@@ -8,7 +8,7 @@ The Plivo Ruby SDK makes it simpler to integrate communications into your Ruby a
8
8
  Add this line to your application's Gemfile:
9
9
 
10
10
  ```ruby
11
- gem 'plivo', '>= 4.6.1'
11
+ gem 'plivo', '>= 4.9.0'
12
12
  ```
13
13
 
14
14
  And then execute:
@@ -0,0 +1,32 @@
1
+ require 'rubygems'
2
+ require 'plivo'
3
+
4
+ include Plivo
5
+
6
+ AUTH_ID = 'MADADADADADADADADADA'
7
+ AUTH_TOKEN = 'AUTH_TOKEN'
8
+
9
+ begin
10
+ acctkn = Plivo::Token::AccessToken.new(
11
+ AUTH_ID,
12
+ AUTH_TOKEN,
13
+ '{username}',
14
+ '{uid}'
15
+ )
16
+ # update token validity (from, lifetime)
17
+ acctkn.update_validity(Time.now, 300)
18
+ # add voice grants (incoming, outgoing)
19
+ acctkn.add_voice_grants(Plivo::Token::VoiceGrants.new(true, true))
20
+ puts acctkn.to_jwt
21
+
22
+ # update token validity (from, nil, till)
23
+ acctkn.update_validity(Time.now, nil, Time.now + 300)
24
+ # add voice grants (incoming, outgoing)
25
+ acctkn.add_voice_grants(Plivo::Token::VoiceGrants.new(true, true))
26
+ puts acctkn.to_jwt
27
+ rescue ValidationError => e
28
+ puts 'Exception: ' + e.message
29
+ end
30
+
31
+ # Sample Response:
32
+ #
@@ -5,6 +5,7 @@ require_relative 'plivo/base'
5
5
  require_relative 'plivo/resources'
6
6
  require_relative 'plivo/rest_client'
7
7
  require_relative 'plivo/xml'
8
+ require_relative 'plivo/jwt'
8
9
  require_relative 'plivo/phlo_client'
9
10
  require_relative 'plivo/base_client'
10
11
 
@@ -5,6 +5,11 @@ require_relative 'base/response'
5
5
  module Plivo
6
6
  module Base
7
7
  PLIVO_API_URL = 'https://api.plivo.com'.freeze
8
+
9
+ API_VOICE = 'https://voice.plivo.com'.freeze
10
+ API_VOICE_FALLBACK_1 = 'https://voice-usw1.plivo.com'.freeze
11
+ API_VOICE_FALLBACK_2 = 'https://voice-use1.plivo.com'.freeze
12
+
8
13
  CALLINSIGHTS_API_URL = 'https://stats.plivo.com'.freeze
9
14
  PHLO_API_URL = 'https://phlorunner.plivo.com'.freeze
10
15
  end
@@ -8,6 +8,7 @@ module Plivo
8
8
  configure_client(client)
9
9
  configure_options(options) if options
10
10
  configure_resource_uri
11
+ @_is_voice_request = false
11
12
  end
12
13
 
13
14
  private
@@ -56,7 +57,7 @@ module Plivo
56
57
  'without an identifier')
57
58
  end
58
59
 
59
- response_json = @_client.send_request(@_resource_uri, 'POST', params, nil, use_multipart_conn)
60
+ response_json = @_client.send_request(@_resource_uri, 'POST', params, nil, use_multipart_conn, is_voice_request: @_is_voice_request)
60
61
 
61
62
  parse_and_set(params)
62
63
  parse_and_set(response_json)
@@ -65,7 +66,7 @@ module Plivo
65
66
 
66
67
  def perform_action(action = nil, method = 'GET', params = nil, parse = false)
67
68
  resource_path = action ? @_resource_uri + action + '/' : @_resource_uri
68
- response = @_client.send_request(resource_path, method, params)
69
+ response = @_client.send_request(resource_path, method, params,nil,false,is_voice_request: @_is_voice_request)
69
70
  parse ? parse_and_set(response) : self
70
71
  method == 'POST' ? parse_and_set(params) : self
71
72
  self
@@ -73,7 +74,7 @@ module Plivo
73
74
 
74
75
  def perform_custome_action(action = nil, method = 'GET', params = nil, parse = false)
75
76
  resource_path = action ? @_resource_uri + action + '/' : @_resource_uri
76
- response = @_client.send_request(resource_path, method, params)
77
+ response = @_client.send_request(resource_path, method, params,nil,false,is_voice_request: @_is_voice_request)
77
78
  parse ? parse_and_set(response) : self
78
79
  method == 'POST' ? parse_and_set(params) : self
79
80
  self
@@ -81,7 +82,7 @@ module Plivo
81
82
 
82
83
  def perform_action_apiresponse(action = nil, method = 'GET', params = nil, parse = false)
83
84
  resource_path = action ? @_resource_uri + action + '/' : @_resource_uri
84
- response = @_client.send_request(resource_path, method, params)
85
+ response = @_client.send_request(resource_path, method, params,nil,false,is_voice_request: @_is_voice_request)
85
86
  parse ? parse_and_set(response) : self
86
87
  method == 'POST' ? parse_and_set(params) : self
87
88
  method == 'DELETE' ? parse_and_set(params) : self
@@ -90,7 +91,7 @@ module Plivo
90
91
 
91
92
  def perform_custom_action_apiresponse(action = nil, method = 'GET', params = nil, parse = false)
92
93
  resource_path = action ? '/v1/Account/' + @_client.auth_id + '/'+ action + '/' : @_resource_uri
93
- response = @_client.send_request(resource_path, method, params)
94
+ response = @_client.send_request(resource_path, method, params,nil,false,is_voice_request: @_is_voice_request)
94
95
  parse ? parse_and_set(response) : self
95
96
  method == 'POST' ? parse_and_set(params) : self
96
97
  method == 'DELETE' ? parse_and_set(params) : self
@@ -103,12 +104,12 @@ module Plivo
103
104
  'without an identifier')
104
105
  end
105
106
 
106
- Response.new(@_client.send_request(@_resource_uri, 'DELETE', params),
107
+ Response.new(@_client.send_request(@_resource_uri, 'DELETE', params, nil, false, is_voice_request: @_is_voice_request),
107
108
  @_identifier_string)
108
109
  end
109
110
 
110
111
  def perform_run(params)
111
- response_json = @_client.send_request(@_resource_uri, 'POST', params, nil)
112
+ response_json = @_client.send_request(@_resource_uri, 'POST', params, nil,false,is_voice_request: @_is_voice_request)
112
113
  parse_and_set(response_json)
113
114
  Response.new(response_json, @_identifier_string)
114
115
  end
@@ -6,6 +6,7 @@ module Plivo
6
6
  configure_client(client)
7
7
  configure_resource_uri
8
8
  parse_and_set(resource_list_json) if resource_list_json
9
+ @_is_voice_request = false
9
10
  end
10
11
 
11
12
  private
@@ -41,25 +42,25 @@ module Plivo
41
42
 
42
43
  def perform_get(identifier, params = nil)
43
44
  valid_param?(:identifier, identifier, [String, Symbol], true)
44
- response_json = @_client.send_request(@_resource_uri + identifier.to_s + '/', 'GET', params)
45
+ response_json = @_client.send_request(@_resource_uri + identifier.to_s + '/', 'GET', params, nil, false, is_voice_request: @_is_voice_request)
45
46
  @_resource_type.new(@_client, resource_json: response_json)
46
47
  end
47
48
 
48
49
  def perform_get_without_identifier(params)
49
50
  valid_param?(:params, params, Hash, true)
50
- response_json = @_client.send_request(@_resource_uri, 'GET', params)
51
+ response_json = @_client.send_request(@_resource_uri, 'GET', params, nil, false, is_voice_request: @_is_voice_request)
51
52
  @_resource_type.new(@_client, resource_json: response_json)
52
53
  end
53
54
 
54
55
  def perform_create(params, use_multipart_conn=false)
55
56
  Response.new(
56
- @_client.send_request(@_resource_uri, 'POST', params, nil, use_multipart_conn),
57
+ @_client.send_request(@_resource_uri, 'POST', params, nil, use_multipart_conn, is_voice_request: @_is_voice_request),
57
58
  @_identifier_string
58
59
  )
59
60
  end
60
61
 
61
62
  def perform_post(params)
62
- response_json = @_client.send_request(@_resource_uri, 'POST', params)
63
+ response_json = @_client.send_request(@_resource_uri, 'POST', params, nil, false, is_voice_request: @_is_voice_request)
63
64
 
64
65
  parse_and_set(response_json)
65
66
  self
@@ -74,7 +75,7 @@ module Plivo
74
75
  end
75
76
 
76
77
  def perform_list(params = nil)
77
- response_json = @_client.send_request(@_resource_uri, 'GET', params)
78
+ response_json = @_client.send_request(@_resource_uri, 'GET', params, nil, false, is_voice_request: @_is_voice_request)
78
79
  parse_and_set(response_json)
79
80
  {
80
81
  api_id: @api_id,
@@ -85,14 +86,14 @@ module Plivo
85
86
 
86
87
  def perform_action(action = nil, method = 'GET', params = nil, parse = false)
87
88
  resource_path = action ? @_resource_uri + action + '/' : @_resource_uri
88
- response = @_client.send_request(resource_path, method, params)
89
+ response = @_client.send_request(resource_path, method, params, nil, false, is_voice_request: @_is_voice_request)
89
90
  parse ? parse_and_set(response) : self
90
91
  method == 'POST' ? parse_and_set(params) : self
91
92
  self
92
93
  end
93
94
 
94
95
  def perform_list_without_object(params = nil)
95
- response_json = @_client.send_request(@_resource_uri, 'GET', params)
96
+ response_json = @_client.send_request(@_resource_uri, 'GET', params, nil, false, is_voice_request: @_is_voice_request)
96
97
  parse_and_set(response_json)
97
98
  response_json
98
99
  end
@@ -13,7 +13,7 @@ module Plivo
13
13
  class BaseClient
14
14
  # Base stuff
15
15
  attr_reader :headers, :auth_credentials
16
-
16
+ @@voice_retry_count = 0
17
17
  def initialize(auth_id = nil, auth_token = nil, proxy_options = nil, timeout=5)
18
18
  configure_credentials(auth_id, auth_token)
19
19
  configure_proxies(proxy_options)
@@ -36,21 +36,42 @@ module Plivo
36
36
  elsif !([200, 201, 202, 207].include? response[:status])
37
37
  raise Exceptions::PlivoRESTError, "Received #{response[:status]} for #{method}"
38
38
  end
39
-
39
+ @@voice_retry_count = 0
40
40
  response[:body]
41
41
  end
42
42
 
43
- def send_request(resource_path, method = 'GET', data = {}, timeout = nil, use_multipart_conn = false)
43
+ def send_request(resource_path, method = 'GET', data = {}, timeout = nil, use_multipart_conn = false, options = nil)
44
44
  timeout ||= @timeout
45
45
 
46
- response = case method
47
- when 'GET' then send_get(resource_path, data, timeout)
48
- when 'POST' then send_post(resource_path, data, timeout, use_multipart_conn)
49
- when 'DELETE' then send_delete(resource_path, data, timeout)
50
- else raise_invalid_request("#{method} not supported by Plivo, yet")
51
- end
46
+ if options[:is_voice_request] == true
47
+ response = case method
48
+ when 'GET' then send_get(resource_path, data, timeout, is_voice_request: options[:is_voice_request], voice_retry_count: @@voice_retry_count)
49
+ when 'POST' then send_post(resource_path, data, timeout, use_multipart_conn, is_voice_request: options[:is_voice_request], voice_retry_count: @@voice_retry_count)
50
+ when 'DELETE' then send_delete(resource_path, data, timeout, is_voice_request: options[:is_voice_request], voice_retry_count: @@voice_retry_count)
51
+ else raise_invalid_request("#{method} not supported by Plivo, yet")
52
+ end
53
+
54
+ if response.status >= 500
55
+ @@voice_retry_count += 1
56
+ if @@voice_retry_count > 2
57
+ return process_response(method, response.to_hash)
58
+ end
59
+ is_voice_request = true
60
+ send_request(resource_path, method, data, timeout, use_multipart_conn, is_voice_request: is_voice_request)
61
+ else
62
+ process_response(method, response.to_hash)
63
+ end
52
64
 
53
- process_response(method, response.to_hash)
65
+ else
66
+ response = case method
67
+ when 'GET' then send_get(resource_path, data, timeout)
68
+ when 'POST' then send_post(resource_path, data, timeout, use_multipart_conn)
69
+ when 'DELETE' then send_delete(resource_path, data, timeout)
70
+ else raise_invalid_request("#{method} not supported by Plivo, yet")
71
+ end
72
+
73
+ process_response(method, response.to_hash)
74
+ end
54
75
  end
55
76
 
56
77
  private
@@ -118,6 +139,45 @@ module Plivo
118
139
  faraday.adapter Faraday.default_adapter
119
140
  end
120
141
 
142
+ @voice_conn_no_retry = Faraday.new(@voice_base_uri) do |faraday|
143
+ faraday.headers = @headers
144
+
145
+ # DANGER: Basic auth should always come after headers, else
146
+ # The headers will replace the basic_auth
147
+
148
+ faraday.basic_auth(auth_id, auth_token)
149
+
150
+ faraday.proxy=@proxy_hash if @proxy_hash
151
+ faraday.response :json, content_type: /\bjson$/
152
+ faraday.adapter Faraday.default_adapter
153
+ end
154
+
155
+ @voice_conn_retry_1 = Faraday.new(@voice_base_uri_fallback_1) do |faraday|
156
+ faraday.headers = @headers
157
+
158
+ # DANGER: Basic auth should always come after headers, else
159
+ # The headers will replace the basic_auth
160
+
161
+ faraday.basic_auth(auth_id, auth_token)
162
+
163
+ faraday.proxy=@proxy_hash if @proxy_hash
164
+ faraday.response :json, content_type: /\bjson$/
165
+ faraday.adapter Faraday.default_adapter
166
+ end
167
+
168
+ @voice_conn_retry_2 = Faraday.new(@voice_base_uri_fallback_2) do |faraday|
169
+ faraday.headers = @headers
170
+
171
+ # DANGER: Basic auth should always come after headers, else
172
+ # The headers will replace the basic_auth
173
+
174
+ faraday.basic_auth(auth_id, auth_token)
175
+
176
+ faraday.proxy=@proxy_hash if @proxy_hash
177
+ faraday.response :json, content_type: /\bjson$/
178
+ faraday.adapter Faraday.default_adapter
179
+ end
180
+
121
181
  @callinsights_conn = Faraday.new(@callinsights_base_uri) do |faraday|
122
182
  faraday.headers = @headers
123
183
 
@@ -133,15 +193,34 @@ module Plivo
133
193
 
134
194
  end
135
195
 
136
- def send_get(resource_path, data, timeout)
137
- response = @conn.get do |req|
138
- req.url resource_path, data
139
- req.options.timeout = timeout if timeout
196
+ def send_get(resource_path, data, timeout, options = nil)
197
+ if options
198
+ if options[:voice_retry_count] == 0 and options[:is_voice_request] == true
199
+ response = @voice_conn_no_retry.get do |req|
200
+ req.url resource_path, data
201
+ req.options.timeout = timeout if timeout
202
+ end
203
+ elsif options[:voice_retry_count] == 1 and options[:is_voice_request] == true
204
+ response = @voice_conn_retry_1.get do |req|
205
+ req.url resource_path, data
206
+ req.options.timeout = timeout if timeout
207
+ end
208
+ elsif options[:voice_retry_count] == 2 and options[:is_voice_request] == true
209
+ response = @voice_conn_retry_2.get do |req|
210
+ req.url resource_path, data
211
+ req.options.timeout = timeout if timeout
212
+ end
213
+ end
214
+ else
215
+ response = @conn.get do |req|
216
+ req.url resource_path, data
217
+ req.options.timeout = timeout if timeout
218
+ end
140
219
  end
141
220
  response
142
221
  end
143
222
 
144
- def send_post(resource_path, data, timeout, use_multipart_conn)
223
+ def send_post(resource_path, data, timeout, use_multipart_conn, options = nil)
145
224
  if use_multipart_conn
146
225
  multipart_conn = Faraday.new(@base_uri) do |faraday|
147
226
  faraday.headers = {
@@ -178,7 +257,26 @@ module Plivo
178
257
  req.options.timeout = timeout if timeout
179
258
  req.body = JSON.generate(data) if data
180
259
  end
181
-
260
+ elsif options
261
+ if options[:voice_retry_count] == 0 and options[:is_voice_request] == true
262
+ response = @voice_conn_no_retry.post do |req|
263
+ req.url resource_path
264
+ req.options.timeout = timeout if timeout
265
+ req.body = JSON.generate(data) if data
266
+ end
267
+ elsif options[:voice_retry_count] == 1 and options[:is_voice_request] == true
268
+ response = @voice_conn_retry_1.post do |req|
269
+ req.url resource_path
270
+ req.options.timeout = timeout if timeout
271
+ req.body = JSON.generate(data) if data
272
+ end
273
+ elsif options[:voice_retry_count] == 2 and options[:is_voice_request] == true
274
+ response = @voice_conn_retry_2.post do |req|
275
+ req.url resource_path
276
+ req.options.timeout = timeout if timeout
277
+ req.body = JSON.generate(data) if data
278
+ end
279
+ end
182
280
  else
183
281
  response = @conn.post do |req|
184
282
  req.url resource_path
@@ -190,11 +288,33 @@ module Plivo
190
288
  response
191
289
  end
192
290
 
193
- def send_delete(resource_path, data, timeout)
194
- response = @conn.delete do |req|
195
- req.url resource_path
196
- req.options.timeout = timeout if timeout
197
- req.body = JSON.generate(data) if data
291
+ def send_delete(resource_path, data, timeout, options = nil)
292
+ if options
293
+ if options[:voice_retry_count] == 0 and options[:is_voice_request] == true
294
+ response = @voice_conn_no_retry.delete do |req|
295
+ req.url resource_path
296
+ req.options.timeout = timeout if timeout
297
+ req.body = JSON.generate(data) if data
298
+ end
299
+ elsif options[:voice_retry_count] == 1 and options[:is_voice_request] == true
300
+ response = @voice_conn_retry_1.delete do |req|
301
+ req.url resource_path
302
+ req.options.timeout = timeout if timeout
303
+ req.body = JSON.generate(data) if data
304
+ end
305
+ elsif options[:voice_retry_count] == 2 and options[:is_voice_request] == true
306
+ response = @voice_conn_retry_2.delete do |req|
307
+ req.url resource_path
308
+ req.options.timeout = timeout if timeout
309
+ req.body = JSON.generate(data) if data
310
+ end
311
+ end
312
+ else
313
+ response = @conn.delete do |req|
314
+ req.url resource_path
315
+ req.options.timeout = timeout if timeout
316
+ req.body = JSON.generate(data) if data
317
+ end
198
318
  end
199
319
  response
200
320
  end
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openssl'
4
+ require 'uri'
5
+ require 'base64'
6
+ require 'date'
7
+ require 'jwt'
8
+
9
+ module Plivo
10
+ module Token
11
+ include Utils
12
+
13
+ class VoiceGrants
14
+ attr_reader :incoming_allow, :outgoing_allow
15
+
16
+ def initialize(incoming = nil, outgoing = nil)
17
+ Utils.valid_param?(:incoming, incoming, [TrueClass, FalseClass], false)
18
+ Utils.valid_param?(:outgoing, outgoing, [TrueClass, FalseClass], false)
19
+ @incoming_allow = incoming
20
+ @outgoing_allow = outgoing
21
+ end
22
+
23
+ def to_hash
24
+ hash = {}
25
+ instance_variables.each { |var| hash[var.to_s.delete('@')] = instance_variable_get(var) }
26
+ hash
27
+ end
28
+ end
29
+
30
+ class AccessToken
31
+ attr_reader :uid, :username, :valid_from, :lifetime, :grants
32
+ def initialize(auth_id = nil, auth_token = nil, username = nil, uid = nil)
33
+ configure_credentials(auth_id, auth_token)
34
+ Utils.valid_param?(:username, username, [String, Symbol], true)
35
+ @username = username
36
+
37
+ Utils.valid_param?(:uid, uid, [String, Symbol], false)
38
+ uid ||= username + '-' + Time.now.to_i
39
+ @uid = uid
40
+ update_validity
41
+ end
42
+
43
+ def update_validity(valid_from = nil, lifetime = nil, valid_till = nil)
44
+ Utils.valid_param?(:valid_from, valid_from, [Time, Integer], false)
45
+ Utils.valid_param?(:lifetime, lifetime, [Integer], false)
46
+ Utils.valid_param?(:valid_till, valid_till, [Time, Integer], false)
47
+
48
+ if valid_from.nil?
49
+ @lifetime = lifetime || 84_600
50
+ @valid_from = if valid_till.nil?
51
+ Time.now
52
+ else
53
+ Time.at(valid_till.to_i - @lifetime).utc
54
+ end
55
+
56
+ elsif valid_till.nil?
57
+ @lifetime = lifetime || 84_600
58
+ @valid_from = valid_from
59
+ else
60
+ unless lifetime.nil?
61
+ raise Exceptions::ValidationError, 'use any 2 of valid_from, lifetime and valid_till'
62
+ end
63
+
64
+ @valid_from = valid_from
65
+ @lifetime = valid_till.to_i - valid_from.to_i
66
+ end
67
+
68
+ return unless @lifetime < 180 || @lifetime > 84_600
69
+
70
+ raise Exceptions::ValidationError, 'validity out of [180, 84600] seconds'
71
+ end
72
+
73
+ def auth_id
74
+ @auth_credentials[:auth_id]
75
+ end
76
+
77
+ def add_voice_grants(grants)
78
+ Utils.valid_param?(:grants, grants, [VoiceGrants], true)
79
+ @grants = grants
80
+ end
81
+
82
+ def to_jwt
83
+ payload = {
84
+ jti: uid,
85
+ sub: username,
86
+ iss: auth_id,
87
+ nbf: valid_from.to_i,
88
+ exp: valid_from.to_i + lifetime,
89
+ grants: {
90
+ voice: grants.to_hash || {}
91
+ }
92
+ }
93
+ JWT.encode payload, key, 'HS256', {typ: 'JWT', cty: 'plivo;v=1'}
94
+ end
95
+
96
+ private
97
+
98
+ def key
99
+ @auth_credentials[:auth_token]
100
+ end
101
+
102
+ def configure_credentials(auth_id, auth_token)
103
+ # Fetches and sets the right credentials
104
+ auth_id ||= ENV['PLIVO_AUTH_ID']
105
+ auth_token ||= ENV['PLIVO_AUTH_TOKEN']
106
+
107
+ raise Exceptions::AuthenticationError, 'Couldn\'t find auth credentials' unless
108
+ auth_id && auth_token
109
+
110
+ raise Exceptions::AuthenticationError, "Invalid auth_id: '#{auth_id}'" unless
111
+ Utils.valid_account?(auth_id)
112
+
113
+ @auth_credentials = {
114
+ auth_id: auth_id,
115
+ auth_token: auth_token
116
+ }
117
+ end
118
+ end
119
+ end
120
+ end
@@ -8,6 +8,7 @@ module Plivo
8
8
  @_name = 'Application'
9
9
  @_identifier_string = 'app_id'
10
10
  super
11
+ @_is_voice_request = true
11
12
  end
12
13
 
13
14
  # @param [Hash] options
@@ -109,6 +110,7 @@ module Plivo
109
110
  @_resource_type = Application
110
111
  @_identifier_string = 'app_id'
111
112
  super
113
+ @_is_voice_request = true
112
114
  end
113
115
 
114
116
  # @param [String] app_id
@@ -6,6 +6,7 @@ module Plivo
6
6
  @_name = 'Call'
7
7
  @_identifier_string = 'call_uuid'
8
8
  super
9
+ @_is_voice_request = true
9
10
  end
10
11
 
11
12
  def update(options)
@@ -199,7 +200,7 @@ module Plivo
199
200
 
200
201
  def cancel_request
201
202
  resource_path = @_resource_uri.sub('Call', 'Request')
202
- @_client.send_request(resource_path, 'DELETE', nil)
203
+ @_client.send_request(resource_path, 'DELETE', nil, nil, false , is_voice_request: @_is_voice_request)
203
204
  end
204
205
 
205
206
  def to_s
@@ -240,6 +241,7 @@ module Plivo
240
241
  @_resource_type = Call
241
242
  @_identifier_string = 'call_uuid'
242
243
  super
244
+ @_is_voice_request = true
243
245
  end
244
246
 
245
247
  ##
@@ -288,9 +290,9 @@ module Plivo
288
290
  answer_method: answer_method
289
291
  }
290
292
 
291
- return perform_create(params) if options.nil?
293
+ return perform_create(params, false) if options.nil?
292
294
 
293
- perform_create(params.merge(options))
295
+ perform_create(params.merge(options), false)
294
296
  end
295
297
 
296
298
  ##
@@ -6,6 +6,7 @@ module Plivo
6
6
  @_name = 'Conference'
7
7
  @_identifier_string = 'conference_name'
8
8
  super
9
+ @_is_voice_request = true
9
10
  end
10
11
 
11
12
  def delete
@@ -186,18 +187,12 @@ module Plivo
186
187
  end
187
188
 
188
189
  def to_s
189
- unless @members.nil?
190
- members_json = @members.map do |member|
191
- JSON.parse(to_json_member(member))
192
- end
190
+ response_json = {}
191
+ response_variables = self.instance_variables.drop(5)
192
+ response_variables.each do |variable|
193
+ response_json[variable.to_s[1..-1]] = self.instance_variable_get(variable)
193
194
  end
194
- {
195
- conference_name: @conference_name,
196
- conference_run_time: @conference_run_time,
197
- conference_member_count: @conference_member_count,
198
- members: members_json,
199
- api_id: @api_id
200
- }.to_s
195
+ return response_json.to_s
201
196
  end
202
197
 
203
198
  def to_json_member(member)
@@ -221,6 +216,7 @@ module Plivo
221
216
  @_resource_type = Conference
222
217
  @_identifier_string = 'conference_name'
223
218
  super
219
+ @_is_voice_request = true
224
220
  end
225
221
 
226
222
  def get(conference_name)
@@ -6,6 +6,7 @@ module Plivo
6
6
  @_name = 'Endpoint'
7
7
  @_identifier_string = 'endpoint_id'
8
8
  super
9
+ @_is_voice_request = true
9
10
  end
10
11
 
11
12
  # @param [Hash] options
@@ -71,6 +72,7 @@ module Plivo
71
72
  @_resource_type = Endpoint
72
73
  @_identifier_string = 'endpoint_id'
73
74
  super
75
+ @_is_voice_request = true
74
76
  end
75
77
 
76
78
  # @param [String] endpoint_id
@@ -69,6 +69,7 @@ module Plivo
69
69
  # @option options [String] :log If set to false, the content of this message will not be logged on the Plivo infrastructure and the dst value will be masked (e.g., 141XXXXX528). Default is set to true.
70
70
  # @option options [String] :trackable set to false
71
71
  #@option options[List]: media_urls Minimum one media url should be present in Media urls list to send mms. Maximum allowd 10 media urls inside the list (e.g, media_urls : ['https//example.com/test.jpg', 'https://example.com/abcd.gif'])
72
+ #@option options[List]: media_ids Minimum one media ids should be present in Media ids list to send mms. Maximum allowd 10 media ids inside the list (e.g, media_ids : ['1fs211ba-355b-11ea-bbc9-02121c1190q7'])
72
73
 
73
74
  def create(src, dst, text = nil, options = nil, powerpack_uuid = nil)
74
75
  valid_param?(:src, src, [Integer, String, Symbol], false)
@@ -130,6 +131,10 @@ module Plivo
130
131
  valid_param?(:media_urls, options[:media_urls], Array, true)
131
132
  params[:media_urls] = options[:media_urls]
132
133
  end
134
+ if options.key?(:media_ids) &&
135
+ valid_param?(:media_ids, options[:media_ids], Array, true)
136
+ params[:media_ids] = options[:media_ids]
137
+ end
133
138
  perform_create(params)
134
139
  end
135
140
 
@@ -148,6 +153,7 @@ module Plivo
148
153
  # @option options [Int] :offset Denotes the number of value items by which the results should be offset. Eg:- If the result contains a 1000 values and limit is set to 10 and offset is set to 705, then values 706 through 715 are displayed in the results. This parameter is also used for pagination of the results.
149
154
  # @option options [String] :error_code Delivery Response code returned by the carrier attempting the delivery. See Supported error codes {https://www.plivo.com/docs/api/message/#standard-plivo-error-codes}.
150
155
  #@option options[List]: media_urls Minimum one media url should be present in Media urls list to send mms. Maximum allowd 10 media urls inside the list (e.g, media_urls : ['https//example.com/test.jpg', 'https://example.com/abcd.gif'])
156
+ #@option options[List]: media_ids Minimum one media ids should be present in Media ids list to send mms. Maximum allowd 10 media ids inside the list (e.g, media_ids : ['1fs211ba-355b-11ea-bbc9-02121c1190q7'])
151
157
  def list(options = nil)
152
158
  return perform_list if options.nil?
153
159
  valid_param?(:options, options, Hash, true)
@@ -6,6 +6,7 @@ module Plivo
6
6
  @_name = 'Recording'
7
7
  @_identifier_string = 'recording_id'
8
8
  super
9
+ @_is_voice_request = true
9
10
  end
10
11
 
11
12
  def delete
@@ -36,6 +37,7 @@ module Plivo
36
37
  @_resource_type = Recording
37
38
  @_identifier_string = 'recording_id'
38
39
  super
40
+ @_is_voice_request = true
39
41
  end
40
42
 
41
43
  # @param [Hash] options
@@ -24,6 +24,9 @@ module Plivo
24
24
 
25
25
  def configure_base_uri
26
26
  @base_uri = Base::PLIVO_API_URL
27
+ @voice_base_uri = Base::API_VOICE
28
+ @voice_base_uri_fallback_1 = Base::API_VOICE_FALLBACK_1
29
+ @voice_base_uri_fallback_2 = Base::API_VOICE_FALLBACK_2
27
30
  @callinsights_base_uri = Base::CALLINSIGHTS_API_URL
28
31
  end
29
32
 
@@ -101,11 +101,83 @@ module Plivo
101
101
  # @param [String] auth_token
102
102
  def valid_signature?(uri, nonce, signature, auth_token)
103
103
  parsed_uri = URI.parse(uri)
104
- uri_details = { host: parsed_uri.host, path: parsed_uri.path }
104
+ uri_details = {host: parsed_uri.host, path: parsed_uri.path}
105
105
  uri_builder_module = parsed_uri.scheme == 'https' ? URI::HTTPS : URI::HTTP
106
106
  data_to_sign = uri_builder_module.build(uri_details).to_s + nonce
107
107
  sha256_digest = OpenSSL::Digest.new('sha256')
108
108
  Base64.encode64(OpenSSL::HMAC.digest(sha256_digest, auth_token, data_to_sign)).strip() == signature
109
109
  end
110
+
111
+ def generate_url?(uri, params, method)
112
+ uri.sub!("+", "%20")
113
+ parsed_uri = URI.parse(uri)
114
+ uri = parsed_uri.scheme + "://" + parsed_uri.host + parsed_uri.path
115
+ if params.to_s.length > 0 || parsed_uri.query.to_s.length > 0
116
+ uri += "?"
117
+ end
118
+ if parsed_uri.query.to_s.length > 0
119
+ parsed_uri_query = URI.decode(parsed_uri.query)
120
+ if method == "GET"
121
+ queryParamMap = getMapFromQueryString?(parsed_uri_query)
122
+ params.keys.sort.each { |key|
123
+ queryParamMap[key] = params[key]
124
+ }
125
+ uri += GetSortedQueryParamString?(queryParamMap, true)
126
+ else
127
+ uri += GetSortedQueryParamString?(getMapFromQueryString?(parsed_uri_query), true) + "." + GetSortedQueryParamString?(params, false)
128
+ uri = uri.chomp(".")
129
+ end
130
+ else
131
+ if method == "GET"
132
+ uri += GetSortedQueryParamString?(params, true)
133
+ else
134
+ uri += GetSortedQueryParamString?(params, false)
135
+ end
136
+ end
137
+ return uri
138
+ end
139
+
140
+ def getMapFromQueryString?(query)
141
+ mp = Hash.new
142
+ if query.to_s.length == 0
143
+ return mp
144
+ end
145
+ keyValuePairs = query.split("&")
146
+ keyValuePairs.each { |key|
147
+ params = key.split("=", 2)
148
+ if params.length == 2
149
+ mp[params[0]] = params[1]
150
+ end
151
+ }
152
+ return mp
153
+ end
154
+
155
+ def GetSortedQueryParamString?(params, queryParams)
156
+ url = ""
157
+ if queryParams
158
+ params.keys.sort.each { |key|
159
+ url += key + "=" + params[key] + "&"
160
+ }
161
+ url = url.chomp("&")
162
+ else
163
+ params.keys.sort.each { |key|
164
+ url += key.to_s + params[key].to_s
165
+ }
166
+ end
167
+ return url
168
+ end
169
+
170
+
171
+ def compute_signatureV3?(url, auth_token, nonce)
172
+ sha256_digest = OpenSSL::Digest.new('sha256')
173
+ new_url = url + "." + nonce
174
+ return Base64.encode64(OpenSSL::HMAC.digest(sha256_digest, auth_token, new_url)).strip()
175
+ end
176
+
177
+ def valid_signatureV3?(uri, nonce, signature, auth_token, method, params={})
178
+ new_url = generate_url?(uri, params, method)
179
+ generated_signature = compute_signatureV3?(new_url, auth_token, nonce)
180
+ return signature.split(",").include? generated_signature
181
+ end
110
182
  end
111
183
  end
@@ -1,4 +1,3 @@
1
1
  module Plivo
2
- VERSION = '4.6.1'.freeze
3
-
2
+ VERSION = '4.9.0'.freeze
4
3
  end
@@ -34,6 +34,7 @@ Gem::Specification.new do |spec|
34
34
  spec.add_dependency 'faraday', '~> 0.9'
35
35
  spec.add_dependency 'faraday_middleware', '~> 0.12.2'
36
36
  spec.add_dependency 'htmlentities'
37
+ spec.add_dependency 'jwt'
37
38
 
38
39
  spec.add_development_dependency 'bundler', '>= 1.14', '<3.0'
39
40
  spec.add_development_dependency 'rake', '~> 10.0'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: plivo
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.6.1
4
+ version: 4.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - The Plivo SDKs Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-02 00:00:00.000000000 Z
11
+ date: 2020-08-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: jwt
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: bundler
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -150,6 +164,7 @@ files:
150
164
  - Rakefile
151
165
  - ci/config.yml
152
166
  - examples/conference_bridge.rb
167
+ - examples/jwt.rb
153
168
  - examples/multi_party_call.rb
154
169
  - examples/phlos.rb
155
170
  - lib/plivo.rb
@@ -159,6 +174,7 @@ files:
159
174
  - lib/plivo/base/response.rb
160
175
  - lib/plivo/base_client.rb
161
176
  - lib/plivo/exceptions.rb
177
+ - lib/plivo/jwt.rb
162
178
  - lib/plivo/phlo_client.rb
163
179
  - lib/plivo/resources.rb
164
180
  - lib/plivo/resources/accounts.rb