Need to verify webhook in firebase cloud function (SHA-256) - firebase

I need a google cloud function that listens to a webhook from jobber(a CRM for small businesses). I have my https endpoint setup but decoding the Hmac header is giving me trouble.
Their docs posted in the solution in Ruby but not node.js
Here is their solution in Ruby. Any idea how I would implement this as a firebase function?
MY_SECRET = "my apps secret"
# 'data' is the raw JSON payload
# 'hmac_header' is the base64 encoded header `X-Jobber-Hmac-SHA256`
def verify_webhook(data, hmac_header)
digest = OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), MY_SECRET, data)
calculated_hmac = Base64.strict_encode64(digest)
# https://api.rubyonrails.org/classes/ActiveSupport/SecurityUtils.html
# Compare strings of variable length, without exposing yourself to a timing attack
ActiveSupport::SecurityUtils.secure_compare(calculated_hmac, hmac_header)
end
verify_webhook(
"{\"data\":{\"webHookEvent\":{\"topic\":\"APP_CONNECT\",\"appId\":\"id\",\"accountId\":\"id\",\"itemId\":\"id\",\"occuredAt\":\"ISO8601DateTime\"}}}",
"ks1dre6TCHsMO2GVWnDYmx3ZrxubXGbCNZ5gPiXvP9E="
)
# => returns boolean value which determines authenticity

Related

Encryption key retrieve on http call to the API?

Can you tell me if the following flow is good practice for retrieving encryption key?
So I have an Angular app which has custom encryption service created by me and a npm library, which now uses simple string value for key.
I also store access token inside a cookie and the value is encrypted.
Is it good practice, while executing a standard CRUD operation method against my API, first in this method to execute a separate http get request to get the encryption key from the API (from a separate endpoint), then de-crypt the cookie and THEN send it in the http request?
For example, look at this pseudo-code:
getAllProductsAsAdmin(): Observable<any>{
let encryptionKey = callApiAndGetKeyMethod(this.encryptionKeyApiUrl);
let decryptedCookie = decryptCookie(this.existingCookie, encryptionKey);
this.headers = this.headers.set('Authorization', decryptedCookie);
return this.httpClient.get<IGetProductAdminModel[]>(this.getAllProductsAsAdminUrl, {headers: this.headers})
.pipe(
tap(data => console.log('All:',JSON.stringify(data))),
catchError(this.handleError)
);

Encoded / Encrypted body before verifying a Pact

A server I need to integrate with returns its answers encoded as a JWT. Worse, the response body actually is a json, of the form:
{d: token} with token = JWT.encode({id: 123, field: "John", etc.})
I'd like to use a pact verification on the content of the decoded token. I know I can easily have a pact verifying that I get back a {d: string}, I can't do an exact match on the string (as the JWT contains some varying IDs). What I want is the following, which presumes the addition of a new Pact.JWT functionality.
my_provider.
upon_receiving('my request')
.with(method: :post,
path: '/order',
headers: {'Content-Type' => 'application/json'}
).will_respond_with(
status: 200,
headers: {'Content-Type' => 'application/json; charset=utf-8'},
body: {
d: Pact::JWT( {
id: Pact.like(123),
field: Pact.term(generate: "John", matcher: /J.*/
},signing_key,algo
)
})
Short of adding this Pact::JWT, is there a way to achive this kind of result?
I am already using the pact proxy to run my verification. I know you can modify the request before sending it for verification (How do I verify pacts against an API that requires an auth token?). Can you modify the request once you receive it from the proxy server?
If that's the case, I can plan for the following work around:
a switch in my actual code to sometimes expect the answers decoded instead of in the JWT
run my tests once with the swich off (normal code behaviour, mocks returns JWT data encoded.
run my tests a second time with the swich off (code expect data already decoded, mocks return decoded data.)
use the contract json from this second run
hook into the proxy:verify task to decode the JWT on the fly, and use the existing pact mechanisms for verification. (Step that I do not know how to do).
My code is in ruby. I do not have access to the provider.
Any suggestions appreciated! Thanks
You can modify the request or response by using (another) proxy app.
class ProxyApp
def initialize real_provider_app
#real_provider_app = real_provider_app
end
def call env
response = #real_provider_app.call(env)
# modify response here
response
end
end
Pact.service_provider "My Service Provider" do
app { ProxyApp.new(RealApp) }
end
Pact as a tool, I don't expect it to give this behavior out of the box.
In my opinion, the best is,
Do not change source code only for tests
Make sure your tests verifies encoded json only (generate encoded expected json in test & verify that with actual)

How to verify a shopify webhook request in asp.net

Can someone explain how do I compute a HMAC
===============
To verify that the request came from Shopify, compute the HMAC digest according to the following algorithm and compare it to the value in the X-Shopify-Hmac-SHA256 header. If they match, you can be sure that the Webhook was sent from Shopify and the data has not been compromised.
Each Webhook request includes a X-Shopify-Hmac-SHA256 header which is generated using the app's shared secret, along with the data sent in the request.
I have the secret key... how can I combine the secret key + the data in the request to generate a HMAC
The easiest way is to use the ShopifySharp Library. You can use the Nuget package and install it in your project.
This is an example taken from the ShopifySharp website for validating webhooks:
NameValueCollection requestHeaders = Request.Headers;
Stream inputStream = Request.InputStream;
if(AuthorizationService.IsAuthenticWebhook(requestHeaders, inputStream, shopifySecretKey))
{
//Webhook is authentic.
}
else
{
//Webhook is not authentic and should not be acted on.
}
If you don't want to use ShopifySharp, you can see how they implemented it in the source code.

PAW Rest Client: Generating HMAC-SHA256 Signature for AWS requests

I cannot successfully generate a signature for making AWS Requests using PAW.
Here is a link to the signature I am attempting to generate: http://docs.aws.amazon.com/AWSECommerceService/latest/DG/HMACSignatures.html#HMACAuth_ItemsRequired
I have already searched other StackOverflow posts such as: Paw rest client : how to compute HMAC-SHA256 using absolute url as input
To answer your precise question about HMAC-SHA256 signatures, here's a code snippet that will work to compute this specific type of signature, returning the result Base 64 encoded in Paw (it uses the HMAC Dynamic Value programmatically):
function signHmac256(input, key) {
var dv = DynamicValue("com.luckymarmot.HMACDynamicValue", {
input: input,
key: key,
algorithm: 3 /* = SHA256 */,
uppercase: false /* keep hashes lowercase */,
encoding: 'Base64' /* encode hash data in base 64 */,
});
return dv.getEvaluatedString();
}
Otherwise, about the AWS Product Advertising API, we've made a dynamic value for it just today (which is a good opportunity for use to showcase the extension API), see AWS Product Advertising API Auth for Paw and the GitHub Repository here.
To use this dynamic value, first install it through the link shared above, then you can set up all other parameters and then enter a Signature parameter, and set this dynamic value as its value:
Open the token to enter your AWS Secret Key (used in the HMAC signature):

How to sign R API requests with credentials

I'm trying to use Hackpad's API in R. Unlike the example in httr, the Hackpad documentation
1. uses oauth 1.0 and
2. says that the requests should be signed with your credentials.
I do not completely understand how to do the 2nd part in R (with any library). I understand how to use the request, authorize, and access URLs -- but those are not provided for Hackpad (as far as I can tell).
Here is what I tried in R (to no success):
library(httr)
myapp <- oauth_app("hackpad",
key = mykey,
secret = mysecret)
hackpad_token <- oauth1.0_token(oauth_endpoint(authorize = 'https://hackpad.com/api/1.0/',
request = 'https://hackpad.com/api/1.0/',
access = 'https://hackpad.com/api/1.0/'),
myapp)
and also
req <- GET("https://hackpad.com/api/1.0/pad/k9bpcEeOo2Q/content/latest.html",
config = authenticate(user=myuser,
password=mypass))
which tries to return the API documentation content.
Thank you for your help

Resources