UNPKG

@getopenpay/client

Version:

OpenPay API TypeScript SDK

129 lines (128 loc) 5.53 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.WebhookUtils = exports.SignatureVersion = exports.InvalidSignatureError = void 0; const CryptoJS = __importStar(require("crypto-js")); const EXPECTED_TIMESTAMP_MARKER = 't'; /** * Raised when a webhook event signature is invalid. */ class InvalidSignatureError extends Error { constructor() { super('Invalid signature'); this.name = 'InvalidSignatureError'; } } exports.InvalidSignatureError = InvalidSignatureError; /** * Supported signature versions. */ var SignatureVersion; (function (SignatureVersion) { SignatureVersion["V1"] = "v1"; })(SignatureVersion || (exports.SignatureVersion = SignatureVersion = {})); class WebhookUtils { constructor() { } /** * Verification algorithm for OpenPay v1 event signatures. * See _verifySignature for usage. */ _verifyV1Signature(payload, timestamp, secretKey, signatureDigest) { const signaturePayload = `${timestamp}.${payload}`; const expectedSignature = CryptoJS.HmacSHA256(signaturePayload, secretKey).toString(); return signatureDigest === expectedSignature; } /** * Verifies the signature string for the event message. * * @param version - The signature version. * @param payload - The serialized event data JSON. * @param timestamp - The timestamp of the signature. * @param secretKey - The secret key to use for the signature. * @param signatureDigest - The signature digest to validate. * @returns True if the signature is valid, False otherwise. * @throws Error if the signature version is not supported. */ _verifySignature(version, payload, timestamp, secretKey, signatureDigest) { // Check if version is a valid SignatureVersion if (!Object.keys(SignatureVersion).some(key => SignatureVersion[key] === version)) { throw new Error(`Signature version ${version} is not supported`); } if (version === SignatureVersion.V1) { return this._verifyV1Signature(payload, timestamp, secretKey, signatureDigest); } // Should never reach here if all enum values are properly handled return false; } /** * Extracts the timestamp from the signature digest. * * @param signatureDigest - The signature digest to extract the timestamp from. * @returns The timestamp extracted from the signature digest. */ extractTimestampFromDigest(signatureDigest) { const parts = signatureDigest.split(','); const [timestampMarker, timestampValue] = parts[0].split('='); if (timestampMarker !== EXPECTED_TIMESTAMP_MARKER) { throw new InvalidSignatureError(); } const timestamp = parseInt(timestampValue, 10); if (isNaN(timestamp)) { throw new InvalidSignatureError(); } return timestamp; } /** * Validates a webhook event payload using the value of the * signature digest header and a secret key. * * @param eventData - The serialized event data JSON. This is the value of the `data` field in the event payload. * @param signatureDigest - The signature digest to validate. This is the value of the `signature-digest` field in the event payload. * @param secret - The secret key to use for the signature. This is autogenerated when you create a webhook endpoint. You can find it in the OpenPay dashboard. * @throws InvalidSignatureError if the signature is invalid. */ validatePayload(eventData, signatureDigest, secret) { const timestamp = this.extractTimestampFromDigest(signatureDigest); const parts = signatureDigest.split(','); const digestTuples = parts.slice(1).map(p => p.split('=')); const verifiedSignatures = digestTuples.map(([digestVersion, digest]) => { return this._verifySignature(digestVersion, eventData, timestamp, secret, digest); }); if (!verifiedSignatures.some(Boolean)) { throw new InvalidSignatureError(); } } } exports.WebhookUtils = WebhookUtils;