Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SubtleCryptoProvider and update Webhooks to allow async crypto. #1288

Merged
merged 1 commit into from
Nov 11, 2021

Conversation

dcr-stripe
Copy link
Contributor

@dcr-stripe dcr-stripe commented Nov 9, 2021

Notify

r? @richardm-stripe

Summary

Introduce a new CryptoProvider which uses the SubtleCrypto API. This is the main implementation for the Web Crypto API.

This requires adding support for async HMAC computations in CryptoProvider and adding new async Webhook creation/verification functions which can use these.

As a result, we can now construct and verify a webhook asynchronously by doing:

const cryptoProvider = Stripe.createSubtleCryptoProvider();

const event = await stripe.webhooks.constructEventAsync(
  body, 
  signature, 
  secret,
  tolerance, 
  cryptoProvider
);

I opted to go down the route of having sync and async methods rather than parameterizing the CryptoProvider. We could have done something like CryptoProvider<T> and then constructEvent():T. However our internal code would still need to check whether the T was a promise or not. Instead this forces one to be explicit about whether you want to operate synchronously or asynchronously, and gives us an opportunity to error if trying to mix contexts.

Motivation

We need this for Deno support (#997). Deno's crypto package doesn't implement HMAC and instead relies on the Web Crypto API, which is all async.

Test Plan

Added tests throughout. Note that unfortunately the SubtleCryptoProvider can only be tested on Node 16, as Node only added a SubtleCrypto shim in Node 15. All tests are shared between sync and async versinos.

I've also set up a Deno template which processes webhooks asynchronously using this

describe('SubtleCryptoProvider', () => {
const provider = new SubtleCryptoProvider(webcrypto.subtle);

createCryptoProviderTestSuite(provider, true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I try to avoid calling functions that call describe and it since this interacts poorly with test runners, but nbd

Copy link
Contributor

@richardm-stripe richardm-stripe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! I like the choice of completely parallel async and sync pathways.

@dcr-stripe dcr-stripe merged commit 4e82cca into master Nov 11, 2021
@dcr-stripe dcr-stripe deleted the dcr-async-crypto branch November 11, 2021 17:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants