nexmo 7.0.0 → 7.2.1
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 +4 -4
- data/README.md +37 -6
- data/lib/nexmo.rb +1 -1
- data/lib/nexmo/abstract_authentication.rb +0 -2
- data/lib/nexmo/applications.rb +24 -4
- data/lib/nexmo/client.rb +40 -19
- data/lib/nexmo/config.rb +42 -9
- data/lib/nexmo/conversations.rb +24 -1
- data/lib/nexmo/conversations/events.rb +1 -1
- data/lib/nexmo/conversations/legs.rb +1 -1
- data/lib/nexmo/conversations/members.rb +1 -1
- data/lib/nexmo/conversations/users.rb +1 -1
- data/lib/nexmo/conversions.rb +4 -1
- data/lib/nexmo/entity.rb +2 -2
- data/lib/nexmo/errors.rb +6 -1
- data/lib/nexmo/files.rb +7 -3
- data/lib/nexmo/gsm7.rb +0 -2
- data/lib/nexmo/http.rb +12 -4
- data/lib/nexmo/json.rb +4 -1
- data/lib/nexmo/jwt.rb +11 -12
- data/lib/nexmo/key_secret_params.rb +9 -3
- data/lib/nexmo/keys.rb +24 -3
- data/lib/nexmo/logger.rb +14 -5
- data/lib/nexmo/messages.rb +6 -1
- data/lib/nexmo/number_insight.rb +1 -1
- data/lib/nexmo/numbers.rb +1 -1
- data/lib/nexmo/pricing.rb +1 -1
- data/lib/nexmo/pricing_types.rb +1 -1
- data/lib/nexmo/redact.rb +4 -1
- data/lib/nexmo/response.rb +1 -1
- data/lib/nexmo/secrets.rb +1 -1
- data/lib/nexmo/signature.rb +1 -1
- data/lib/nexmo/sms.rb +1 -1
- data/lib/nexmo/tfa.rb +1 -1
- data/lib/nexmo/verify.rb +66 -3
- data/lib/nexmo/version.rb +1 -1
- data/lib/nexmo/voice.rb +1 -1
- data/lib/nexmo/voice/dtmf.rb +1 -1
- data/lib/nexmo/voice/stream.rb +1 -1
- data/lib/nexmo/voice/talk.rb +1 -1
- data/nexmo.gemspec +13 -1
- metadata +29 -6
data/lib/nexmo/conversations.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
module Nexmo
|
5
5
|
class Conversations < Namespace
|
6
|
+
extend T::Sig
|
7
|
+
|
6
8
|
self.authentication = BearerToken
|
7
9
|
|
8
10
|
self.request_body = JSON
|
@@ -33,6 +35,7 @@ module Nexmo
|
|
33
35
|
#
|
34
36
|
# @see https://developer.nexmo.com/api/conversation#createConversation
|
35
37
|
#
|
38
|
+
sig { params(params: T::Hash[Symbol, T.untyped]).returns(Nexmo::Response) }
|
36
39
|
def create(params)
|
37
40
|
request('/beta/conversations', params: params, type: Post)
|
38
41
|
end
|
@@ -63,6 +66,7 @@ module Nexmo
|
|
63
66
|
#
|
64
67
|
# @see https://developer.nexmo.com/api/conversation#replaceConversation
|
65
68
|
#
|
69
|
+
sig { params(params: T.nilable(T::Hash[Symbol, T.untyped])).returns(Nexmo::Response) }
|
66
70
|
def list(params = nil)
|
67
71
|
request('/beta/conversations', params: params)
|
68
72
|
end
|
@@ -78,6 +82,7 @@ module Nexmo
|
|
78
82
|
#
|
79
83
|
# @see https://developer.nexmo.com/api/conversation#retrieveConversation
|
80
84
|
#
|
85
|
+
sig { params(id: String).returns(Nexmo::Response) }
|
81
86
|
def get(id)
|
82
87
|
request('/beta/conversations/' + id)
|
83
88
|
end
|
@@ -110,6 +115,10 @@ module Nexmo
|
|
110
115
|
#
|
111
116
|
# @see https://developer.nexmo.com/api/conversation#replaceConversation
|
112
117
|
#
|
118
|
+
sig { params(
|
119
|
+
id: String,
|
120
|
+
params: T::Hash[Symbol, T.untyped]
|
121
|
+
).returns(Nexmo::Response) }
|
113
122
|
def update(id, params)
|
114
123
|
request('/beta/conversations/' + id, params: params, type: Put)
|
115
124
|
end
|
@@ -125,6 +134,7 @@ module Nexmo
|
|
125
134
|
#
|
126
135
|
# @see https://developer.nexmo.com/api/conversation#deleteConversation
|
127
136
|
#
|
137
|
+
sig { params(id: String).returns(Nexmo::Response) }
|
128
138
|
def delete(id)
|
129
139
|
request('/beta/conversations/' + id, type: Delete)
|
130
140
|
end
|
@@ -156,31 +166,44 @@ module Nexmo
|
|
156
166
|
#
|
157
167
|
# @see https://developer.nexmo.com/api/conversation#recordConversation
|
158
168
|
#
|
169
|
+
sig { params(
|
170
|
+
id: String,
|
171
|
+
params: T::Hash[Symbol, T.untyped]
|
172
|
+
).returns(Nexmo::Response) }
|
159
173
|
def record(id, params)
|
160
174
|
request('/v1/conversations/' + id + '/record', params: params, type: Put)
|
161
175
|
end
|
162
176
|
|
163
177
|
# @return [Events]
|
164
178
|
#
|
179
|
+
sig { returns(T.nilable(Nexmo::Conversations::Events)) }
|
165
180
|
def events
|
181
|
+
@events = T.let(@events, T.nilable(Nexmo::Conversations::Events))
|
182
|
+
@config = T.let(@config, T.nilable(Nexmo::Config))
|
166
183
|
@events ||= Events.new(@config)
|
167
184
|
end
|
168
185
|
|
169
186
|
# @return [Legs]
|
170
187
|
#
|
188
|
+
sig { returns(T.nilable(Nexmo::Conversations::Legs)) }
|
171
189
|
def legs
|
190
|
+
@legs = T.let(@legs, T.nilable(Nexmo::Conversations::Legs))
|
172
191
|
@legs ||= Legs.new(@config)
|
173
192
|
end
|
174
193
|
|
175
194
|
# @return [Members]
|
176
195
|
#
|
196
|
+
sig { returns(T.nilable(Nexmo::Conversations::Members)) }
|
177
197
|
def members
|
198
|
+
@members = T.let(@members, T.nilable(Nexmo::Conversations::Members))
|
178
199
|
@members ||= Members.new(@config)
|
179
200
|
end
|
180
201
|
|
181
202
|
# @return [Users]
|
182
203
|
#
|
204
|
+
sig { returns(T.nilable(Nexmo::Conversations::Users)) }
|
183
205
|
def users
|
206
|
+
@users = T.let(@users, T.nilable(Nexmo::Conversations::Users))
|
184
207
|
@users ||= Users.new(@config)
|
185
208
|
end
|
186
209
|
end
|
data/lib/nexmo/conversions.rb
CHANGED
@@ -1,14 +1,17 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
module Nexmo
|
5
5
|
class Conversions < Namespace
|
6
|
+
extend T::Sig
|
6
7
|
include Keys
|
7
8
|
|
9
|
+
sig { params(params: T::Hash[Symbol, T.untyped]).returns(Nexmo::Response) }
|
8
10
|
def track_sms(params)
|
9
11
|
request('/conversions/sms', params: hyphenate(params), type: Post)
|
10
12
|
end
|
11
13
|
|
14
|
+
sig { params(params: T::Hash[Symbol, T.untyped]).returns(Nexmo::Response) }
|
12
15
|
def track_voice(params)
|
13
16
|
request('/conversions/voice', params: hyphenate(params), type: Post)
|
14
17
|
end
|
data/lib/nexmo/entity.rb
CHANGED
data/lib/nexmo/errors.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
require 'json'
|
4
4
|
|
5
5
|
module Nexmo
|
6
6
|
module Errors
|
7
|
+
extend T::Sig
|
8
|
+
|
9
|
+
sig {params(response: T.any(Net::HTTPUnauthorized, Net::HTTPClientError, Net::HTTPServerError, T.untyped)).returns(Nexmo::Error)}
|
7
10
|
def self.parse(response)
|
8
11
|
exception_class = case response
|
9
12
|
when Net::HTTPUnauthorized
|
@@ -33,10 +36,12 @@ module Nexmo
|
|
33
36
|
exception_class.new(message)
|
34
37
|
end
|
35
38
|
|
39
|
+
sig { params(hash: T::Hash[String, T.untyped]).returns(T::Boolean) }
|
36
40
|
def self.problem_details?(hash)
|
37
41
|
hash.key?('title') && hash.key?('detail') && hash.key?('type')
|
38
42
|
end
|
39
43
|
|
44
|
+
sig { params(hash: T::Hash[String, T.untyped]).returns(String) }
|
40
45
|
def self.problem_details_message(hash)
|
41
46
|
"#{hash['title']}. #{hash['detail']} See #{hash['type']} for more info, or email support@nexmo.com if you have any questions."
|
42
47
|
end
|
data/lib/nexmo/files.rb
CHANGED
@@ -1,16 +1,20 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
module Nexmo
|
5
5
|
class Files < Namespace
|
6
|
+
extend T::Sig
|
7
|
+
|
6
8
|
self.authentication = BearerToken
|
7
9
|
|
10
|
+
sig { params(id: String).returns(T.nilable(Nexmo::Response)) }
|
8
11
|
def get(id)
|
9
|
-
request('/v1/files/' + id.split('/').last)
|
12
|
+
request('/v1/files/' + T.must(id.split('/').last))
|
10
13
|
end
|
11
14
|
|
15
|
+
sig { params(id: String, filename: String).returns(T.nilable(Nexmo::Response)) }
|
12
16
|
def save(id, filename)
|
13
|
-
request('/v1/files/' + id.split('/').last) do |response|
|
17
|
+
request('/v1/files/' + T.must(id.split('/').last)) do |response|
|
14
18
|
File.open(filename, 'wb') do |file|
|
15
19
|
response.read_body do |chunk|
|
16
20
|
file.write(chunk)
|
data/lib/nexmo/gsm7.rb
CHANGED
data/lib/nexmo/http.rb
CHANGED
@@ -1,12 +1,18 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
require 'net/http'
|
4
4
|
|
5
5
|
module Nexmo
|
6
6
|
module HTTP
|
7
7
|
class Options
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
sig { params(hash: T::Hash[Symbol, T.untyped]).void }
|
8
11
|
def initialize(hash)
|
9
|
-
|
12
|
+
raise ArgumentError, 'hash parameter cannot be empty or nil' if hash == {} || hash.nil?
|
13
|
+
|
14
|
+
@hash = T.let(@hash, T::Hash[Symbol, T.untyped]) if defined? @hash
|
15
|
+
@hash = hash
|
10
16
|
|
11
17
|
@hash.each_key do |name|
|
12
18
|
next if defined_options.key?(name)
|
@@ -15,6 +21,7 @@ module Nexmo
|
|
15
21
|
end
|
16
22
|
end
|
17
23
|
|
24
|
+
sig { params(http: Net::HTTP).returns(T::Hash[Symbol, T.untyped]) }
|
18
25
|
def set(http)
|
19
26
|
@hash.each do |name, value|
|
20
27
|
http.public_send(defined_options.fetch(name), value)
|
@@ -23,13 +30,14 @@ module Nexmo
|
|
23
30
|
|
24
31
|
private
|
25
32
|
|
33
|
+
sig { returns(T::Hash[Symbol, T.untyped]) }
|
26
34
|
def defined_options
|
35
|
+
@defined_options = T.let(@defined_options, T.nilable(T::Hash[Symbol, T.untyped]))
|
36
|
+
|
27
37
|
@defined_options ||= Net::HTTP.instance_methods.grep(/\w=\z/).each_with_object({}) do |name, hash|
|
28
38
|
hash[name.to_s.chomp('=').to_sym] = name
|
29
39
|
end
|
30
40
|
end
|
31
41
|
end
|
32
42
|
end
|
33
|
-
|
34
|
-
private_constant :HTTP
|
35
43
|
end
|
data/lib/nexmo/json.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
require 'json'
|
4
4
|
|
5
5
|
module Nexmo
|
6
6
|
module JSON
|
7
|
+
extend T::Sig
|
8
|
+
|
9
|
+
sig { params(http_request: T.any(Net::HTTP::Put, Net::HTTP::Post), params: T::Hash[Symbol, T.untyped]).void }
|
7
10
|
def self.update(http_request, params)
|
8
11
|
http_request['Content-Type'] = 'application/json'
|
9
12
|
http_request.body = ::JSON.generate(params)
|
data/lib/nexmo/jwt.rb
CHANGED
@@ -2,10 +2,10 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
require 'securerandom'
|
4
4
|
require 'openssl'
|
5
|
-
require 'jwt'
|
5
|
+
require 'nexmo-jwt'
|
6
6
|
|
7
7
|
module Nexmo
|
8
|
-
|
8
|
+
class JWT
|
9
9
|
# Generate an encoded JSON Web Token.
|
10
10
|
#
|
11
11
|
# By default the Nexmo Ruby SDK generates a short lived JWT per request.
|
@@ -14,12 +14,14 @@ module Nexmo
|
|
14
14
|
# directly call {Nexmo::JWT.generate} to generate a token, and set the token
|
15
15
|
# attribute on the client object.
|
16
16
|
#
|
17
|
+
# Documentation for the Nexmo Ruby JWT generator gem can be found at
|
18
|
+
# https://www.rubydoc.info/github/nexmo/nexmo-jwt-ruby
|
19
|
+
#
|
17
20
|
# @example
|
18
21
|
# claims = {
|
19
22
|
# application_id: application_id,
|
20
|
-
#
|
21
|
-
#
|
22
|
-
# iat: 1483228800
|
23
|
+
# ttl: 800,
|
24
|
+
# subject: 'My_Subject'
|
23
25
|
# }
|
24
26
|
#
|
25
27
|
# private_key = File.read('path/to/private.key')
|
@@ -31,14 +33,11 @@ module Nexmo
|
|
31
33
|
#
|
32
34
|
# @return [String]
|
33
35
|
#
|
34
|
-
def self.generate(payload, private_key)
|
35
|
-
payload
|
36
|
-
payload[:exp] = iat + 60 unless payload.key?(:exp) || payload.key?('exp')
|
37
|
-
payload[:jti] = SecureRandom.uuid unless payload.key?(:jti) || payload.key?('jti')
|
38
|
-
|
39
|
-
private_key = OpenSSL::PKey::RSA.new(private_key) unless private_key.respond_to?(:sign)
|
36
|
+
def self.generate(payload, private_key = nil)
|
37
|
+
raise "Expecting 'private_key' in either the payload or as a separate parameter" if !payload[:private_key] && !private_key
|
40
38
|
|
41
|
-
|
39
|
+
payload[:private_key] = private_key if private_key && !payload[:private_key]
|
40
|
+
@token = Nexmo::JWTBuilder.new(payload).jwt.generate
|
42
41
|
end
|
43
42
|
end
|
44
43
|
end
|
@@ -1,12 +1,18 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
|
3
3
|
module Nexmo
|
4
4
|
class KeySecretParams < AbstractAuthentication
|
5
|
+
extend T::Sig
|
6
|
+
|
7
|
+
sig { params(
|
8
|
+
object: T.any(T::Hash[T.untyped, T.untyped], URI::HTTPS, Net::HTTP::Post, Net::HTTP::Get)
|
9
|
+
).void }
|
5
10
|
def update(object)
|
6
11
|
return unless object.is_a?(Hash)
|
7
12
|
|
8
|
-
|
9
|
-
object[:
|
13
|
+
@config = T.let(@config, T.nilable(Nexmo::Config))
|
14
|
+
object[:api_key] = T.must(@config).api_key
|
15
|
+
object[:api_secret] = T.must(@config).api_secret
|
10
16
|
end
|
11
17
|
end
|
12
18
|
|
data/lib/nexmo/keys.rb
CHANGED
@@ -1,17 +1,37 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
module Nexmo
|
5
5
|
module Keys
|
6
|
+
extend T::Sig
|
7
|
+
|
8
|
+
sig { params(hash: T::Hash[T.untyped, T.untyped]).returns(T::Hash[String, T.untyped]) }
|
6
9
|
def hyphenate(hash)
|
7
10
|
hash.transform_keys { |k| k.to_s.tr('_', '-') }
|
8
11
|
end
|
9
12
|
|
13
|
+
sig { params(hash: T::Hash[T.untyped, T.untyped]).returns(T::Hash[T.untyped, T.untyped]) }
|
10
14
|
def camelcase(hash)
|
11
|
-
|
15
|
+
exceptions = [
|
16
|
+
'dr_call_back_url',
|
17
|
+
'mo_http_url',
|
18
|
+
'mo_smpp_sys_type',
|
19
|
+
'mo_call_back_url',
|
20
|
+
'voice_callback_type',
|
21
|
+
'voice_callback_value',
|
22
|
+
'voice_status_callback',
|
23
|
+
'messages_callback_value',
|
24
|
+
'messages_callback_type'
|
25
|
+
]
|
26
|
+
hash.transform_keys do |k|
|
27
|
+
if exceptions.include?(k.to_s)
|
28
|
+
next k.to_s.gsub(/_(\w)/) { $1.upcase.to_s }
|
29
|
+
end
|
30
|
+
k
|
31
|
+
end
|
12
32
|
end
|
13
33
|
|
14
|
-
ATTRIBUTE_KEYS = Hash.new { |h, k| h[k] = k.split(PATTERN).join('_').downcase.to_sym }
|
34
|
+
ATTRIBUTE_KEYS = T.let(Hash.new { |h, k| h[k] = k.split(PATTERN).join('_').downcase.to_sym }, T::Hash[T.untyped, T.untyped])
|
15
35
|
|
16
36
|
PATTERN = /[\-_]|(?<=\w)(?=[A-Z])/
|
17
37
|
|
@@ -19,6 +39,7 @@ module Nexmo
|
|
19
39
|
|
20
40
|
private_constant :PATTERN
|
21
41
|
|
42
|
+
sig { params(k: T.any(Symbol, String)).returns(Symbol) }
|
22
43
|
def attribute_key(k)
|
23
44
|
return k if k.is_a?(Symbol)
|
24
45
|
|
data/lib/nexmo/logger.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: false
|
2
2
|
# frozen_string_literal: true
|
3
3
|
require 'logger'
|
4
4
|
require 'forwardable'
|
5
5
|
|
6
6
|
module Nexmo
|
7
7
|
class Logger
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
sig { params(logger: T.nilable(T.any(::Logger, Nexmo::Logger))).void }
|
8
11
|
def initialize(logger)
|
9
12
|
@logger = logger || ::Logger.new(nil)
|
10
13
|
end
|
@@ -15,8 +18,11 @@ module Nexmo
|
|
15
18
|
def_delegator :@logger, name, name
|
16
19
|
end
|
17
20
|
|
21
|
+
sig { params(request: T.any(Net::HTTP::Post, Net::HTTP::Get, Net::HTTP::Delete, Net::HTTP::Put)).void }
|
18
22
|
def log_request_info(request)
|
19
|
-
@logger.
|
23
|
+
@logger = T.let(@logger, T.nilable(T.any(::Logger, Nexmo::Logger)))
|
24
|
+
|
25
|
+
T.must(@logger).info do
|
20
26
|
format('Nexmo API request', {
|
21
27
|
method: request.method,
|
22
28
|
path: request.uri.path
|
@@ -24,8 +30,12 @@ module Nexmo
|
|
24
30
|
end
|
25
31
|
end
|
26
32
|
|
33
|
+
sig { params(
|
34
|
+
response: T.any(Net::HTTPOK, Net::HTTPNoContent, Net::HTTPBadRequest, Net::HTTPInternalServerError, Net::HTTPResponse),
|
35
|
+
host: String
|
36
|
+
).void }
|
27
37
|
def log_response_info(response, host)
|
28
|
-
@logger.info do
|
38
|
+
T.must(@logger).info do
|
29
39
|
format('Nexmo API response', {
|
30
40
|
host: host,
|
31
41
|
status: response.code,
|
@@ -38,6 +48,7 @@ module Nexmo
|
|
38
48
|
|
39
49
|
private
|
40
50
|
|
51
|
+
sig { params(message: String, hash: T::Hash[Symbol, T.untyped]).returns(String) }
|
41
52
|
def format(message, hash)
|
42
53
|
return message if hash.nil?
|
43
54
|
|
@@ -46,6 +57,4 @@ module Nexmo
|
|
46
57
|
fields.join(' ')
|
47
58
|
end
|
48
59
|
end
|
49
|
-
|
50
|
-
private_constant :Logger
|
51
60
|
end
|