Class: Webhookdb::Increase

Inherits:
Object
  • Object
show all
Extended by:
MethodUtilities
Includes:
Appydays::Configurable, Appydays::Loggable
Defined in:
lib/webhookdb/increase.rb

Defined Under Namespace

Classes: WebhookSignature

Constant Summary collapse

OLD_CUTOFF =
35.days
NEW_CUTOFF =
4.days

Class Method Summary collapse

Methods included from MethodUtilities

attr_predicate, attr_predicate_accessor, singleton_attr_accessor, singleton_attr_reader, singleton_attr_writer, singleton_method_alias, singleton_predicate_accessor, singleton_predicate_reader

Class Method Details

.compute_signature(secret:, data:, t:) ⇒ WebhookSignature

Parameters:

  • secret (String)
  • data (String)
  • t (Time)

Returns:



62
63
64
65
66
# File 'lib/webhookdb/increase.rb', line 62

def self.compute_signature(secret:, data:, t:)
  signed_payload = "#{t.utc.iso8601}.#{data}"
  sig = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha256"), secret, signed_payload)
  return WebhookSignature.new(v1: [sig], t:)
end

.parse_signature(s) ⇒ WebhookSignature

Parameters:

  • s (String, nil)

Returns:



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/webhookdb/increase.rb', line 41

def self.parse_signature(s)
  sig = WebhookSignature.new
  s&.split(",")&.each do |part|
    key, val = part.split("=")
    if key == "t"
      begin
        sig.t = Time.rfc3339(val)
      rescue ArgumentError
        nil
      end
    elsif key == "v1"
      sig.v1 << val
    end
  end
  return sig
end

.webhook_response(request, webhook_secret, now: Time.now) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/webhookdb/increase.rb', line 71

def self.webhook_response(request, webhook_secret, now: Time.now)
  http_signature = request.env["HTTP_INCREASE_WEBHOOK_SIGNATURE"]
  return Webhookdb::WebhookResponse.error("missing header") if http_signature.nil?

  request.body.rewind
  request_data = request.body.read

  parsed_signature = self.parse_signature(http_signature)
  return Webhookdb::WebhookResponse.error("missing timestamp") if parsed_signature.t.nil?
  return Webhookdb::WebhookResponse.error("missing signatures") if parsed_signature.v1.empty?
  return Webhookdb::WebhookResponse.error("too old") if parsed_signature.t < (now - OLD_CUTOFF)
  return Webhookdb::WebhookResponse.error("too new") if parsed_signature.t > (now + NEW_CUTOFF)

  computed_signature = self.compute_signature(secret: webhook_secret, data: request_data, t: parsed_signature.t)
  return Webhookdb::WebhookResponse.error("invalid signature") unless
    parsed_signature.v1.include?(computed_signature.v1.first)

  return Webhookdb::WebhookResponse.ok
end