Class: Pagaris::Signature

Inherits:
Object
  • Object
show all
Defined in:
lib/pagaris/signature.rb

Overview

Signatures (SHA256 HMACs) are used inside the Authorization header of API calls. This class extracts the signature building process.

Constant Summary collapse

HEADER_REGEXP =
/\A(Pagaris\s)?(.+):(.+):(.+)\z/

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path:, timestamp: Time.now.to_i, body: nil, method: 'POST') ⇒ Signature

Constructs a signature that should be included in the Authorization header of requests made by Client to the API.

Parameters:

  • path (String)

    The path on your app where this webhook was received. It must match the path of the URL that you set in your Pagaris

  • timestamp (Integer, String) (defaults to: Time.now.to_i)

    Defaults to current time. Seconds since the Unix epoch

  • body (String, NilClass) (defaults to: nil)

    nil by default. Raw body string.

  • method (String) (defaults to: 'POST')

    'POST' by default, but could be changed (e.g. 'GET')



25
26
27
28
29
# File 'lib/pagaris/signature.rb', line 25

def initialize(path:, timestamp: Time.now.to_i, body: nil, method: 'POST')
  @timestamp = timestamp
  data = "#{@timestamp}-#{method}-#{path}-#{body}"
  @value = OpenSSL::HMAC.hexdigest('SHA256', Pagaris.private_key, data)
end

Instance Attribute Details

#valueObject (readonly)

Returns the value of attribute value.



11
12
13
# File 'lib/pagaris/signature.rb', line 11

def value
  @value
end

Class Method Details

.valid?(header_value:, path:, body:, method: 'POST') ⇒ Boolean

Checks if a given Authorization header's value contains a valid signature, by comparing it to an expected signature that would be generated with the configured Pagaris.private_key. Useful for verifying a signature of a received webhook.

Examples:

Signature.valid?(
  header_value: request.authorization, # e.g. 'Pagaris a:b:c'
  path: request.fullpath, # e.g. '/path/for/receiving/webhooks'
  body: request.raw_post # e.g. '{"order": {"amount": "9876.54"}}'
) # => true or false

Parameters:

  • header_value (String)

    The value of the Authorization header. It may include the Pagaris prefix as the Authentication type or not.

  • path (String)

    The path on your app where this webhook was received. It must match the path of the URL that you set in your Pagaris Application (e.g. if you use a trailing slash on your Application, you should include it here too).

  • body (String, NilClass)

    Raw body string.

  • method (String) (defaults to: 'POST')

    'POST' by default, but could be changed (e.g. 'GET')

Returns:

  • (Boolean)


63
64
65
66
67
68
69
70
# File 'lib/pagaris/signature.rb', line 63

def self.valid?(header_value:, path:, body:, method: 'POST')
  timestamp, signature = header_value&.match(HEADER_REGEXP)&.captures
    &.[](2..3)

  expected_signature = self.new(timestamp: timestamp, path: path,
    body: body, method: method)
  expected_signature.value == signature
end

Instance Method Details

#header_valueObject

Constructs the value of an Authorization HTTP header, from its calculated value when initializing, as well as the timestamp that was used to calculate it.



36
37
38
# File 'lib/pagaris/signature.rb', line 36

def header_value
  "Pagaris #{Pagaris.application_id}:#{@timestamp}:#{@value}"
end