Open gotchahn opened 3 years ago
Hello @gotchahn,
Thank you for reporting this issue to us. I have been unable to reproduce. Could you please provide some more detail about your setup? Here is the code I used to test:
require 'sendgrid-ruby'
include SendGrid
ew = SendGrid::EventWebhook.new
public_key = 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE83T4O/n84iotIvIW4mdBgQ/7dAfSmpqIM8kF9mN1flpVKS3GRqe62gw+2fNNRaINXvVpiglSI8eNEc6wEA3F+g=='.freeze
signature = 'MEUCIGHQVtGj+Y3LkG9fLcxf3qfI10QysgDWmMOVmxG0u6ZUAiEAyBiXDWzM+uOe5W0JuG+luQAbPIqHh89M15TluLtEZtM='.freeze
timestamp = '1600112502'.freeze
payload = "#{[
{
email: 'hello@world.com',
event: 'dropped',
reason: 'Bounced Address',
sg_event_id: 'ZHJvcC0xMDk5NDkxOS1MUnpYbF9OSFN0T0doUTRrb2ZTbV9BLTA',
sg_message_id: 'LRzXl_NHStOGhQ4kofSm_A.filterdrecv-p3mdw1-756b745b58-kmzbl-18-5F5FC76C-9.0',
'smtp-id': '<LRzXl_NHStOGhQ4kofSm_A@ismtpd0039p1iad1.sendgrid.net>',
timestamp: 1_600_112_492
}
].to_json}\r\n".freeze
ec_public_key = ew.convert_public_key_to_ecdsa(public_key)
value = ew.verify_signature(ec_public_key, payload, signature, timestamp)
print value
This returned true
.
With best regards,
Elmer
Hi @thinkingserious, I copy pasted your code in my rails console, and gave me false
hmm, weird. I'm using Rails 6.0.3.2
, Ruby 2.6.5
and Sendgrid-ruby 6.3.8
$ rails c
Running via Spring preloader in process 58835
Loading development environment (Rails 6.0.3.2)
irb(main):001:0> ew = SendGrid::EventWebhook.new
=> #<SendGrid::EventWebhook:0x00007faa4fe0c468>
irb(main):002:0> public_key = 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE83T4O/n84iotIvIW4mdBgQ/7dAfSmpqIM8kF9mN1flpVKS3GRqe62gw+2fNNRaINXvVpiglSI8eNEc6wEA3F+g=='.freeze
=> "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE83T4O/n84iotIvIW4mdBgQ/7dAfSmpqIM8kF9mN1flpVKS3GRqe62gw+2fNNRaINXvVpiglSI8eNEc6wEA3F+g=="
irb(main):003:0> signature = 'MEUCIGHQVtGj+Y3LkG9fLcxf3qfI10QysgDWmMOVmxG0u6ZUAiEAyBiXDWzM+uOe5W0JuG+luQAbPIqHh89M15TluLtEZtM='.freeze
=> "MEUCIGHQVtGj+Y3LkG9fLcxf3qfI10QysgDWmMOVmxG0u6ZUAiEAyBiXDWzM+uOe5W0JuG+luQAbPIqHh89M15TluLtEZtM="
irb(main):004:0> timestamp = '1600112502'.freeze
=> "1600112502"
irb(main):005:0> payload = "#{[
irb(main):006:1> {
irb(main):007:2> email: 'hello@world.com',
irb(main):008:2> event: 'dropped',
irb(main):009:2> reason: 'Bounced Address',
irb(main):010:2> sg_event_id: 'ZHJvcC0xMDk5NDkxOS1MUnpYbF9OSFN0T0doUTRrb2ZTbV9BLTA',
irb(main):011:2> sg_message_id: 'LRzXl_NHStOGhQ4kofSm_A.filterdrecv-p3mdw1-756b745b58-kmzbl-18-5F5FC76C-9.0',
irb(main):012:2> 'smtp-id': '<LRzXl_NHStOGhQ4kofSm_A@ismtpd0039p1iad1.sendgrid.net>',
irb(main):013:2> timestamp: 1_600_112_492
irb(main):014:2> }
irb(main):015:1> ].to_json}\r\n".freeze
=> "[{\"email\":\"hello@world.com\",\"event\":\"dropped\",\"reason\":\"Bounced Address\",\"sg_event_id\":\"ZHJvcC0xMDk5NDkxOS1MUnpYbF9OSFN0T0doUTRrb2ZTbV9BLTA\",\"sg_message_id\":\"LRzXl_NHStOGhQ4kofSm_A.filterdrecv-p3mdw1-756b745b58-kmzbl-18-5F5FC76C-9.0\",\"smtp-id\":\"\\u003cLRzXl_NHStOGhQ4kofSm_A@ismtpd0039p1iad1.sendgrid.net\\u003e\",\"timestamp\":1600112492}]\r\n"
irb(main):016:0> ec_public_key = ew.convert_public_key_to_ecdsa(public_key)
=> #<OpenSSL::PKey::EC:0x00007faa4ffe7f30>
irb(main):017:0> value = ew.verify_signature(ec_public_key, payload, signature, timestamp)
=> false
irb(main):018:0> print value
false=> nil
irb(main):019:0>
BUT, noticed that if I do that code in a plain irb
console, it works! but not on rails console
or in my rails testing suite. Do you have any idea why it works only in a irb
console??
$ irb
irb(main):001:0> require 'sendgrid-ruby'
=> true
irb(main):002:0> include SendGrid
=> Object
irb(main):003:0>
irb(main):004:0> ew = SendGrid::EventWebhook.new
=> #<SendGrid::EventWebhook:0x00007fb08aa6cdd0>
irb(main):005:0> public_key = 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE83T4O/n84iotIvIW4mdBgQ/7dAfSmpqIM8kF9mN1flpVKS3GRqe62gw+2fNNRaINXvVpiglSI8eNEc6wEA3F+g=='.freeze
=> "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE83T4O/n84iotIvIW4mdBgQ/7dAfSmpqIM8kF9mN1flpVKS3GRqe62gw+2fNNRaINXvVpiglSI8eNEc6wEA3F+g=="
irb(main):006:0> signature = 'MEUCIGHQVtGj+Y3LkG9fLcxf3qfI10QysgDWmMOVmxG0u6ZUAiEAyBiXDWzM+uOe5W0JuG+luQAbPIqHh89M15TluLtEZtM='.freeze
=> "MEUCIGHQVtGj+Y3LkG9fLcxf3qfI10QysgDWmMOVmxG0u6ZUAiEAyBiXDWzM+uOe5W0JuG+luQAbPIqHh89M15TluLtEZtM="
irb(main):007:0> timestamp = '1600112502'.freeze
=> "1600112502"
irb(main):008:0> payload = "#{[
irb(main):009:1> {
irb(main):010:2> email: 'hello@world.com',
irb(main):011:2> event: 'dropped',
irb(main):012:2> reason: 'Bounced Address',
irb(main):013:2> sg_event_id: 'ZHJvcC0xMDk5NDkxOS1MUnpYbF9OSFN0T0doUTRrb2ZTbV9BLTA',
irb(main):014:2> sg_message_id: 'LRzXl_NHStOGhQ4kofSm_A.filterdrecv-p3mdw1-756b745b58-kmzbl-18-5F5FC76C-9.0',
irb(main):015:2> 'smtp-id': '<LRzXl_NHStOGhQ4kofSm_A@ismtpd0039p1iad1.sendgrid.net>',
irb(main):016:2> timestamp: 1_600_112_492
irb(main):017:2> }
irb(main):018:1> ].to_json}\r\n".freeze
=> "[{\"email\":\"hello@world.com\",\"event\":\"dropped\",\"reason\":\"Bounced Address\",\"sg_event_id\":\"ZHJvcC0xMDk5NDkxOS1MUnpYbF9OSFN0T0doUTRrb2ZTbV9BLTA\",\"sg_message_id\":\"LRzXl_NHStOGhQ4kofSm_A.filterdrecv-p3mdw1-756b745b58-kmzbl-18-5F5FC76C-9.0\",\"smtp-id\":\"<LRzXl_NHStOGhQ4kofSm_A@ismtpd0039p1iad1.sendgrid.net>\",\"timestamp\":1600112492}]\r\n"
irb(main):019:0> ec_public_key = ew.convert_public_key_to_ecdsa(public_key)
=> #<OpenSSL::PKey::EC:0x00007fb08aadf4e8>
irb(main):020:0> value = ew.verify_signature(ec_public_key, payload, signature, timestamp)
=> true
irb(main):021:0> print value
true=> nil
Hello @gotchahn,
Here are few things to check:
RUBY_VERSION
while in the irb console vs rails console.Thanks!
With best regards,
Elmer
Hi @thinkingserious,
2.6.5
as the RUBY_VERSION
. Running via Spring preloader in process....
dunno if that has something to do.rails console
. I tested in production, and the endpoint works well with the validation of the REAL key and signature. Is just the made of ones for the tests that gives me false
the verifier.
UPDATE:
I tested the rails console without the Spring preloader, and it returns false still.
Hi @thinkingserious,
I figured it out, it's the payload the cause of the issue, and mainly, the .to_json
method with the 'smtp-id'
section, look:
in irb
console:
$ irb
irb(main):001:0> require 'sendgrid-ruby'
=> true
irb(main):002:0> include SendGrid
=> Object
irb(main):017:0> "'smtp-id': '<LRzXl_NHStOGhQ4kofSm_A@ismtpd0039p1iad1.sendgrid.net>'".to_json
=> "\"'smtp-id': '<LRzXl_NHStOGhQ4kofSm_A@ismtpd0039p1iad1.sendgrid.net>'\""
in rails console
:
irb(main):001:0> "'smtp-id': '<LRzXl_NHStOGhQ4kofSm_A@ismtpd0039p1iad1.sendgrid.net>'".to_json
=> "\"'smtp-id': '\\u003cLRzXl_NHStOGhQ4kofSm_A@ismtpd0039p1iad1.sendgrid.net\\u003e'\""
irb(main):002:0>
The <
and >
are converted, so that's why the verifier doesn't returns true. Using JSON.generate
worked:
irb(main):004:0> JSON.generate("'smtp-id': '<LRzXl_NHStOGhQ4kofSm_A@ismtpd0039p1iad1.sendgrid.net>'")
=> "\"'smtp-id': '<LRzXl_NHStOGhQ4kofSm_A@ismtpd0039p1iad1.sendgrid.net>'\""
But I have another question, If I slightly change the payload, the verifier returns false, any idea of how I can use a custom payload with a different type of event for example, and get the right signature for the public key??
I realise this is an old issue, but I wanted to post a solution to the issue of how to generate signatures for custom payloads:
def sendgrid_key
@sendgrid_key ||= OpenSSL::PKey::EC.generate("prime256v1")
end
def sendgrid_public_key
Base64.strict_encode64(sendgrid_key.public_to_pem)
end
def sendgrid_signature(payload, timestamp)
Base64.strict_encode64(sendgrid_key.dsa_sign_asn1(Digest::SHA256.digest("#{timestamp}#{payload}")))
end
def sendgrid_headers(body)
timestamp = Time.now.to_i
{
"Content-Type" => "application/json;charset=utf-8",
::SendGrid::EventWebhookHeader::SIGNATURE => sendgrid_signature(body, timestamp),
::SendGrid::EventWebhookHeader::TIMESTAMP => timestamp
}
end
Note that you have to generate a new key for your tests since SendGrid (correctly) does not provide the private key for generating signatures. We use an environment variable in our controller to get the public key, a gem that modifies ENV
such as climate_control
can be used to override it in tests, e.g.
ClimateControl.modify SENDGRID_PUBLIC_KEY: sendgrid_public_key do
post "/sendgrid", params: payload, headers: sendgrid_headers(payload)
end
Issue Summary
I'm trying to do some tests in rails to check if my sendgrid webhook endpoint is working. I'm in using the same values for PUBLIC KEY and SIGNATURE key shared on the fixtures page: https://github.com/sendgrid/sendgrid-ruby/blob/865a2accaa11aa990e188fc4f018be619590b52c/spec/fixtures/event_webhook.rb#L5-L20
But overall the verify method returns false to me.
Code Snippet
If I do this manually in the console, using the same values, the verify returns
false
:Also this is my rspec that I was coding:
Exception/Log
Technical details: