vonage 7.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +190 -0
- data/README.md +191 -0
- data/lib/vonage.rb +29 -0
- data/lib/vonage/abstract_authentication.rb +9 -0
- data/lib/vonage/account.rb +61 -0
- data/lib/vonage/alerts.rb +72 -0
- data/lib/vonage/applications.rb +148 -0
- data/lib/vonage/applications/list_response.rb +11 -0
- data/lib/vonage/authentication_error.rb +6 -0
- data/lib/vonage/basic.rb +13 -0
- data/lib/vonage/bearer_token.rb +14 -0
- data/lib/vonage/client.rb +134 -0
- data/lib/vonage/client_error.rb +6 -0
- data/lib/vonage/config.rb +208 -0
- data/lib/vonage/conversations.rb +210 -0
- data/lib/vonage/conversations/events.rb +73 -0
- data/lib/vonage/conversations/legs.rb +30 -0
- data/lib/vonage/conversations/members.rb +104 -0
- data/lib/vonage/conversations/users.rb +93 -0
- data/lib/vonage/conversions.rb +19 -0
- data/lib/vonage/entity.rb +51 -0
- data/lib/vonage/error.rb +6 -0
- data/lib/vonage/errors.rb +51 -0
- data/lib/vonage/files.rb +26 -0
- data/lib/vonage/form_data.rb +11 -0
- data/lib/vonage/gsm7.rb +13 -0
- data/lib/vonage/http.rb +43 -0
- data/lib/vonage/json.rb +17 -0
- data/lib/vonage/jwt.rb +43 -0
- data/lib/vonage/key_secret_params.rb +20 -0
- data/lib/vonage/keys.rb +51 -0
- data/lib/vonage/logger.rb +60 -0
- data/lib/vonage/messages.rb +25 -0
- data/lib/vonage/namespace.rb +118 -0
- data/lib/vonage/number_insight.rb +140 -0
- data/lib/vonage/numbers.rb +196 -0
- data/lib/vonage/numbers/list_response.rb +11 -0
- data/lib/vonage/numbers/response.rb +8 -0
- data/lib/vonage/params.rb +27 -0
- data/lib/vonage/pricing.rb +30 -0
- data/lib/vonage/pricing_types.rb +18 -0
- data/lib/vonage/redact.rb +37 -0
- data/lib/vonage/response.rb +25 -0
- data/lib/vonage/secrets.rb +85 -0
- data/lib/vonage/secrets/list_response.rb +11 -0
- data/lib/vonage/server_error.rb +6 -0
- data/lib/vonage/signature.rb +53 -0
- data/lib/vonage/sms.rb +121 -0
- data/lib/vonage/tfa.rb +14 -0
- data/lib/vonage/user_agent.rb +16 -0
- data/lib/vonage/verify.rb +253 -0
- data/lib/vonage/version.rb +5 -0
- data/lib/vonage/voice.rb +250 -0
- data/lib/vonage/voice/dtmf.rb +26 -0
- data/lib/vonage/voice/list_response.rb +11 -0
- data/lib/vonage/voice/stream.rb +44 -0
- data/lib/vonage/voice/talk.rb +48 -0
- data/vonage.gemspec +26 -0
- metadata +155 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Vonage
|
5
|
+
class Conversions < Namespace
|
6
|
+
extend T::Sig
|
7
|
+
include Keys
|
8
|
+
|
9
|
+
sig { params(params: T::Hash[Symbol, T.untyped]).returns(Vonage::Response) }
|
10
|
+
def track_sms(params)
|
11
|
+
request('/conversions/sms', params: hyphenate(params), type: Post)
|
12
|
+
end
|
13
|
+
|
14
|
+
sig { params(params: T::Hash[Symbol, T.untyped]).returns(Vonage::Response) }
|
15
|
+
def track_voice(params)
|
16
|
+
request('/conversions/voice', params: hyphenate(params), type: Post)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# typed: true
|
2
|
+
|
3
|
+
module Vonage
|
4
|
+
class Entity
|
5
|
+
include Keys
|
6
|
+
|
7
|
+
def initialize(attributes = nil)
|
8
|
+
@attributes = attributes || {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def [](key)
|
12
|
+
@attributes[attribute_key(key)]
|
13
|
+
end
|
14
|
+
|
15
|
+
def []=(key, value)
|
16
|
+
@attributes[attribute_key(key)] = value
|
17
|
+
end
|
18
|
+
|
19
|
+
def respond_to_missing?(name, include_private = false)
|
20
|
+
@attributes.key?(name) or super
|
21
|
+
end
|
22
|
+
|
23
|
+
def method_missing(name, *args)
|
24
|
+
return super unless @attributes.key?(name)
|
25
|
+
|
26
|
+
@attributes[name]
|
27
|
+
end
|
28
|
+
|
29
|
+
def ==(entity)
|
30
|
+
entity.class == self.class && entity.attributes == @attributes
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_h
|
34
|
+
@attributes
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_reader :attributes
|
38
|
+
|
39
|
+
protected :attributes
|
40
|
+
|
41
|
+
def each_pair(&block)
|
42
|
+
return to_enum(:each_pair) unless block
|
43
|
+
|
44
|
+
@attributes.each_pair(&block)
|
45
|
+
end
|
46
|
+
|
47
|
+
alias_method :each, :each_pair
|
48
|
+
|
49
|
+
include Enumerable
|
50
|
+
end
|
51
|
+
end
|
data/lib/vonage/error.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Vonage
|
6
|
+
module Errors
|
7
|
+
extend T::Sig
|
8
|
+
|
9
|
+
sig {params(response: T.any(Net::HTTPUnauthorized, Net::HTTPClientError, Net::HTTPServerError, T.untyped)).returns(Vonage::Error)}
|
10
|
+
def self.parse(response)
|
11
|
+
exception_class = case response
|
12
|
+
when Net::HTTPUnauthorized
|
13
|
+
AuthenticationError
|
14
|
+
when Net::HTTPClientError
|
15
|
+
ClientError
|
16
|
+
when Net::HTTPServerError
|
17
|
+
ServerError
|
18
|
+
else
|
19
|
+
Error
|
20
|
+
end
|
21
|
+
|
22
|
+
message = if response.content_type == 'application/json'
|
23
|
+
hash = ::JSON.parse(response.body)
|
24
|
+
|
25
|
+
if hash.key?('error_title')
|
26
|
+
hash['error_title']
|
27
|
+
elsif hash.key?('error-code-label')
|
28
|
+
hash['error-code-label']
|
29
|
+
elsif hash.key?('description')
|
30
|
+
hash['description']
|
31
|
+
elsif problem_details?(hash)
|
32
|
+
problem_details_message(hash)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
exception_class.new(message)
|
37
|
+
end
|
38
|
+
|
39
|
+
sig { params(hash: T::Hash[String, T.untyped]).returns(T::Boolean) }
|
40
|
+
def self.problem_details?(hash)
|
41
|
+
hash.key?('title') && hash.key?('detail') && hash.key?('type')
|
42
|
+
end
|
43
|
+
|
44
|
+
sig { params(hash: T::Hash[String, T.untyped]).returns(String) }
|
45
|
+
def self.problem_details_message(hash)
|
46
|
+
"#{hash['title']}. #{hash['detail']} See #{hash['type']} for more info, or email support@nexmo.com if you have any questions."
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private_constant :Errors
|
51
|
+
end
|
data/lib/vonage/files.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Vonage
|
5
|
+
class Files < Namespace
|
6
|
+
extend T::Sig
|
7
|
+
|
8
|
+
self.authentication = BearerToken
|
9
|
+
|
10
|
+
sig { params(id: String).returns(T.nilable(Vonage::Response)) }
|
11
|
+
def get(id)
|
12
|
+
request('/v1/files/' + T.must(id.split('/').last))
|
13
|
+
end
|
14
|
+
|
15
|
+
sig { params(id: String, filename: String).returns(T.nilable(Vonage::Response)) }
|
16
|
+
def save(id, filename)
|
17
|
+
request('/v1/files/' + T.must(id.split('/').last)) do |response|
|
18
|
+
File.open(filename, 'wb') do |file|
|
19
|
+
response.read_body do |chunk|
|
20
|
+
file.write(chunk)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/vonage/gsm7.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# typed: ignore
|
2
|
+
|
3
|
+
module Vonage
|
4
|
+
module GSM7
|
5
|
+
CHARACTERS = "\n\f\r !\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_abcdefghijklmnopqrstuvwxyz{|}~ ¡£¤¥§¿ÄÅÆÉÑÖØÜßàäåæçèéìñòöøùüΓΔΘΛΞΠΣΦΨΩ€"
|
6
|
+
|
7
|
+
REGEXP = /\A[#{Regexp.escape(CHARACTERS)}]*\z/
|
8
|
+
|
9
|
+
def self.encoded?(string)
|
10
|
+
REGEXP =~ string
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/vonage/http.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
require 'net/http'
|
4
|
+
|
5
|
+
module Vonage
|
6
|
+
module HTTP
|
7
|
+
class Options
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
sig { params(hash: T::Hash[Symbol, T.untyped]).void }
|
11
|
+
def initialize(hash)
|
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
|
16
|
+
|
17
|
+
@hash.each_key do |name|
|
18
|
+
next if defined_options.key?(name)
|
19
|
+
|
20
|
+
raise ArgumentError, "#{name.inspect} is not a valid option"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
sig { params(http: Net::HTTP).returns(T::Hash[Symbol, T.untyped]) }
|
25
|
+
def set(http)
|
26
|
+
@hash.each do |name, value|
|
27
|
+
http.public_send(defined_options.fetch(name), value)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
sig { returns(T::Hash[Symbol, T.untyped]) }
|
34
|
+
def defined_options
|
35
|
+
@defined_options = T.let(@defined_options, T.nilable(T::Hash[Symbol, T.untyped]))
|
36
|
+
|
37
|
+
@defined_options ||= Net::HTTP.instance_methods.grep(/\w=\z/).each_with_object({}) do |name, hash|
|
38
|
+
hash[name.to_s.chomp('=').to_sym] = name
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/vonage/json.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Vonage
|
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 }
|
10
|
+
def self.update(http_request, params)
|
11
|
+
http_request['Content-Type'] = 'application/json'
|
12
|
+
http_request.body = ::JSON.generate(params)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private_constant :JSON
|
17
|
+
end
|
data/lib/vonage/jwt.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
require 'securerandom'
|
4
|
+
require 'openssl'
|
5
|
+
require 'nexmo-jwt'
|
6
|
+
|
7
|
+
module Vonage
|
8
|
+
class JWT
|
9
|
+
# Generate an encoded JSON Web Token.
|
10
|
+
#
|
11
|
+
# By default the Vonage Ruby SDK generates a short lived JWT per request.
|
12
|
+
#
|
13
|
+
# To generate a long lived JWT for multiple requests or to specify JWT claims
|
14
|
+
# directly call {Vonage::JWT.generate} to generate a token, and set the token
|
15
|
+
# attribute on the client object.
|
16
|
+
#
|
17
|
+
# Documentation for the Vonage Ruby JWT generator gem can be found at
|
18
|
+
# https://www.rubydoc.info/github/Nexmo/nexmo-jwt-ruby
|
19
|
+
#
|
20
|
+
# @example
|
21
|
+
# claims = {
|
22
|
+
# application_id: application_id,
|
23
|
+
# ttl: 800,
|
24
|
+
# subject: 'My_Subject'
|
25
|
+
# }
|
26
|
+
#
|
27
|
+
# private_key = File.read('path/to/private.key')
|
28
|
+
#
|
29
|
+
# client.config.token = Vonage::JWT.generate(claims, private_key)
|
30
|
+
#
|
31
|
+
# @param [Hash] payload
|
32
|
+
# @param [String, OpenSSL::PKey::RSA] private_key
|
33
|
+
#
|
34
|
+
# @return [String]
|
35
|
+
#
|
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
|
38
|
+
|
39
|
+
payload[:private_key] = private_key if private_key && !payload[:private_key]
|
40
|
+
@token = Nexmo::JWTBuilder.new(payload).jwt.generate
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
module Vonage
|
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 }
|
10
|
+
def update(object)
|
11
|
+
return unless object.is_a?(Hash)
|
12
|
+
|
13
|
+
@config = T.let(@config, T.nilable(Vonage::Config))
|
14
|
+
object[:api_key] = T.must(@config).api_key
|
15
|
+
object[:api_secret] = T.must(@config).api_secret
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private_constant :KeySecretParams
|
20
|
+
end
|
data/lib/vonage/keys.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Vonage
|
5
|
+
module Keys
|
6
|
+
extend T::Sig
|
7
|
+
|
8
|
+
sig { params(hash: T::Hash[T.untyped, T.untyped]).returns(T::Hash[String, T.untyped]) }
|
9
|
+
def hyphenate(hash)
|
10
|
+
hash.transform_keys { |k| k.to_s.tr('_', '-') }
|
11
|
+
end
|
12
|
+
|
13
|
+
sig { params(hash: T::Hash[T.untyped, T.untyped]).returns(T::Hash[T.untyped, T.untyped]) }
|
14
|
+
def camelcase(hash)
|
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
|
32
|
+
end
|
33
|
+
|
34
|
+
ATTRIBUTE_KEYS = T.let(Hash.new { |h, k| h[k] = k.split(PATTERN).join('_').downcase.to_sym }, T::Hash[T.untyped, T.untyped])
|
35
|
+
|
36
|
+
PATTERN = /[\-_]|(?<=\w)(?=[A-Z])/
|
37
|
+
|
38
|
+
private_constant :ATTRIBUTE_KEYS
|
39
|
+
|
40
|
+
private_constant :PATTERN
|
41
|
+
|
42
|
+
sig { params(k: T.any(Symbol, String)).returns(Symbol) }
|
43
|
+
def attribute_key(k)
|
44
|
+
return k if k.is_a?(Symbol)
|
45
|
+
|
46
|
+
ATTRIBUTE_KEYS[k]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private_constant :Keys
|
51
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
require 'logger'
|
4
|
+
require 'forwardable'
|
5
|
+
|
6
|
+
module Vonage
|
7
|
+
class Logger
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
sig { params(logger: T.nilable(T.any(::Logger, Vonage::Logger))).void }
|
11
|
+
def initialize(logger)
|
12
|
+
@logger = logger || ::Logger.new(nil)
|
13
|
+
end
|
14
|
+
|
15
|
+
extend Forwardable
|
16
|
+
|
17
|
+
::Logger::Severity.constants.map(&:downcase).each do |name|
|
18
|
+
def_delegator :@logger, name, name
|
19
|
+
end
|
20
|
+
|
21
|
+
sig { params(request: T.any(Net::HTTP::Post, Net::HTTP::Get, Net::HTTP::Delete, Net::HTTP::Put)).void }
|
22
|
+
def log_request_info(request)
|
23
|
+
@logger = T.let(@logger, T.nilable(T.any(::Logger, Vonage::Logger)))
|
24
|
+
|
25
|
+
T.must(@logger).info do
|
26
|
+
format('Vonage API request', {
|
27
|
+
method: request.method,
|
28
|
+
path: request.uri.path
|
29
|
+
})
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
sig { params(
|
34
|
+
response: T.any(Net::HTTPOK, Net::HTTPNoContent, Net::HTTPBadRequest, Net::HTTPInternalServerError, Net::HTTPResponse),
|
35
|
+
host: String
|
36
|
+
).void }
|
37
|
+
def log_response_info(response, host)
|
38
|
+
T.must(@logger).info do
|
39
|
+
format('Vonage API response', {
|
40
|
+
host: host,
|
41
|
+
status: response.code,
|
42
|
+
type: response.content_type,
|
43
|
+
length: response.content_length,
|
44
|
+
trace_id: response['x-Vonage-trace-id']
|
45
|
+
})
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
sig { params(message: String, hash: T::Hash[Symbol, T.untyped]).returns(String) }
|
52
|
+
def format(message, hash)
|
53
|
+
return message if hash.nil?
|
54
|
+
|
55
|
+
fields = hash.map { |key, value| "#{key}=#{value}" if value }.compact
|
56
|
+
fields.unshift(message)
|
57
|
+
fields.join(' ')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Vonage
|
5
|
+
class Messages < Namespace
|
6
|
+
extend T::Sig
|
7
|
+
|
8
|
+
self.host = :rest_host
|
9
|
+
|
10
|
+
sig { params(id: String).returns(Vonage::Response) }
|
11
|
+
def get(id)
|
12
|
+
request('/search/message', params: {id: id})
|
13
|
+
end
|
14
|
+
|
15
|
+
sig { params(params: T::Hash[Symbol, T.untyped]).returns(Vonage::Response) }
|
16
|
+
def search(params)
|
17
|
+
request('/search/messages', params: params)
|
18
|
+
end
|
19
|
+
|
20
|
+
sig { params(params: T::Hash[Symbol, T.untyped]).returns(Vonage::Response) }
|
21
|
+
def rejections(params)
|
22
|
+
request('/search/rejections', params: params)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|