Files
Emailsorter/server/node_modules/stripe/esm/Webhooks.js
ANDJ abf761db07 Email Sorter Beta
Ich habe soweit automatisiert the Emails sortieren aber ich muss noch schauen was es fur bugs es gibt wenn die app online  ist deswegen wurde ich mit diesen Commit die website veroffentlichen obwohjl es sein konnte  das es noch nicht fertig ist und verkaufs bereit
2026-01-22 19:32:12 +01:00

209 lines
11 KiB
JavaScript

import { StripeError, StripeSignatureVerificationError } from './Error.js';
import { CryptoProviderOnlySupportsAsyncError, } from './crypto/CryptoProvider.js';
export function createWebhooks(platformFunctions) {
const Webhook = {
DEFAULT_TOLERANCE: 300,
// @ts-ignore
signature: null,
constructEvent(payload, header, secret, tolerance, cryptoProvider, receivedAt) {
try {
this.signature.verifyHeader(payload, header, secret, tolerance || Webhook.DEFAULT_TOLERANCE, cryptoProvider, receivedAt);
}
catch (e) {
if (e instanceof CryptoProviderOnlySupportsAsyncError) {
e.message +=
'\nUse `await constructEventAsync(...)` instead of `constructEvent(...)`';
}
throw e;
}
const jsonPayload = payload instanceof Uint8Array
? JSON.parse(new TextDecoder('utf8').decode(payload))
: JSON.parse(payload);
return jsonPayload;
},
async constructEventAsync(payload, header, secret, tolerance, cryptoProvider, receivedAt) {
await this.signature.verifyHeaderAsync(payload, header, secret, tolerance || Webhook.DEFAULT_TOLERANCE, cryptoProvider, receivedAt);
const jsonPayload = payload instanceof Uint8Array
? JSON.parse(new TextDecoder('utf8').decode(payload))
: JSON.parse(payload);
return jsonPayload;
},
/**
* Generates a header to be used for webhook mocking
*
* @typedef {object} opts
* @property {number} timestamp - Timestamp of the header. Defaults to Date.now()
* @property {string} payload - JSON stringified payload object, containing the 'id' and 'object' parameters
* @property {string} secret - Stripe webhook secret 'whsec_...'
* @property {string} scheme - Version of API to hit. Defaults to 'v1'.
* @property {string} signature - Computed webhook signature
* @property {CryptoProvider} cryptoProvider - Crypto provider to use for computing the signature if none was provided. Defaults to NodeCryptoProvider.
*/
generateTestHeaderString: function (opts) {
const preparedOpts = prepareOptions(opts);
const signature = preparedOpts.signature ||
preparedOpts.cryptoProvider.computeHMACSignature(preparedOpts.payloadString, preparedOpts.secret);
return preparedOpts.generateHeaderString(signature);
},
generateTestHeaderStringAsync: async function (opts) {
const preparedOpts = prepareOptions(opts);
const signature = preparedOpts.signature ||
(await preparedOpts.cryptoProvider.computeHMACSignatureAsync(preparedOpts.payloadString, preparedOpts.secret));
return preparedOpts.generateHeaderString(signature);
},
};
const signature = {
EXPECTED_SCHEME: 'v1',
verifyHeader(encodedPayload, encodedHeader, secret, tolerance, cryptoProvider, receivedAt) {
const { decodedHeader: header, decodedPayload: payload, details, suspectPayloadType, } = parseEventDetails(encodedPayload, encodedHeader, this.EXPECTED_SCHEME);
const secretContainsWhitespace = /\s/.test(secret);
cryptoProvider = cryptoProvider || getCryptoProvider();
const expectedSignature = cryptoProvider.computeHMACSignature(makeHMACContent(payload, details), secret);
validateComputedSignature(payload, header, details, expectedSignature, tolerance, suspectPayloadType, secretContainsWhitespace, receivedAt);
return true;
},
async verifyHeaderAsync(encodedPayload, encodedHeader, secret, tolerance, cryptoProvider, receivedAt) {
const { decodedHeader: header, decodedPayload: payload, details, suspectPayloadType, } = parseEventDetails(encodedPayload, encodedHeader, this.EXPECTED_SCHEME);
const secretContainsWhitespace = /\s/.test(secret);
cryptoProvider = cryptoProvider || getCryptoProvider();
const expectedSignature = await cryptoProvider.computeHMACSignatureAsync(makeHMACContent(payload, details), secret);
return validateComputedSignature(payload, header, details, expectedSignature, tolerance, suspectPayloadType, secretContainsWhitespace, receivedAt);
},
};
function makeHMACContent(payload, details) {
return `${details.timestamp}.${payload}`;
}
function parseEventDetails(encodedPayload, encodedHeader, expectedScheme) {
if (!encodedPayload) {
throw new StripeSignatureVerificationError(encodedHeader, encodedPayload, {
message: 'No webhook payload was provided.',
});
}
const suspectPayloadType = typeof encodedPayload != 'string' &&
!(encodedPayload instanceof Uint8Array);
const textDecoder = new TextDecoder('utf8');
const decodedPayload = encodedPayload instanceof Uint8Array
? textDecoder.decode(encodedPayload)
: encodedPayload;
// Express's type for `Request#headers` is `string | []string`
// which is because the `set-cookie` header is an array,
// but no other headers are an array (docs: https://nodejs.org/api/http.html#http_message_headers)
// (Express's Request class is an extension of http.IncomingMessage, and doesn't appear to be relevantly modified: https://github.com/expressjs/express/blob/master/lib/request.js#L31)
if (Array.isArray(encodedHeader)) {
throw new Error('Unexpected: An array was passed as a header, which should not be possible for the stripe-signature header.');
}
if (encodedHeader == null || encodedHeader == '') {
throw new StripeSignatureVerificationError(encodedHeader, encodedPayload, {
message: 'No stripe-signature header value was provided.',
});
}
const decodedHeader = encodedHeader instanceof Uint8Array
? textDecoder.decode(encodedHeader)
: encodedHeader;
const details = parseHeader(decodedHeader, expectedScheme);
if (!details || details.timestamp === -1) {
throw new StripeSignatureVerificationError(decodedHeader, decodedPayload, {
message: 'Unable to extract timestamp and signatures from header',
});
}
if (!details.signatures.length) {
throw new StripeSignatureVerificationError(decodedHeader, decodedPayload, {
message: 'No signatures found with expected scheme',
});
}
return {
decodedPayload,
decodedHeader,
details,
suspectPayloadType,
};
}
function validateComputedSignature(payload, header, details, expectedSignature, tolerance, suspectPayloadType, secretContainsWhitespace, receivedAt) {
const signatureFound = !!details.signatures.filter(platformFunctions.secureCompare.bind(platformFunctions, expectedSignature)).length;
const docsLocation = '\nLearn more about webhook signing and explore webhook integration examples for various frameworks at ' +
'https://docs.stripe.com/webhooks/signature';
const whitespaceMessage = secretContainsWhitespace
? '\n\nNote: The provided signing secret contains whitespace. This often indicates an extra newline or space is in the value'
: '';
if (!signatureFound) {
if (suspectPayloadType) {
throw new StripeSignatureVerificationError(header, payload, {
message: 'Webhook payload must be provided as a string or a Buffer (https://nodejs.org/api/buffer.html) instance representing the _raw_ request body.' +
'Payload was provided as a parsed JavaScript object instead. \n' +
'Signature verification is impossible without access to the original signed material. \n' +
docsLocation +
'\n' +
whitespaceMessage,
});
}
throw new StripeSignatureVerificationError(header, payload, {
message: 'No signatures found matching the expected signature for payload.' +
' Are you passing the raw request body you received from Stripe? \n' +
' If a webhook request is being forwarded by a third-party tool,' +
' ensure that the exact request body, including JSON formatting and new line style, is preserved.\n' +
docsLocation +
'\n' +
whitespaceMessage,
});
}
const timestampAge = Math.floor((typeof receivedAt === 'number' ? receivedAt : Date.now()) / 1000) - details.timestamp;
if (tolerance > 0 && timestampAge > tolerance) {
// @ts-ignore
throw new StripeSignatureVerificationError(header, payload, {
message: 'Timestamp outside the tolerance zone',
});
}
return true;
}
function parseHeader(header, scheme) {
if (typeof header !== 'string') {
return null;
}
return header.split(',').reduce((accum, item) => {
const kv = item.split('=');
if (kv[0] === 't') {
accum.timestamp = parseInt(kv[1], 10);
}
if (kv[0] === scheme) {
accum.signatures.push(kv[1]);
}
return accum;
}, {
timestamp: -1,
signatures: [],
});
}
let webhooksCryptoProviderInstance = null;
/**
* Lazily instantiate a CryptoProvider instance. This is a stateless object
* so a singleton can be used here.
*/
function getCryptoProvider() {
if (!webhooksCryptoProviderInstance) {
webhooksCryptoProviderInstance = platformFunctions.createDefaultCryptoProvider();
}
return webhooksCryptoProviderInstance;
}
function prepareOptions(opts) {
if (!opts) {
throw new StripeError({
message: 'Options are required',
});
}
const timestamp = Math.floor(opts.timestamp) || Math.floor(Date.now() / 1000);
const scheme = opts.scheme || signature.EXPECTED_SCHEME;
const cryptoProvider = opts.cryptoProvider || getCryptoProvider();
const payloadString = `${timestamp}.${opts.payload}`;
const generateHeaderString = (signature) => {
return `t=${timestamp},${scheme}=${signature}`;
};
return Object.assign(Object.assign({}, opts), { timestamp,
scheme,
cryptoProvider,
payloadString,
generateHeaderString });
}
Webhook.signature = signature;
return Webhook;
}