plivo 4.5.0 → 4.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/README.md +1 -1
- data/examples/jwt.rb +23 -0
- data/lib/plivo.rb +1 -0
- data/lib/plivo/base_client.rb +4 -3
- data/lib/plivo/jwt.rb +120 -0
- data/lib/plivo/resources/applications.rb +21 -4
- data/lib/plivo/resources/messages.rb +6 -0
- data/lib/plivo/utils.rb +73 -1
- data/lib/plivo/version.rb +1 -2
- data/plivo.gemspec +1 -0
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dbbe456a4f4f19cb4d520c470c32a12fbf1d886a
|
4
|
+
data.tar.gz: 017ae48d6b340d1f71267a8c726b1ccacab11bde
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c2b4252b08ad48e9302fb37ec1f8dc1362ea4c2af5b95334841eada03f1e88865453dea532e5fe6d15a829dd868ebabc67cf75a41905ba8276b6d158edda4d23
|
7
|
+
data.tar.gz: 578e0a1b358eb14dba2ae2b03b6925975586a262122628bf84257c63f50cc3d59bfc9ea486c4fc71590ecbbdd037c7ddab863c4ebe7451f4308330a64fbd6498
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## [4.8.0](https://github.com/plivo/plivo-ruby/releases/tag/v4.8.0) (2020-05-28)
|
4
|
+
- Add JWT helper functions.
|
5
|
+
|
6
|
+
## [4.7.1](https://github.com/plivo/plivo-ruby/releases/tag/v4.7.1) (2020-05-06)
|
7
|
+
- Fix Send MMS with existing media_ids.
|
8
|
+
|
9
|
+
## [4.7.0](https://github.com/plivo/plivo-ruby/releases/tag/v4.7.0) (2020-04-29)
|
10
|
+
- Add V3 signature helper functions.
|
11
|
+
|
12
|
+
## [4.6.1](https://github.com/plivo/plivo-ruby/releases/tag/v4.6.1) (2020-04-02)
|
13
|
+
- Add nil check for API requests.
|
14
|
+
|
15
|
+
## [4.6.0](https://github.com/plivo/plivo-ruby/releases/tag/v4.6.0) (2020-03-31)
|
16
|
+
- Add application cascade delete support.
|
17
|
+
|
3
18
|
## [4.5.0](https://github.com/plivo/plivo-ruby/releases/tag/v4.5.0) (2020-03-30)
|
4
19
|
- Add Tollfree support for Powerpack
|
5
20
|
|
data/README.md
CHANGED
data/examples/jwt.rb
ADDED
@@ -0,0 +1,23 @@
|
|
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, till)
|
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
|
+
rescue ValidationError => e
|
22
|
+
puts 'Exception: ' + e.message
|
23
|
+
end
|
data/lib/plivo.rb
CHANGED
data/lib/plivo/base_client.rb
CHANGED
@@ -46,7 +46,7 @@ module Plivo
|
|
46
46
|
response = case method
|
47
47
|
when 'GET' then send_get(resource_path, data, timeout)
|
48
48
|
when 'POST' then send_post(resource_path, data, timeout, use_multipart_conn)
|
49
|
-
when 'DELETE' then send_delete(resource_path, timeout)
|
49
|
+
when 'DELETE' then send_delete(resource_path, data, timeout)
|
50
50
|
else raise_invalid_request("#{method} not supported by Plivo, yet")
|
51
51
|
end
|
52
52
|
|
@@ -167,7 +167,7 @@ module Plivo
|
|
167
167
|
req.body = data
|
168
168
|
end
|
169
169
|
else
|
170
|
-
if data.has_key? 'is_callinsights_request'
|
170
|
+
if !data.nil? && (data.has_key? 'is_callinsights_request')
|
171
171
|
callinsight_base_url = data['callinsight_base_url']
|
172
172
|
resource_path = data['request_url']
|
173
173
|
data.delete('is_callinsights_request')
|
@@ -190,10 +190,11 @@ module Plivo
|
|
190
190
|
response
|
191
191
|
end
|
192
192
|
|
193
|
-
def send_delete(resource_path, timeout)
|
193
|
+
def send_delete(resource_path, data, timeout)
|
194
194
|
response = @conn.delete do |req|
|
195
195
|
req.url resource_path
|
196
196
|
req.options.timeout = timeout if timeout
|
197
|
+
req.body = JSON.generate(data) if data
|
197
198
|
end
|
198
199
|
response
|
199
200
|
end
|
data/lib/plivo/jwt.rb
ADDED
@@ -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
|
@@ -57,8 +57,22 @@ module Plivo
|
|
57
57
|
perform_update(params)
|
58
58
|
end
|
59
59
|
|
60
|
-
|
61
|
-
|
60
|
+
# @param [Hash] options
|
61
|
+
# @option options [Boolean] :cascade - delete associated endpoints
|
62
|
+
# @option options [String] :new_endpoint_application - Link associated endpoints to this app
|
63
|
+
def delete(options = nil)
|
64
|
+
return perform_delete if options.nil?
|
65
|
+
params = {}
|
66
|
+
|
67
|
+
if options.key?(:cascade) && valid_param?(:cascade, options[:cascade], [TrueClass, FalseClass], false, [true, false])
|
68
|
+
params[:cascade] = options[:cascade]
|
69
|
+
end
|
70
|
+
|
71
|
+
if options.key?(:new_endpoint_application) && valid_param?(:new_endpoint_application, options[:new_endpoint_application], [String, Symbol])
|
72
|
+
params[:new_endpoint_application] = options[:new_endpoint_application]
|
73
|
+
end
|
74
|
+
|
75
|
+
perform_delete(params)
|
62
76
|
end
|
63
77
|
|
64
78
|
def to_s
|
@@ -227,10 +241,13 @@ module Plivo
|
|
227
241
|
##
|
228
242
|
# Delete an application
|
229
243
|
# @param [String] app_id
|
230
|
-
|
244
|
+
# @param [Hash] options
|
245
|
+
# @option options [Boolean] :cascade - delete associated endpoints
|
246
|
+
# @option options [String] :new_endpoint_application - Link associated endpoints to this app
|
247
|
+
def delete(app_id, options = nil)
|
231
248
|
valid_param?(:app_id, app_id, [String, Symbol], true)
|
232
249
|
Application.new(@_client,
|
233
|
-
resource_id: app_id).delete
|
250
|
+
resource_id: app_id).delete(options)
|
234
251
|
end
|
235
252
|
end
|
236
253
|
end
|
@@ -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)
|
data/lib/plivo/utils.rb
CHANGED
@@ -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 = {
|
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
|
data/lib/plivo/version.rb
CHANGED
data/plivo.gemspec
CHANGED
@@ -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.
|
4
|
+
version: 4.8.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-
|
11
|
+
date: 2020-05-28 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
|