From 81c80d59154dbe93de0302aee6b04235f91e49e6 Mon Sep 17 00:00:00 2001 From: Annie Li Date: Tue, 7 Feb 2023 15:12:44 -0800 Subject: [PATCH] Add back createCryptoProvider and createHttpClient, remove non-null assertion, more specific return type on createStripe --- lib/Webhooks.js | 10 +++++----- lib/platform/NodePlatformFunctions.js | 9 +++++++++ lib/platform/PlatformFunctions.js | 13 +++++++++++++ lib/platform/WebPlatformFunctions.js | 10 +++++++++- src/Webhooks.ts | 17 +++++++---------- src/crypto/SubtleCryptoProvider.ts | 2 +- src/platform/NodePlatformFunctions.ts | 11 +++++++++++ src/platform/PlatformFunctions.ts | 25 ++++++++++++++++++++++--- src/platform/WebPlatformFunctions.ts | 12 +++++++++++- src/stripe.common.ts | 2 +- 10 files changed, 89 insertions(+), 22 deletions(-) diff --git a/lib/Webhooks.js b/lib/Webhooks.js index fa455fbefa..ba623da518 100644 --- a/lib/Webhooks.js +++ b/lib/Webhooks.js @@ -40,7 +40,7 @@ function createWebhooks(platformFunctions) { opts.timestamp = Math.floor(opts.timestamp) || Math.floor(Date.now() / 1000); opts.scheme = opts.scheme || signature.EXPECTED_SCHEME; - opts.cryptoProvider = opts.cryptoProvider || getNodeCryptoProvider(); + opts.cryptoProvider = opts.cryptoProvider || getCryptoProvider(); opts.signature = opts.signature || opts.cryptoProvider.computeHMACSignature(opts.timestamp + '.' + opts.payload, opts.secret); @@ -55,14 +55,14 @@ function createWebhooks(platformFunctions) { EXPECTED_SCHEME: 'v1', verifyHeader(encodedPayload, encodedHeader, secret, tolerance, cryptoProvider) { const { decodedHeader: header, decodedPayload: payload, details, } = parseEventDetails(encodedPayload, encodedHeader, this.EXPECTED_SCHEME); - cryptoProvider = cryptoProvider || getNodeCryptoProvider(); + cryptoProvider = cryptoProvider || getCryptoProvider(); const expectedSignature = cryptoProvider.computeHMACSignature(makeHMACContent(payload, details), secret); validateComputedSignature(payload, header, details, expectedSignature, tolerance); return true; }, async verifyHeaderAsync(encodedPayload, encodedHeader, secret, tolerance, cryptoProvider) { const { decodedHeader: header, decodedPayload: payload, details, } = parseEventDetails(encodedPayload, encodedHeader, this.EXPECTED_SCHEME); - cryptoProvider = cryptoProvider || getNodeCryptoProvider(); + cryptoProvider = cryptoProvider || getCryptoProvider(); const expectedSignature = await cryptoProvider.computeHMACSignatureAsync(makeHMACContent(payload, details), secret); return validateComputedSignature(payload, header, details, expectedSignature, tolerance); }, @@ -144,9 +144,9 @@ function createWebhooks(platformFunctions) { * Lazily instantiate a CryptoProvider instance. This is a stateless object * so a singleton can be used here. */ - function getNodeCryptoProvider() { + function getCryptoProvider() { if (!webhooksCryptoProviderInstance) { - webhooksCryptoProviderInstance = platformFunctions.createNodeCryptoProvider(); + webhooksCryptoProviderInstance = platformFunctions.createCryptoProvider(); } return webhooksCryptoProviderInstance; } diff --git a/lib/platform/NodePlatformFunctions.js b/lib/platform/NodePlatformFunctions.js index 3166f4895a..d680c45fe1 100644 --- a/lib/platform/NodePlatformFunctions.js +++ b/lib/platform/NodePlatformFunctions.js @@ -113,8 +113,17 @@ class NodePlatformFunctions extends PlatformFunctions { return new NodeHttpClient(agent); } /** @override */ + createHttpClient(agent) { + // @ts-ignore + return new NodeHttpClient(agent); + } + /** @override */ createNodeCryptoProvider() { return new NodeCryptoProvider(); } + /** @override */ + createCryptoProvider() { + return this.createNodeCryptoProvider(); + } } module.exports = NodePlatformFunctions; diff --git a/lib/platform/PlatformFunctions.js b/lib/platform/PlatformFunctions.js index 2dd96ea9ba..7cad5881e1 100644 --- a/lib/platform/PlatformFunctions.js +++ b/lib/platform/PlatformFunctions.js @@ -9,6 +9,10 @@ const SubtleCryptoProvider = require("../crypto/SubtleCryptoProvider"); * implementations depend on the platform / JS runtime. */ class PlatformFunctions { + constructor() { + this._fetchFn = null; + this._agent = null; + } /** * Gets uname with Node's built-in `exec` function, if available. */ @@ -71,6 +75,12 @@ class PlatformFunctions { // @ts-ignore return new FetchHttpClient(fetchFn); } + /** + * Creates an HTTP client using runtime-specific APIs. + */ + createHttpClient(agent) { + throw new Error('createHttpClient not implemented.'); + } /** * Creates a CryptoProvider which uses the Node `crypto` package for its computations. */ @@ -83,5 +93,8 @@ class PlatformFunctions { createSubtleCryptoProvider(subtleCrypto) { return new SubtleCryptoProvider(subtleCrypto); } + createCryptoProvider() { + throw new Error('createCryptoProvider not implemented.'); + } } module.exports = PlatformFunctions; diff --git a/lib/platform/WebPlatformFunctions.js b/lib/platform/WebPlatformFunctions.js index 1e1c534c42..8f4fbb73cd 100644 --- a/lib/platform/WebPlatformFunctions.js +++ b/lib/platform/WebPlatformFunctions.js @@ -23,12 +23,20 @@ class WebPlatformFunctions extends PlatformFunctions { return Promise.resolve(data); } /** @override */ - createNodeHttpClient(agent) { + createNodeHttpClient() { throw new Error('Stripe: `createNodeHttpClient()` is not available in non-Node environments. Please use `createFetchHttpClient()` instead.'); } /** @override */ + createHttpClient() { + return super.createFetchHttpClient(); + } + /** @override */ createNodeCryptoProvider() { throw new Error('Stripe: `createNodeCryptoProvider()` is not available in non-Node environments. Please use `createSubtleCryptoProvider()` instead.'); } + /** @override */ + createCryptoProvider() { + return this.createSubtleCryptoProvider(); + } } module.exports = WebPlatformFunctions; diff --git a/src/Webhooks.ts b/src/Webhooks.ts index 459cf3c0ce..5c8340cf3f 100644 --- a/src/Webhooks.ts +++ b/src/Webhooks.ts @@ -1,6 +1,6 @@ +import CryptoProvider = require('./crypto/CryptoProvider'); import _Error = require('./Error'); import PlatformFunctions = require('./platform/PlatformFunctions'); -import CryptoProvider = require('./crypto/CryptoProvider'); const {StripeError, StripeSignatureVerificationError} = _Error; type WebhookHeader = string | Uint8Array; @@ -131,7 +131,7 @@ function createWebhooks(platformFunctions: PlatformFunctions): WebhookObject { Math.floor(opts.timestamp) || Math.floor(Date.now() / 1000); opts.scheme = opts.scheme || signature.EXPECTED_SCHEME; - opts.cryptoProvider = opts.cryptoProvider || getNodeCryptoProvider(); + opts.cryptoProvider = opts.cryptoProvider || getCryptoProvider(); opts.signature = opts.signature || @@ -169,7 +169,7 @@ function createWebhooks(platformFunctions: PlatformFunctions): WebhookObject { this.EXPECTED_SCHEME ); - cryptoProvider = cryptoProvider || getNodeCryptoProvider(); + cryptoProvider = cryptoProvider || getCryptoProvider(); const expectedSignature = cryptoProvider.computeHMACSignature( makeHMACContent(payload, details), secret @@ -203,7 +203,7 @@ function createWebhooks(platformFunctions: PlatformFunctions): WebhookObject { this.EXPECTED_SCHEME ); - cryptoProvider = cryptoProvider || getNodeCryptoProvider(); + cryptoProvider = cryptoProvider || getCryptoProvider(); const expectedSignature = await cryptoProvider.computeHMACSignatureAsync( makeHMACContent(payload, details), @@ -290,10 +290,7 @@ function createWebhooks(platformFunctions: PlatformFunctions): WebhookObject { tolerance: number ): boolean { const signatureFound = !!details.signatures.filter( - platformFunctions!.secureCompare.bind( - platformFunctions, - expectedSignature - ) + platformFunctions.secureCompare.bind(platformFunctions, expectedSignature) ).length; if (!signatureFound) { @@ -353,9 +350,9 @@ function createWebhooks(platformFunctions: PlatformFunctions): WebhookObject { * Lazily instantiate a CryptoProvider instance. This is a stateless object * so a singleton can be used here. */ - function getNodeCryptoProvider(): StripeCryptoProvider { + function getCryptoProvider(): StripeCryptoProvider { if (!webhooksCryptoProviderInstance) { - webhooksCryptoProviderInstance = platformFunctions.createNodeCryptoProvider(); + webhooksCryptoProviderInstance = platformFunctions.createCryptoProvider(); } return webhooksCryptoProviderInstance!; } diff --git a/src/crypto/SubtleCryptoProvider.ts b/src/crypto/SubtleCryptoProvider.ts index 999181e4cc..886ac469d5 100644 --- a/src/crypto/SubtleCryptoProvider.ts +++ b/src/crypto/SubtleCryptoProvider.ts @@ -8,7 +8,7 @@ import CryptoProvider = require('./CryptoProvider'); class SubtleCryptoProvider extends CryptoProvider { subtleCrypto: SubtleCrypto; - constructor(subtleCrypto: SubtleCrypto) { + constructor(subtleCrypto?: SubtleCrypto) { super(); // If no subtle crypto is interface, default to the global namespace. This diff --git a/src/platform/NodePlatformFunctions.ts b/src/platform/NodePlatformFunctions.ts index c0ec38e62d..6354983cba 100644 --- a/src/platform/NodePlatformFunctions.ts +++ b/src/platform/NodePlatformFunctions.ts @@ -132,10 +132,21 @@ class NodePlatformFunctions extends PlatformFunctions { return new NodeHttpClient(agent); } + /** @override */ + createHttpClient(agent?: http.Agent): typeof HttpClient { + // @ts-ignore + return new NodeHttpClient(agent); + } + /** @override */ createNodeCryptoProvider(): StripeCryptoProvider { return new NodeCryptoProvider(); } + + /** @override */ + createCryptoProvider(): StripeCryptoProvider { + return this.createNodeCryptoProvider(); + } } export = NodePlatformFunctions; diff --git a/src/platform/PlatformFunctions.ts b/src/platform/PlatformFunctions.ts index 0a72973d62..c0d5c1835e 100644 --- a/src/platform/PlatformFunctions.ts +++ b/src/platform/PlatformFunctions.ts @@ -12,6 +12,14 @@ import SubtleCryptoProvider = require('../crypto/SubtleCryptoProvider'); * implementations depend on the platform / JS runtime. */ class PlatformFunctions { + _fetchFn: any | null; + _agent: http.Agent | null; + + constructor() { + this._fetchFn = null; + this._agent = null; + } + /** * Gets uname with Node's built-in `exec` function, if available. */ @@ -67,7 +75,7 @@ class PlatformFunctions { * Creates an HTTP client which uses the Node `http` and `https` packages * to issue requests. */ - createNodeHttpClient(agent: http.Agent): typeof HttpClient { + createNodeHttpClient(agent?: http.Agent | null): typeof HttpClient { throw new Error('createNodeHttpClient not implemented.'); } @@ -78,11 +86,18 @@ class PlatformFunctions { * A fetch function can optionally be passed in as a parameter. If none is * passed, will default to the default `fetch` function in the global scope. */ - createFetchHttpClient(fetchFn: typeof fetch): typeof HttpClient { + createFetchHttpClient(fetchFn?: typeof fetch | null): typeof HttpClient { // @ts-ignore return new FetchHttpClient(fetchFn); } + /** + * Creates an HTTP client using runtime-specific APIs. + */ + createHttpClient(agent?: http.Agent | null): typeof HttpClient { + throw new Error('createHttpClient not implemented.'); + } + /** * Creates a CryptoProvider which uses the Node `crypto` package for its computations. */ @@ -94,10 +109,14 @@ class PlatformFunctions { * Creates a CryptoProvider which uses the SubtleCrypto interface of the Web Crypto API. */ createSubtleCryptoProvider( - subtleCrypto: typeof crypto.subtle + subtleCrypto?: typeof crypto.subtle ): StripeCryptoProvider { return new SubtleCryptoProvider(subtleCrypto); } + + createCryptoProvider(): StripeCryptoProvider { + throw new Error('createCryptoProvider not implemented.'); + } } export = PlatformFunctions; diff --git a/src/platform/WebPlatformFunctions.ts b/src/platform/WebPlatformFunctions.ts index 40536fa842..1c5c3326de 100644 --- a/src/platform/WebPlatformFunctions.ts +++ b/src/platform/WebPlatformFunctions.ts @@ -31,18 +31,28 @@ class WebPlatformFunctions extends PlatformFunctions { } /** @override */ - createNodeHttpClient(agent: http.Agent): typeof HttpClient { + createNodeHttpClient(): typeof HttpClient { throw new Error( 'Stripe: `createNodeHttpClient()` is not available in non-Node environments. Please use `createFetchHttpClient()` instead.' ); } + /** @override */ + createHttpClient(): typeof HttpClient { + return super.createFetchHttpClient(); + } + /** @override */ createNodeCryptoProvider(): StripeCryptoProvider { throw new Error( 'Stripe: `createNodeCryptoProvider()` is not available in non-Node environments. Please use `createSubtleCryptoProvider()` instead.' ); } + + /** @override */ + createCryptoProvider(): StripeCryptoProvider { + return this.createSubtleCryptoProvider(); + } } export = WebPlatformFunctions; diff --git a/src/stripe.common.ts b/src/stripe.common.ts index 8e630887b0..f88dde17f9 100644 --- a/src/stripe.common.ts +++ b/src/stripe.common.ts @@ -39,7 +39,7 @@ import CryptoProvider = require('./crypto/CryptoProvider'); import PlatformFunctions = require('./platform/PlatformFunctions'); import createWebhooks = require('./Webhooks'); -function createStripe(platformFunctions: PlatformFunctions): any { +function createStripe(platformFunctions: PlatformFunctions): typeof Stripe { Stripe.PACKAGE_VERSION = require('../package.json').version; Stripe.USER_AGENT = { bindings_version: Stripe.PACKAGE_VERSION,