Class: Twilio::Security::RequestValidator

Inherits:
Object
  • Object
show all
Defined in:
lib/twilio-ruby/security/request_validator.rb

Instance Method Summary collapse

Constructor Details

#initialize(auth_token = nil) ⇒ RequestValidator

Initialize a Request Validator. auth_token will either be grabbed from the global Twilio object or you can pass it in here.

Raises:

  • (ArgumentError)


11
12
13
14
# File 'lib/twilio-ruby/security/request_validator.rb', line 11

def initialize(auth_token = nil)
  @auth_token = auth_token || Twilio.auth_token
  raise ArgumentError, 'Auth token is required' if @auth_token.nil?
end

Instance Method Details

#build_hash_for(body) ⇒ String

Build a SHA256 hash for a body string



55
56
57
58
# File 'lib/twilio-ruby/security/request_validator.rb', line 55

def build_hash_for(body)
  hasher = OpenSSL::Digest.new('sha256')
  hasher.hexdigest(body)
end

#build_signature_for(url, params) ⇒ String

Build a SHA1-HMAC signature for a url and parameter hash



67
68
69
70
71
# File 'lib/twilio-ruby/security/request_validator.rb', line 67

def build_signature_for(url, params)
  data = url + params.sort.join
  digest = OpenSSL::Digest.new('sha1')
  Base64.strict_encode64(OpenSSL::HMAC.digest(digest, @auth_token, data))
end

#validate(url, params, signature) ⇒ Boolean

Validates that after hashing a request with Twilio’s request-signing algorithm (www.twilio.com/docs/usage/security#validating-requests), the hash matches the signature parameter



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/twilio-ruby/security/request_validator.rb', line 27

def validate(url, params, signature)
  parsed_url = URI(url)
  url_with_port = add_port(parsed_url)
  url_without_port = remove_port(parsed_url)

  valid_body = true # default succeed, since body not always provided
  params_hash = body_or_hash(params)
  unless params_hash.is_a? Enumerable
    body_hash = URI.decode_www_form(parsed_url.query).to_h['bodySHA256']
    params_hash = build_hash_for(params)
    valid_body = !(params_hash.nil? || body_hash.nil?) && secure_compare(params_hash, body_hash)
    params_hash = {}
  end

  # Check signature of the url with and without port numbers
  # since signature generation on the back end is inconsistent
  valid_signature_with_port = secure_compare(build_signature_for(url_with_port, params_hash), signature)
  valid_signature_without_port = secure_compare(build_signature_for(url_without_port, params_hash), signature)

  valid_body && (valid_signature_with_port || valid_signature_without_port)
end