Permalink
Cannot retrieve contributors at this time
require 'pp' | |
require 'json' | |
require 'time' | |
require 'base64' | |
require 'openssl' | |
require 'securerandom' | |
require 'net/http/persistent' | |
module Telesign | |
SDK_VERSION = '2.2.3' | |
# The TeleSign RestClient is a generic HTTP REST client that can be extended to make requests against any of | |
# TeleSign's REST API endpoints. | |
# | |
# RequestEncodingMixin offers the function _encode_params for url encoding the body for use in string_to_sign outside | |
# of a regular HTTP request. | |
# | |
# See https://developer.telesign.com for detailed API documentation. | |
class RestClient | |
@@user_agent = "TeleSignSDK/ruby-{#{SDK_VERSION} #{RUBY_DESCRIPTION} net/http/persistent" | |
# A simple HTTP Response object to abstract the underlying net/http library response. | |
# * +http_response+ - A net/http response object. | |
class Response | |
attr_accessor :status_code, :headers, :body, :ok, :json | |
def initialize(http_response) | |
@status_code = http_response.code | |
@headers = http_response.to_hash | |
@body = http_response.body | |
@ok = http_response.kind_of? Net::HTTPSuccess | |
begin | |
@json = JSON.parse(http_response.body) | |
rescue JSON::JSONError | |
@json = nil | |
end | |
end | |
end | |
# TeleSign RestClient, useful for making generic RESTful requests against the API. | |
# | |
# * +customer_id+ - Your customer_id string associated with your account. | |
# * +api_key+ - Your api_key string associated with your account. | |
# * +rest_endpoint+ - (optional) Override the default rest_endpoint to target another endpoint. | |
# * +timeout+ - (optional) How long to wait for the server to send data before giving up, as a float. | |
def initialize(customer_id, | |
api_key, | |
rest_endpoint: 'https://rest-api.telesign.com', | |
proxy: nil, | |
timeout: 10) | |
@customer_id = customer_id | |
@api_key = api_key | |
@rest_endpoint = rest_endpoint | |
@http = Net::HTTP::Persistent.new(name: 'telesign', proxy: proxy) | |
unless timeout.nil? | |
@http.open_timeout = timeout | |
@http.read_timeout = timeout | |
end | |
end | |
# Generates the TeleSign REST API headers used to authenticate requests. | |
# | |
# Creates the canonicalized string_to_sign and generates the HMAC signature. This is used to authenticate requests | |
# against the TeleSign REST API. | |
# | |
# See https://developer.telesign.com/docs/authentication for detailed API documentation. | |
# | |
# * +customer_id+ - Your account customer_id. | |
# * +api_key+ - Your account api_key. | |
# * +method_name+ - The HTTP method name of the request as a upper case string, should be one of 'POST', 'GET', | |
# 'PUT' or 'DELETE'. | |
# * +resource+ - The partial resource URI to perform the request against, as a string. | |
# * +url_encoded_fields+ - HTTP body parameters to perform the HTTP request with, must be a urlencoded string. | |
# * +date_rfc2616+ - The date and time of the request formatted in rfc 2616, as a string. | |
# * +nonce+ - A unique cryptographic nonce for the request, as a string. | |
# * +user_agent+ - (optional) User Agent associated with the request, as a string. | |
def self.generate_telesign_headers(customer_id, | |
api_key, | |
method_name, | |
resource, | |
content_type, | |
encoded_fields, | |
date_rfc2616: nil, | |
nonce: nil, | |
user_agent: nil) | |
if date_rfc2616.nil? | |
date_rfc2616 = Time.now.httpdate | |
end | |
if nonce.nil? | |
nonce = SecureRandom.uuid | |
end | |
content_type = (%w[POST PUT].include? method_name) ? content_type : '' | |
auth_method = 'HMAC-SHA256' | |
string_to_sign = "#{method_name}" | |
string_to_sign << "\n#{content_type}" | |
string_to_sign << "\n#{date_rfc2616}" | |
string_to_sign << "\nx-ts-auth-method:#{auth_method}" | |
string_to_sign << "\nx-ts-nonce:#{nonce}" | |
if !content_type.empty? and !encoded_fields.empty? | |
string_to_sign << "\n#{encoded_fields}" | |
end | |
string_to_sign << "\n#{resource}" | |
digest = OpenSSL::Digest.new('sha256') | |
key = Base64.decode64(api_key) | |
signature = Base64.encode64(OpenSSL::HMAC.digest(digest, key, string_to_sign)).strip | |
authorization = "TSA #{customer_id}:#{signature}" | |
headers = { | |
'Authorization'=>authorization, | |
'Date'=>date_rfc2616, | |
'x-ts-auth-method'=>auth_method, | |
'x-ts-nonce'=>nonce | |
} | |
unless user_agent.nil? | |
headers['User-Agent'] = user_agent | |
end | |
headers | |
end | |
# Generic TeleSign REST API POST handler. | |
# | |
# * +resource+ - The partial resource URI to perform the request against, as a string. | |
# * +params+ - Body params to perform the POST request with, as a hash. | |
def post(resource, **params) | |
execute(Net::HTTP::Post, 'POST', resource, **params) | |
end | |
# Generic TeleSign REST API GET handler. | |
# | |
# * +resource+ - The partial resource URI to perform the request against, as a string. | |
# * +params+ - Body params to perform the GET request with, as a hash. | |
def get(resource, **params) | |
execute(Net::HTTP::Get, 'GET', resource, **params) | |
end | |
# Generic TeleSign REST API PUT handler. | |
# | |
# * +resource+ - The partial resource URI to perform the request against, as a string. | |
# * +params+ - Body params to perform the PUT request with, as a hash. | |
def put(resource, **params) | |
execute(Net::HTTP::Put, 'PUT', resource, **params) | |
end | |
# Generic TeleSign REST API DELETE handler. | |
# | |
# * +resource+ - The partial resource URI to perform the request against, as a string. | |
# * +params+ - Body params to perform the DELETE request with, as a hash. | |
def delete(resource, **params) | |
execute(Net::HTTP::Delete, 'DELETE', resource, **params) | |
end | |
private | |
# Generic TeleSign REST API request handler. | |
# | |
# * +method_function+ - The net/http request to perform the request. | |
# * +method_name+ - The HTTP method name, as an upper case string. | |
# * +resource+ - The partial resource URI to perform the request against, as a string. | |
# * +params+ - Body params to perform the HTTP request with, as a hash. | |
def execute(method_function, method_name, resource, **params) | |
resource_uri = URI.parse("#{@rest_endpoint}#{resource}") | |
encoded_fields = '' | |
if %w[POST PUT].include? method_name | |
request = method_function.new(resource_uri.request_uri) | |
if content_type == "application/x-www-form-urlencoded" | |
unless params.empty? | |
encoded_fields = URI.encode_www_form(params, Encoding::UTF_8) | |
request.set_form_data(params) | |
end | |
else | |
encoded_fields = params.to_json | |
request.body = encoded_fields | |
request.set_content_type("application/json") | |
end | |
else | |
resource_uri.query = URI.encode_www_form(params, Encoding::UTF_8) | |
request = method_function.new(resource_uri.request_uri) | |
end | |
headers = RestClient.generate_telesign_headers(@customer_id, | |
@api_key, | |
method_name, | |
resource, | |
content_type, | |
encoded_fields, | |
user_agent: @@user_agent) | |
headers.each do |k, v| | |
request[k] = v | |
end | |
http_response = @http.request(resource_uri, request) | |
Response.new(http_response) | |
end | |
def content_type | |
"application/x-www-form-urlencoded" | |
end | |
end | |
end |