simplepay-js-sdk 0.12.2 → 0.12.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import l from "crypto";
2
- const d = ["HUF", "HUF_SZEP", "EUR", "USD"], i = (...e) => {
2
+ const g = ["HUF", "HUF_SZEP", "EUR", "USD"], i = (...e) => {
3
3
  process.env.SIMPLEPAY_LOGGER === "true" && console.log("👉 ", ...e);
4
4
  }, E = (e) => {
5
- if (!d.includes(e))
5
+ if (!g.includes(e))
6
6
  throw new Error(`Unsupported currency: ${e}`);
7
- const n = "https://secure.simplepay.hu/payment/v2", r = "https://sandbox.simplepay.hu/payment/v2", t = "SimplePay_Rrd_0.12.1", s = process.env[`SIMPLEPAY_MERCHANT_KEY_${e}`], c = process.env[`SIMPLEPAY_MERCHANT_ID_${e}`], o = process.env.SIMPLEPAY_PRODUCTION === "true" ? n : r, u = o + "/start", R = o + "/dorecurring", a = o + "/cardcancel";
7
+ const n = "https://secure.simplepay.hu/payment/v2", r = "https://sandbox.simplepay.hu/payment/v2", t = "SimplePay_Rrd_0.12.2", s = process.env[`SIMPLEPAY_MERCHANT_KEY_${e}`], c = process.env[`SIMPLEPAY_MERCHANT_ID_${e}`], o = process.env.SIMPLEPAY_PRODUCTION === "true" ? n : r, u = o + "/start", R = o + "/dorecurring", a = o + "/cardcancel";
8
8
  return {
9
9
  MERCHANT_KEY: s,
10
10
  MERCHANT_ID: c,
@@ -13,7 +13,7 @@ const d = ["HUF", "HUF_SZEP", "EUR", "USD"], i = (...e) => {
13
13
  API_URL_CARD_CANCEL: a,
14
14
  SDK_VERSION: t
15
15
  };
16
- }, g = (e) => JSON.stringify(e).replace(/\//g, "\\/"), m = (e, n) => {
16
+ }, d = (e) => JSON.stringify(e).replace(/\//g, "\\/"), m = (e, n) => {
17
17
  const r = l.createHmac("sha384", n.trim());
18
18
  return r.update(e, "utf8"), r.digest("base64");
19
19
  }, _ = (e, n, r) => n === m(e, r), S = (e) => e.toISOString().replace(/\.\d{3}Z$/, "+00:00"), p = (e) => {
@@ -24,7 +24,7 @@ const d = ["HUF", "HUF_SZEP", "EUR", "USD"], i = (...e) => {
24
24
  throw new Error(`Merchant id not found in the environment: ${e}`);
25
25
  return n;
26
26
  }, A = async (e, n, r) => P(e, n, r, "oneTime"), I = async (e, n, r) => P(e, n, r, "recurring"), f = async (e, n, r) => P(e, n, r, "token"), h = async (e, n, r) => P(e, n, r, "cancelCard"), P = async (e, n, r, t) => {
27
- const s = g(n), c = m(s, r);
27
+ const s = d(n), c = m(s, r);
28
28
  i({ function: `SimplePay/makeRequest/${t}`, bodyString: s, signature: c });
29
29
  try {
30
30
  const o = await fetch(e, {
@@ -49,8 +49,8 @@ const d = ["HUF", "HUF_SZEP", "EUR", "USD"], i = (...e) => {
49
49
  } catch (o) {
50
50
  throw o;
51
51
  }
52
- }, U = (e, n) => {
53
- i({ function: "SimplePay/getPaymentResponse", r: e, signature: n }), n = decodeURIComponent(n);
52
+ }, w = (e, n) => {
53
+ i({ function: "SimplePay/getPaymentResponse", r: e, signature: n }), n = n.replace(/ /g, "+");
54
54
  const r = Buffer.from(e, "base64").toString("utf-8"), t = JSON.parse(r), s = p(t.m), { MERCHANT_KEY: c } = E(s);
55
55
  if (!_(r, n, c || ""))
56
56
  throw i({ function: "SimplePay/getPaymentResponse", rDecoded: r, signature: n }), new Error("Invalid response signature");
@@ -63,7 +63,7 @@ const d = ["HUF", "HUF_SZEP", "EUR", "USD"], i = (...e) => {
63
63
  orderRef: o.o,
64
64
  tokens: o.tokens
65
65
  };
66
- }, w = (e, n, r) => {
66
+ }, U = (e, n, r) => {
67
67
  if (i({ function: "SimplePay/handleIpnRequest", ipnBody: e, incomingSignature: n }), !_(e, n, r))
68
68
  throw new Error("Invalid IPN request signature");
69
69
  JSON.parse(e);
@@ -160,8 +160,8 @@ export {
160
160
  v as cancelCard,
161
161
  _ as checkSignature,
162
162
  m as generateSignature,
163
- U as getPaymentResponse,
164
- w as handleIpnRequest,
163
+ w as getPaymentResponse,
164
+ U as handleIpnRequest,
165
165
  L as startPayment,
166
166
  H as startRecurringPayment,
167
167
  k as startTokenPayment,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/types.ts","../src/utils.ts","../src/oneTime.ts","../src/recurring.ts"],"sourcesContent":["export type PaymentMethod = 'CARD' | 'WIRE'\n\nexport const CURRENCIES = ['HUF', 'HUF_SZEP', 'EUR', 'USD'] as const\nexport type Currency = typeof CURRENCIES[number]\n\nexport const LANGUAGES = [\n 'AR', // Arabic\n 'BG', // Bulgarian\n 'CS', // Czech\n 'DE', // German\n 'EN', // English\n 'ES', // Spanish\n 'FR', // French\n 'IT', // Italian\n 'HR', // Croatian\n 'HU', // Hungarian\n 'PL', // Polish\n 'RO', // Romanian\n 'RU', // Russian\n 'SK', // Slovak\n 'TR', // Turkish\n 'ZH', // Chinese\n] as const\nexport type Language = typeof LANGUAGES[number]\n\nexport interface PaymentData {\n orderRef: string\n total: number | string\n customerEmail: string\n currency?: Currency\n language?: Language\n method?: PaymentMethod\n invoice?: {\n name: string\n country: string\n state: string\n city: string\n zip: string\n address: string\n address2?: string\n phone?: string\n }\n}\n\nexport interface PaymentConfig {\n redirectUrl?: string\n}\n\nexport type ISO8601DateString = string\nexport interface Recurring {\n times: number,\n until: ISO8601DateString,\n maxAmount: number\n}\nexport interface RecurringPaymentData extends PaymentData {\n customer: string,\n recurring: Recurring\n}\n\nexport interface TokenPaymentData extends Omit<PaymentData, 'method'> {\n method: 'CARD',\n customer: string,\n token: string\n}\n\nexport interface SimplePayRequestBody extends Omit<PaymentData, 'total'> {\n total: string\n salt: string\n merchant: string\n sdkVersion: string\n methods: PaymentMethod[]\n timeout: string\n url: string\n}\n\nexport interface SimplePayRecurringRequestBody extends SimplePayRequestBody {\n customer: string\n recurring: Recurring\n threeDSReqAuthMethod: '02' // only registered users can use this\n}\n\nexport interface SimplePayTokenRequestBody extends SimplePayRequestBody {\n customer: string\n token: string\n threeDSReqAuthMethod: '02' // only registered users can use this\n type: 'MIT' // Merchant Initiated Transaction\n}\n\nexport interface SimplePayCancelCardRequestBody {\n salt: string\n cardId: string\n merchant: string\n sdkVersion: string\n}\n\nexport interface SimplePayResponse {\n salt: string\n merchant: string\n orderRef: string\n currency: Currency\n transactionId: string\n timeout: ISO8601DateString\n total: string\n paymentUrl: string\n errorCodes?: string[]\n}\n\nexport interface SimplePayRecurringResponse extends SimplePayResponse {\n tokens: string[]\n}\n\nexport interface SimplePayTokenResponse extends Omit<SimplePayResponse, 'paymentUrl' | 'timeout'> { }\n\nexport interface SimplePayCancelCardResponse {\n salt: string\n merchant: string\n cardId: string\n status: 'DISABLED'\n expiry: string\n}\n\nexport type SimplePayEvents = 'SUCCESS' | 'FAIL' | 'TIMEOUT' | 'CANCEL'\n\nexport interface SimplePayAPIResult {\n r: number // response code\n t: string // transaction id\n e: SimplePayEvents // event\n m: string // merchant id\n o: string // order id\n}\n\nexport interface SimplePayResult {\n responseCode: number,\n transactionId: string,\n event: SimplePayEvents,\n merchantId: string,\n orderRef: string,\n tokens?: string[],\n}\n\nexport interface SimplePayIPNResponse {\n salt: string\n orderRef: string\n method: string\n merchant: string\n finishDate: string\n paymentDate: string\n transactionId: number\n status: 'FINISHED' | 'AUTHORIZED' | 'NOTAUTHORIZED' | 'REVERSED' | 'CANCELLED' | 'TIMEOUT'\n receiveDate: string\n expiry?: string\n cardMask?: string\n}\n","import crypto from 'crypto'\nimport { CURRENCIES, Currency, ISO8601DateString, SimplePayAPIResult, SimplePayCancelCardRequestBody, SimplePayCancelCardResponse, SimplePayRecurringRequestBody, SimplePayRecurringResponse, SimplePayRequestBody, SimplePayResponse, SimplePayResult, SimplePayTokenRequestBody, SimplePayTokenResponse } from \"./types\"\n\nexport const simplepayLogger = (...args: any[]) => {\n if (process.env.SIMPLEPAY_LOGGER !== 'true') {\n return\n }\n\n console.log('👉 ', ...args)\n}\n\nexport const getSimplePayConfig = (currency: Currency) => {\n if (!CURRENCIES.includes(currency)) {\n throw new Error(`Unsupported currency: ${currency}`)\n }\n\n const SIMPLEPAY_API_URL = 'https://secure.simplepay.hu/payment/v2'\n const SIMPLEPAY_SANDBOX_URL = 'https://sandbox.simplepay.hu/payment/v2'\n const SDK_VERSION = 'SimplePay_Rrd_0.12.1'\n const MERCHANT_KEY = process.env[`SIMPLEPAY_MERCHANT_KEY_${currency}`]\n const MERCHANT_ID = process.env[`SIMPLEPAY_MERCHANT_ID_${currency}`]\n\n const API_URL = process.env.SIMPLEPAY_PRODUCTION === 'true' ? SIMPLEPAY_API_URL : SIMPLEPAY_SANDBOX_URL\n const API_URL_PAYMENT = API_URL + '/start'\n const API_URL_RECURRING = API_URL + '/dorecurring'\n const API_URL_CARD_CANCEL = API_URL + '/cardcancel'\n return {\n MERCHANT_KEY,\n MERCHANT_ID,\n API_URL_PAYMENT,\n API_URL_RECURRING,\n API_URL_CARD_CANCEL,\n SDK_VERSION\n }\n}\n\n// escaping slashes for the request body to prevent strange SimplePay API errors (eg Missing Signature)\nexport const prepareRequestBody = (body: any) =>\n JSON.stringify(body).replace(/\\//g, '\\\\/')\n\nexport const generateSignature = (body: string, merchantKey: string) => {\n const hmac = crypto.createHmac('sha384', merchantKey.trim())\n hmac.update(body, 'utf8')\n return hmac.digest('base64')\n}\n\nexport const checkSignature = (responseText: string, signature: string, merchantKey: string) =>\n signature === generateSignature(responseText, merchantKey)\n\nexport const toISO8601DateString = (date: Date): ISO8601DateString => date.toISOString().replace(/\\.\\d{3}Z$/, '+00:00')\n\nexport const getCurrencyFromMerchantId = (merchantId: string) => {\n const currency = Object.entries(process.env)\n .find(([key, value]) =>\n key.startsWith('SIMPLEPAY_MERCHANT_ID_') && value === merchantId\n )?.[0]?.replace('SIMPLEPAY_MERCHANT_ID_', '') as Currency\n\n if (!currency) {\n throw new Error(`Merchant id not found in the environment: ${merchantId}`)\n }\n\n return currency\n}\n\nexport const makeSimplePayRequest = async (apiUrl: string, requestBody: SimplePayRequestBody, merchantKey: string) => {\n return makeRequest(apiUrl, requestBody, merchantKey, 'oneTime') as Promise<SimplePayResponse>\n}\n\nexport const makeSimplePayRecurringRequest = async (apiUrl: string, requestBody: SimplePayRecurringRequestBody, merchantKey: string) => {\n return makeRequest(apiUrl, requestBody, merchantKey, 'recurring') as Promise<SimplePayRecurringResponse>\n}\n\nexport const makeSimplePayTokenRequest = async (apiUrl: string, requestBody: SimplePayTokenRequestBody, merchantKey: string) => {\n return makeRequest(apiUrl, requestBody, merchantKey, 'token') as Promise<SimplePayTokenResponse>\n}\n\nexport const makeSimplePayCancelCardRequest = async (apiUrl: string, requestBody: SimplePayCancelCardRequestBody, merchantKey: string) => {\n return makeRequest(apiUrl, requestBody, merchantKey, 'cancelCard') as Promise<SimplePayCancelCardResponse>\n}\n\nconst makeRequest = async (apiUrl: string, requestBody: SimplePayRequestBody | SimplePayRecurringRequestBody | SimplePayTokenRequestBody | SimplePayCancelCardRequestBody, merchantKey: string, type: 'oneTime' | 'recurring' | 'token' | 'cancelCard') => {\n const bodyString = prepareRequestBody(requestBody)\n const signature = generateSignature(bodyString, merchantKey)\n simplepayLogger({ function: `SimplePay/makeRequest/${type}`, bodyString, signature })\n\n try {\n const response = await fetch(apiUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Signature': signature,\n },\n body: bodyString,\n })\n\n simplepayLogger({ function: `SimplePay/makeRequest/${type}`, response })\n\n if (!response.ok) {\n throw new Error(`SimplePay API error: ${response.status}`)\n }\n\n const responseSignature = response.headers.get('Signature')\n simplepayLogger({ function: `SimplePay/makeRequest/${type}`, responseSignature })\n if (!responseSignature) {\n throw new Error('Missing response signature')\n }\n\n const responseText = await response.text()\n const responseJSON = JSON.parse(responseText) as { errorCodes?: string[] }\n simplepayLogger({ function: `SimplePay/makeRequest/${type}`, responseText, responseJSON })\n\n if (responseJSON.errorCodes) {\n throw new Error(`SimplePay API error: ${responseJSON.errorCodes}`)\n }\n\n if (!checkSignature(responseText, responseSignature, merchantKey)) {\n throw new Error('Invalid response signature')\n }\n\n return responseJSON\n\n } catch (error) {\n throw error\n }\n}\n\nexport const getPaymentResponse = (r: string, signature: string) => {\n simplepayLogger({ function: 'SimplePay/getPaymentResponse', r, signature })\n signature = decodeURIComponent(signature)\n const rDecoded = Buffer.from(r, 'base64').toString('utf-8')\n const rDecodedJSON = JSON.parse(rDecoded) as SimplePayAPIResult\n const currency = getCurrencyFromMerchantId(rDecodedJSON.m)\n const { MERCHANT_KEY } = getSimplePayConfig(currency as Currency)\n\n if (!checkSignature(rDecoded, signature, MERCHANT_KEY || '')) {\n simplepayLogger({ function: 'SimplePay/getPaymentResponse', rDecoded, signature })\n throw new Error('Invalid response signature')\n }\n\n const responseJson = JSON.parse(rDecoded)\n const response: SimplePayResult = {\n responseCode: responseJson.r,\n transactionId: responseJson.t,\n event: responseJson.e,\n merchantId: responseJson.m,\n orderRef: responseJson.o,\n tokens: responseJson.tokens,\n }\n\n return response\n}\n\n/**\n * Handles IPN (Instant Payment Notification) request and generates response\n * \n * This function implements the IPN flow according to SimplePay requirements:\n * 1. Validates the incoming signature\n * 2. Adds receiveDate property to the response (preserving original field order and data types)\n * 3. Generates response signature\n * \n * **IMPORTANT**: The responseBody must be sent EXACTLY as returned, without any modifications.\n * Do NOT:\n * - Re-format or pretty-print the JSON\n * - Parse and re-stringify the JSON\n * - Add any whitespace or formatting\n * - Modify the Content-Type header (must be 'application/json')\n * \n * The signature is calculated on the exact string that will be sent in the HTTP body.\n * Any modification to the responseBody will invalidate the signature.\n * \n * @param ipnBody - The raw IPN request body as string (must be the exact string received, not parsed JSON)\n * @param incomingSignature - The signature from the 'Signature' HTTP header\n * @param merchantKey - The merchant secret key for signature validation and generation\n * @returns Object containing the response JSON string and signature to send back\n * \n * @example\n * // In your IPN endpoint handler:\n * const ipnBody = await request.text() // Get raw body as string (IMPORTANT: use .text(), not JSON.parse())\n * const incomingSignature = request.headers.get('Signature')\n * const { responseBody, signature } = handleIpnRequest(ipnBody, incomingSignature, MERCHANT_KEY)\n * \n * // Send response with HTTP 200 status\n * // CRITICAL: Send responseBody exactly as returned, do not modify it!\n * return new Response(responseBody, {\n * status: 200,\n * headers: {\n * 'Content-Type': 'application/json',\n * 'Signature': signature\n * }\n * })\n */\nexport const handleIpnRequest = (ipnBody: string, incomingSignature: string, merchantKey: string) => {\n simplepayLogger({ function: 'SimplePay/handleIpnRequest', ipnBody, incomingSignature })\n \n // Step 1: Validate incoming signature\n if (!checkSignature(ipnBody, incomingSignature, merchantKey)) {\n throw new Error('Invalid IPN request signature')\n }\n \n // Step 2: Validate it's valid JSON (but don't use parsed object to preserve field order and data types)\n JSON.parse(ipnBody) // Just validate, don't use the result\n \n // Step 3: Add receiveDate to the original JSON string while preserving:\n // - Exact field order\n // - Exact data types (numeric vs string)\n // - No whitespace (compact JSON)\n // \n // Use the same simple approach as the working solution:\n // Replace the closing brace with: ,\"receiveDate\":\"${receiveDate}\"}\n // This preserves the exact original format and field order\n const receiveDate = toISO8601DateString(new Date())\n \n // Simple string replacement: replace the first (and only) closing brace\n // This is the same approach as the working solution\n const responseBody = ipnBody.replace('}', `,\"receiveDate\":\"${receiveDate}\"}`)\n \n // Step 4: Generate response signature using SHA384 HMAC + Base64\n // The signature must be calculated on the exact string that will be sent\n const responseSignature = generateSignature(responseBody, merchantKey)\n \n simplepayLogger({ function: 'SimplePay/handleIpnRequest', responseBody, responseSignature })\n \n return {\n responseBody,\n signature: responseSignature\n }\n}\n","import crypto from 'crypto'\nimport { Currency, PaymentConfig, PaymentData, SimplePayRequestBody } from './types'\nimport { simplepayLogger, getSimplePayConfig, toISO8601DateString, makeSimplePayRequest } from './utils'\n\nconst startPayment = async (paymentData: PaymentData, config: PaymentConfig = {}) => {\n simplepayLogger({ function: 'SimplePay/startPayment', paymentData })\n const currency = paymentData.currency || 'HUF'\n const { MERCHANT_KEY, MERCHANT_ID, API_URL_PAYMENT, SDK_VERSION } = getSimplePayConfig(currency)\n simplepayLogger({ function: 'SimplePay/startPayment', MERCHANT_KEY, MERCHANT_ID, API_URL_PAYMENT })\n\n if (!MERCHANT_KEY || !MERCHANT_ID) {\n throw new Error(`Missing SimplePay configuration for ${currency}`)\n }\n\n const requestBody: SimplePayRequestBody = {\n salt: crypto.randomBytes(16).toString('hex'),\n merchant: MERCHANT_ID,\n orderRef: paymentData.orderRef,\n currency: currency.replace('_SZEP', '') as Currency,\n customerEmail: paymentData.customerEmail,\n language: paymentData.language || 'HU',\n sdkVersion: SDK_VERSION,\n methods: [paymentData.method || 'CARD'],\n total: String(paymentData.total),\n timeout: toISO8601DateString(new Date(Date.now() + 30 * 60 * 1000)),\n url: config.redirectUrl || process.env.SIMPLEPAY_REDIRECT_URL || 'http://url.to.redirect',\n invoice: paymentData.invoice,\n }\n\n return makeSimplePayRequest(API_URL_PAYMENT, requestBody, MERCHANT_KEY)\n}\n\nexport { startPayment }\n","import crypto from 'crypto'\nimport { SimplePayRecurringRequestBody, RecurringPaymentData, TokenPaymentData, SimplePayTokenRequestBody, SimplePayCancelCardRequestBody, Currency} from './types'\nimport { getSimplePayConfig, simplepayLogger, toISO8601DateString, makeSimplePayTokenRequest, makeSimplePayRecurringRequest, makeSimplePayRequest, makeSimplePayCancelCardRequest} from './utils'\n\nconst INTERVAL_IN_MONTHS = 6\nconst DEFAULT_UNTIL = new Date(Date.now() + INTERVAL_IN_MONTHS * 30 * 24 * 60 * 60 * 1000)\nconst DEFAULT_MAX_AMOUNT = 12000\nconst DEFAULT_TIMES = 3\n\nconst startRecurringPayment = async (paymentData: RecurringPaymentData) => {\n simplepayLogger({ function: 'SimplePay/startRecurringPayment', paymentData })\n const currency = paymentData.currency || 'HUF'\n const { MERCHANT_KEY, MERCHANT_ID, API_URL_PAYMENT, SDK_VERSION } = getSimplePayConfig(currency)\n simplepayLogger({ function: 'SimplePay/startRecurringPayment', MERCHANT_KEY, MERCHANT_ID, API_URL_PAYMENT })\n\n if (!MERCHANT_KEY || !MERCHANT_ID) {\n throw new Error(`Missing SimplePay configuration for ${currency}`)\n }\n\n const requestBody: SimplePayRecurringRequestBody = {\n salt: crypto.randomBytes(16).toString('hex'),\n merchant: MERCHANT_ID,\n orderRef: paymentData.orderRef,\n currency: currency.replace('_SZEP', '') as Currency,\n customer: paymentData.customer,\n customerEmail: paymentData.customerEmail,\n language: paymentData.language || 'HU',\n sdkVersion: SDK_VERSION,\n methods: ['CARD'],\n recurring: {\n times: paymentData.recurring.times || DEFAULT_TIMES,\n until: paymentData.recurring.until || toISO8601DateString(DEFAULT_UNTIL),\n maxAmount: paymentData.recurring.maxAmount || DEFAULT_MAX_AMOUNT\n },\n threeDSReqAuthMethod: '02', \n total: String(paymentData.total),\n timeout: toISO8601DateString(new Date(Date.now() + 30 * 60 * 1000)),\n url: process.env.SIMPLEPAY_REDIRECT_URL || 'http://url.to.redirect',\n invoice: paymentData.invoice,\n }\n\n return makeSimplePayRecurringRequest(API_URL_PAYMENT, requestBody, MERCHANT_KEY)\n}\n\nconst startTokenPayment = async (paymentData: TokenPaymentData) => {\n simplepayLogger({ function: 'SimplePay/startTokenPayment', paymentData })\n const currency = paymentData.currency || 'HUF'\n const { MERCHANT_KEY, MERCHANT_ID, API_URL_RECURRING, SDK_VERSION } = getSimplePayConfig(currency)\n simplepayLogger({ function: 'SimplePay/startTokenPayment', MERCHANT_KEY, MERCHANT_ID, API_URL_RECURRING })\n\n if (!MERCHANT_KEY || !MERCHANT_ID) {\n throw new Error(`Missing SimplePay configuration for ${currency}`)\n }\n\n const requestBody: SimplePayTokenRequestBody = {\n salt: crypto.randomBytes(16).toString('hex'),\n merchant: MERCHANT_ID,\n orderRef: paymentData.orderRef,\n currency: currency.replace('_SZEP', '') as Currency,\n customer: paymentData.customer,\n customerEmail: paymentData.customerEmail,\n language: paymentData.language || 'HU',\n sdkVersion: SDK_VERSION,\n methods: ['CARD'],\n token: paymentData.token,\n type: 'MIT',\n threeDSReqAuthMethod: '02',\n total: String(paymentData.total),\n timeout: toISO8601DateString(new Date(Date.now() + 30 * 60 * 1000)),\n url: process.env.SIMPLEPAY_REDIRECT_URL || 'http://recurring.url.to.redirect',\n invoice: paymentData.invoice,\n }\n\n return makeSimplePayTokenRequest(API_URL_RECURRING, requestBody, MERCHANT_KEY)\n}\n\nconst cancelCard = async (cardId: string) => {\n simplepayLogger({ function: 'SimplePay/cancelCard', cardId })\n const {API_URL_CARD_CANCEL, MERCHANT_KEY, MERCHANT_ID, SDK_VERSION} = getSimplePayConfig('HUF')\n\n if (!MERCHANT_KEY || !MERCHANT_ID) {\n throw new Error(`Missing SimplePay configuration for HUF`)\n }\n\n const requestBody: SimplePayCancelCardRequestBody = {\n salt: crypto.randomBytes(16).toString('hex'),\n cardId,\n merchant: MERCHANT_ID,\n sdkVersion: SDK_VERSION,\n }\n return makeSimplePayCancelCardRequest(API_URL_CARD_CANCEL, requestBody, MERCHANT_KEY)\n}\n\nexport { startRecurringPayment, startTokenPayment , cancelCard}\n"],"names":["CURRENCIES","simplepayLogger","args","getSimplePayConfig","currency","SIMPLEPAY_API_URL","SIMPLEPAY_SANDBOX_URL","SDK_VERSION","MERCHANT_KEY","MERCHANT_ID","API_URL","API_URL_PAYMENT","API_URL_RECURRING","API_URL_CARD_CANCEL","prepareRequestBody","body","generateSignature","merchantKey","hmac","crypto","checkSignature","responseText","signature","toISO8601DateString","date","getCurrencyFromMerchantId","merchantId","key","value","makeSimplePayRequest","apiUrl","requestBody","makeRequest","makeSimplePayRecurringRequest","makeSimplePayTokenRequest","makeSimplePayCancelCardRequest","type","bodyString","response","responseSignature","responseJSON","error","getPaymentResponse","r","rDecoded","rDecodedJSON","responseJson","handleIpnRequest","ipnBody","incomingSignature","receiveDate","responseBody","startPayment","paymentData","config","INTERVAL_IN_MONTHS","DEFAULT_UNTIL","DEFAULT_MAX_AMOUNT","DEFAULT_TIMES","startRecurringPayment","startTokenPayment","cancelCard","cardId"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/types.ts","../src/utils.ts","../src/oneTime.ts","../src/recurring.ts"],"sourcesContent":["export type PaymentMethod = 'CARD' | 'WIRE'\n\nexport const CURRENCIES = ['HUF', 'HUF_SZEP', 'EUR', 'USD'] as const\nexport type Currency = typeof CURRENCIES[number]\n\nexport const LANGUAGES = [\n 'AR', // Arabic\n 'BG', // Bulgarian\n 'CS', // Czech\n 'DE', // German\n 'EN', // English\n 'ES', // Spanish\n 'FR', // French\n 'IT', // Italian\n 'HR', // Croatian\n 'HU', // Hungarian\n 'PL', // Polish\n 'RO', // Romanian\n 'RU', // Russian\n 'SK', // Slovak\n 'TR', // Turkish\n 'ZH', // Chinese\n] as const\nexport type Language = typeof LANGUAGES[number]\n\nexport interface PaymentData {\n orderRef: string\n total: number | string\n customerEmail: string\n currency?: Currency\n language?: Language\n method?: PaymentMethod\n invoice?: {\n name: string\n country: string\n state: string\n city: string\n zip: string\n address: string\n address2?: string\n phone?: string\n }\n}\n\nexport interface PaymentConfig {\n redirectUrl?: string\n}\n\nexport type ISO8601DateString = string\nexport interface Recurring {\n times: number,\n until: ISO8601DateString,\n maxAmount: number\n}\nexport interface RecurringPaymentData extends PaymentData {\n customer: string,\n recurring: Recurring\n}\n\nexport interface TokenPaymentData extends Omit<PaymentData, 'method'> {\n method: 'CARD',\n customer: string,\n token: string\n}\n\nexport interface SimplePayRequestBody extends Omit<PaymentData, 'total'> {\n total: string\n salt: string\n merchant: string\n sdkVersion: string\n methods: PaymentMethod[]\n timeout: string\n url: string\n}\n\nexport interface SimplePayRecurringRequestBody extends SimplePayRequestBody {\n customer: string\n recurring: Recurring\n threeDSReqAuthMethod: '02' // only registered users can use this\n}\n\nexport interface SimplePayTokenRequestBody extends SimplePayRequestBody {\n customer: string\n token: string\n threeDSReqAuthMethod: '02' // only registered users can use this\n type: 'MIT' // Merchant Initiated Transaction\n}\n\nexport interface SimplePayCancelCardRequestBody {\n salt: string\n cardId: string\n merchant: string\n sdkVersion: string\n}\n\nexport interface SimplePayResponse {\n salt: string\n merchant: string\n orderRef: string\n currency: Currency\n transactionId: string\n timeout: ISO8601DateString\n total: string\n paymentUrl: string\n errorCodes?: string[]\n}\n\nexport interface SimplePayRecurringResponse extends SimplePayResponse {\n tokens: string[]\n}\n\nexport interface SimplePayTokenResponse extends Omit<SimplePayResponse, 'paymentUrl' | 'timeout'> { }\n\nexport interface SimplePayCancelCardResponse {\n salt: string\n merchant: string\n cardId: string\n status: 'DISABLED'\n expiry: string\n}\n\nexport type SimplePayEvents = 'SUCCESS' | 'FAIL' | 'TIMEOUT' | 'CANCEL'\n\nexport interface SimplePayAPIResult {\n r: number // response code\n t: string // transaction id\n e: SimplePayEvents // event\n m: string // merchant id\n o: string // order id\n}\n\nexport interface SimplePayResult {\n responseCode: number,\n transactionId: string,\n event: SimplePayEvents,\n merchantId: string,\n orderRef: string,\n tokens?: string[],\n}\n\nexport interface SimplePayIPNResponse {\n salt: string\n orderRef: string\n method: string\n merchant: string\n finishDate: string\n paymentDate: string\n transactionId: number\n status: 'FINISHED' | 'AUTHORIZED' | 'NOTAUTHORIZED' | 'REVERSED' | 'CANCELLED' | 'TIMEOUT'\n receiveDate: string\n expiry?: string\n cardMask?: string\n}\n","import crypto from 'crypto'\nimport { CURRENCIES, Currency, ISO8601DateString, SimplePayAPIResult, SimplePayCancelCardRequestBody, SimplePayCancelCardResponse, SimplePayRecurringRequestBody, SimplePayRecurringResponse, SimplePayRequestBody, SimplePayResponse, SimplePayResult, SimplePayTokenRequestBody, SimplePayTokenResponse } from \"./types\"\n\nexport const simplepayLogger = (...args: any[]) => {\n if (process.env.SIMPLEPAY_LOGGER !== 'true') {\n return\n }\n\n console.log('👉 ', ...args)\n}\n\nexport const getSimplePayConfig = (currency: Currency) => {\n if (!CURRENCIES.includes(currency)) {\n throw new Error(`Unsupported currency: ${currency}`)\n }\n\n const SIMPLEPAY_API_URL = 'https://secure.simplepay.hu/payment/v2'\n const SIMPLEPAY_SANDBOX_URL = 'https://sandbox.simplepay.hu/payment/v2'\n const SDK_VERSION = 'SimplePay_Rrd_0.12.2'\n const MERCHANT_KEY = process.env[`SIMPLEPAY_MERCHANT_KEY_${currency}`]\n const MERCHANT_ID = process.env[`SIMPLEPAY_MERCHANT_ID_${currency}`]\n\n const API_URL = process.env.SIMPLEPAY_PRODUCTION === 'true' ? SIMPLEPAY_API_URL : SIMPLEPAY_SANDBOX_URL\n const API_URL_PAYMENT = API_URL + '/start'\n const API_URL_RECURRING = API_URL + '/dorecurring'\n const API_URL_CARD_CANCEL = API_URL + '/cardcancel'\n return {\n MERCHANT_KEY,\n MERCHANT_ID,\n API_URL_PAYMENT,\n API_URL_RECURRING,\n API_URL_CARD_CANCEL,\n SDK_VERSION\n }\n}\n\n// escaping slashes for the request body to prevent strange SimplePay API errors (eg Missing Signature)\nexport const prepareRequestBody = (body: any) =>\n JSON.stringify(body).replace(/\\//g, '\\\\/')\n\nexport const generateSignature = (body: string, merchantKey: string) => {\n const hmac = crypto.createHmac('sha384', merchantKey.trim())\n hmac.update(body, 'utf8')\n return hmac.digest('base64')\n}\n\nexport const checkSignature = (responseText: string, signature: string, merchantKey: string) =>\n signature === generateSignature(responseText, merchantKey)\n\nexport const toISO8601DateString = (date: Date): ISO8601DateString => date.toISOString().replace(/\\.\\d{3}Z$/, '+00:00')\n\nexport const getCurrencyFromMerchantId = (merchantId: string) => {\n const currency = Object.entries(process.env)\n .find(([key, value]) =>\n key.startsWith('SIMPLEPAY_MERCHANT_ID_') && value === merchantId\n )?.[0]?.replace('SIMPLEPAY_MERCHANT_ID_', '') as Currency\n\n if (!currency) {\n throw new Error(`Merchant id not found in the environment: ${merchantId}`)\n }\n\n return currency\n}\n\nexport const makeSimplePayRequest = async (apiUrl: string, requestBody: SimplePayRequestBody, merchantKey: string) => {\n return makeRequest(apiUrl, requestBody, merchantKey, 'oneTime') as Promise<SimplePayResponse>\n}\n\nexport const makeSimplePayRecurringRequest = async (apiUrl: string, requestBody: SimplePayRecurringRequestBody, merchantKey: string) => {\n return makeRequest(apiUrl, requestBody, merchantKey, 'recurring') as Promise<SimplePayRecurringResponse>\n}\n\nexport const makeSimplePayTokenRequest = async (apiUrl: string, requestBody: SimplePayTokenRequestBody, merchantKey: string) => {\n return makeRequest(apiUrl, requestBody, merchantKey, 'token') as Promise<SimplePayTokenResponse>\n}\n\nexport const makeSimplePayCancelCardRequest = async (apiUrl: string, requestBody: SimplePayCancelCardRequestBody, merchantKey: string) => {\n return makeRequest(apiUrl, requestBody, merchantKey, 'cancelCard') as Promise<SimplePayCancelCardResponse>\n}\n\nconst makeRequest = async (apiUrl: string, requestBody: SimplePayRequestBody | SimplePayRecurringRequestBody | SimplePayTokenRequestBody | SimplePayCancelCardRequestBody, merchantKey: string, type: 'oneTime' | 'recurring' | 'token' | 'cancelCard') => {\n const bodyString = prepareRequestBody(requestBody)\n const signature = generateSignature(bodyString, merchantKey)\n simplepayLogger({ function: `SimplePay/makeRequest/${type}`, bodyString, signature })\n\n try {\n const response = await fetch(apiUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Signature': signature,\n },\n body: bodyString,\n })\n\n simplepayLogger({ function: `SimplePay/makeRequest/${type}`, response })\n\n if (!response.ok) {\n throw new Error(`SimplePay API error: ${response.status}`)\n }\n\n const responseSignature = response.headers.get('Signature')\n simplepayLogger({ function: `SimplePay/makeRequest/${type}`, responseSignature })\n if (!responseSignature) {\n throw new Error('Missing response signature')\n }\n\n const responseText = await response.text()\n const responseJSON = JSON.parse(responseText) as { errorCodes?: string[] }\n simplepayLogger({ function: `SimplePay/makeRequest/${type}`, responseText, responseJSON })\n\n if (responseJSON.errorCodes) {\n throw new Error(`SimplePay API error: ${responseJSON.errorCodes}`)\n }\n\n if (!checkSignature(responseText, responseSignature, merchantKey)) {\n throw new Error('Invalid response signature')\n }\n\n return responseJSON\n\n } catch (error) {\n throw error\n }\n}\n\nexport const getPaymentResponse = (r: string, signature: string) => {\n simplepayLogger({ function: 'SimplePay/getPaymentResponse', r, signature })\n signature = signature.replace(/ /g, '+')\n const rDecoded = Buffer.from(r, 'base64').toString('utf-8')\n const rDecodedJSON = JSON.parse(rDecoded) as SimplePayAPIResult\n const currency = getCurrencyFromMerchantId(rDecodedJSON.m)\n const { MERCHANT_KEY } = getSimplePayConfig(currency as Currency)\n\n if (!checkSignature(rDecoded, signature, MERCHANT_KEY || '')) {\n simplepayLogger({ function: 'SimplePay/getPaymentResponse', rDecoded, signature })\n throw new Error('Invalid response signature')\n }\n\n const responseJson = JSON.parse(rDecoded)\n const response: SimplePayResult = {\n responseCode: responseJson.r,\n transactionId: responseJson.t,\n event: responseJson.e,\n merchantId: responseJson.m,\n orderRef: responseJson.o,\n tokens: responseJson.tokens,\n }\n\n return response\n}\n\n/**\n * Handles IPN (Instant Payment Notification) request and generates response\n * \n * This function implements the IPN flow according to SimplePay requirements:\n * 1. Validates the incoming signature\n * 2. Adds receiveDate property to the response (preserving original field order and data types)\n * 3. Generates response signature\n * \n * **IMPORTANT**: The responseBody must be sent EXACTLY as returned, without any modifications.\n * Do NOT:\n * - Re-format or pretty-print the JSON\n * - Parse and re-stringify the JSON\n * - Add any whitespace or formatting\n * - Modify the Content-Type header (must be 'application/json')\n * \n * The signature is calculated on the exact string that will be sent in the HTTP body.\n * Any modification to the responseBody will invalidate the signature.\n * \n * @param ipnBody - The raw IPN request body as string (must be the exact string received, not parsed JSON)\n * @param incomingSignature - The signature from the 'Signature' HTTP header\n * @param merchantKey - The merchant secret key for signature validation and generation\n * @returns Object containing the response JSON string and signature to send back\n * \n * @example\n * // In your IPN endpoint handler:\n * const ipnBody = await request.text() // Get raw body as string (IMPORTANT: use .text(), not JSON.parse())\n * const incomingSignature = request.headers.get('Signature')\n * const { responseBody, signature } = handleIpnRequest(ipnBody, incomingSignature, MERCHANT_KEY)\n * \n * // Send response with HTTP 200 status\n * // CRITICAL: Send responseBody exactly as returned, do not modify it!\n * return new Response(responseBody, {\n * status: 200,\n * headers: {\n * 'Content-Type': 'application/json',\n * 'Signature': signature\n * }\n * })\n */\nexport const handleIpnRequest = (ipnBody: string, incomingSignature: string, merchantKey: string) => {\n simplepayLogger({ function: 'SimplePay/handleIpnRequest', ipnBody, incomingSignature })\n \n // Step 1: Validate incoming signature\n if (!checkSignature(ipnBody, incomingSignature, merchantKey)) {\n throw new Error('Invalid IPN request signature')\n }\n \n // Step 2: Validate it's valid JSON (but don't use parsed object to preserve field order and data types)\n JSON.parse(ipnBody) // Just validate, don't use the result\n \n // Step 3: Add receiveDate to the original JSON string while preserving:\n // - Exact field order\n // - Exact data types (numeric vs string)\n // - No whitespace (compact JSON)\n // \n // Use the same simple approach as the working solution:\n // Replace the closing brace with: ,\"receiveDate\":\"${receiveDate}\"}\n // This preserves the exact original format and field order\n const receiveDate = toISO8601DateString(new Date())\n \n // Simple string replacement: replace the first (and only) closing brace\n // This is the same approach as the working solution\n const responseBody = ipnBody.replace('}', `,\"receiveDate\":\"${receiveDate}\"}`)\n \n // Step 4: Generate response signature using SHA384 HMAC + Base64\n // The signature must be calculated on the exact string that will be sent\n const responseSignature = generateSignature(responseBody, merchantKey)\n \n simplepayLogger({ function: 'SimplePay/handleIpnRequest', responseBody, responseSignature })\n \n return {\n responseBody,\n signature: responseSignature\n }\n}\n","import crypto from 'crypto'\nimport { Currency, PaymentConfig, PaymentData, SimplePayRequestBody } from './types'\nimport { simplepayLogger, getSimplePayConfig, toISO8601DateString, makeSimplePayRequest } from './utils'\n\nconst startPayment = async (paymentData: PaymentData, config: PaymentConfig = {}) => {\n simplepayLogger({ function: 'SimplePay/startPayment', paymentData })\n const currency = paymentData.currency || 'HUF'\n const { MERCHANT_KEY, MERCHANT_ID, API_URL_PAYMENT, SDK_VERSION } = getSimplePayConfig(currency)\n simplepayLogger({ function: 'SimplePay/startPayment', MERCHANT_KEY, MERCHANT_ID, API_URL_PAYMENT })\n\n if (!MERCHANT_KEY || !MERCHANT_ID) {\n throw new Error(`Missing SimplePay configuration for ${currency}`)\n }\n\n const requestBody: SimplePayRequestBody = {\n salt: crypto.randomBytes(16).toString('hex'),\n merchant: MERCHANT_ID,\n orderRef: paymentData.orderRef,\n currency: currency.replace('_SZEP', '') as Currency,\n customerEmail: paymentData.customerEmail,\n language: paymentData.language || 'HU',\n sdkVersion: SDK_VERSION,\n methods: [paymentData.method || 'CARD'],\n total: String(paymentData.total),\n timeout: toISO8601DateString(new Date(Date.now() + 30 * 60 * 1000)),\n url: config.redirectUrl || process.env.SIMPLEPAY_REDIRECT_URL || 'http://url.to.redirect',\n invoice: paymentData.invoice,\n }\n\n return makeSimplePayRequest(API_URL_PAYMENT, requestBody, MERCHANT_KEY)\n}\n\nexport { startPayment }\n","import crypto from 'crypto'\nimport { SimplePayRecurringRequestBody, RecurringPaymentData, TokenPaymentData, SimplePayTokenRequestBody, SimplePayCancelCardRequestBody, Currency} from './types'\nimport { getSimplePayConfig, simplepayLogger, toISO8601DateString, makeSimplePayTokenRequest, makeSimplePayRecurringRequest, makeSimplePayRequest, makeSimplePayCancelCardRequest} from './utils'\n\nconst INTERVAL_IN_MONTHS = 6\nconst DEFAULT_UNTIL = new Date(Date.now() + INTERVAL_IN_MONTHS * 30 * 24 * 60 * 60 * 1000)\nconst DEFAULT_MAX_AMOUNT = 12000\nconst DEFAULT_TIMES = 3\n\nconst startRecurringPayment = async (paymentData: RecurringPaymentData) => {\n simplepayLogger({ function: 'SimplePay/startRecurringPayment', paymentData })\n const currency = paymentData.currency || 'HUF'\n const { MERCHANT_KEY, MERCHANT_ID, API_URL_PAYMENT, SDK_VERSION } = getSimplePayConfig(currency)\n simplepayLogger({ function: 'SimplePay/startRecurringPayment', MERCHANT_KEY, MERCHANT_ID, API_URL_PAYMENT })\n\n if (!MERCHANT_KEY || !MERCHANT_ID) {\n throw new Error(`Missing SimplePay configuration for ${currency}`)\n }\n\n const requestBody: SimplePayRecurringRequestBody = {\n salt: crypto.randomBytes(16).toString('hex'),\n merchant: MERCHANT_ID,\n orderRef: paymentData.orderRef,\n currency: currency.replace('_SZEP', '') as Currency,\n customer: paymentData.customer,\n customerEmail: paymentData.customerEmail,\n language: paymentData.language || 'HU',\n sdkVersion: SDK_VERSION,\n methods: ['CARD'],\n recurring: {\n times: paymentData.recurring.times || DEFAULT_TIMES,\n until: paymentData.recurring.until || toISO8601DateString(DEFAULT_UNTIL),\n maxAmount: paymentData.recurring.maxAmount || DEFAULT_MAX_AMOUNT\n },\n threeDSReqAuthMethod: '02', \n total: String(paymentData.total),\n timeout: toISO8601DateString(new Date(Date.now() + 30 * 60 * 1000)),\n url: process.env.SIMPLEPAY_REDIRECT_URL || 'http://url.to.redirect',\n invoice: paymentData.invoice,\n }\n\n return makeSimplePayRecurringRequest(API_URL_PAYMENT, requestBody, MERCHANT_KEY)\n}\n\nconst startTokenPayment = async (paymentData: TokenPaymentData) => {\n simplepayLogger({ function: 'SimplePay/startTokenPayment', paymentData })\n const currency = paymentData.currency || 'HUF'\n const { MERCHANT_KEY, MERCHANT_ID, API_URL_RECURRING, SDK_VERSION } = getSimplePayConfig(currency)\n simplepayLogger({ function: 'SimplePay/startTokenPayment', MERCHANT_KEY, MERCHANT_ID, API_URL_RECURRING })\n\n if (!MERCHANT_KEY || !MERCHANT_ID) {\n throw new Error(`Missing SimplePay configuration for ${currency}`)\n }\n\n const requestBody: SimplePayTokenRequestBody = {\n salt: crypto.randomBytes(16).toString('hex'),\n merchant: MERCHANT_ID,\n orderRef: paymentData.orderRef,\n currency: currency.replace('_SZEP', '') as Currency,\n customer: paymentData.customer,\n customerEmail: paymentData.customerEmail,\n language: paymentData.language || 'HU',\n sdkVersion: SDK_VERSION,\n methods: ['CARD'],\n token: paymentData.token,\n type: 'MIT',\n threeDSReqAuthMethod: '02',\n total: String(paymentData.total),\n timeout: toISO8601DateString(new Date(Date.now() + 30 * 60 * 1000)),\n url: process.env.SIMPLEPAY_REDIRECT_URL || 'http://recurring.url.to.redirect',\n invoice: paymentData.invoice,\n }\n\n return makeSimplePayTokenRequest(API_URL_RECURRING, requestBody, MERCHANT_KEY)\n}\n\nconst cancelCard = async (cardId: string) => {\n simplepayLogger({ function: 'SimplePay/cancelCard', cardId })\n const {API_URL_CARD_CANCEL, MERCHANT_KEY, MERCHANT_ID, SDK_VERSION} = getSimplePayConfig('HUF')\n\n if (!MERCHANT_KEY || !MERCHANT_ID) {\n throw new Error(`Missing SimplePay configuration for HUF`)\n }\n\n const requestBody: SimplePayCancelCardRequestBody = {\n salt: crypto.randomBytes(16).toString('hex'),\n cardId,\n merchant: MERCHANT_ID,\n sdkVersion: SDK_VERSION,\n }\n return makeSimplePayCancelCardRequest(API_URL_CARD_CANCEL, requestBody, MERCHANT_KEY)\n}\n\nexport { startRecurringPayment, startTokenPayment , cancelCard}\n"],"names":["CURRENCIES","simplepayLogger","args","getSimplePayConfig","currency","SIMPLEPAY_API_URL","SIMPLEPAY_SANDBOX_URL","SDK_VERSION","MERCHANT_KEY","MERCHANT_ID","API_URL","API_URL_PAYMENT","API_URL_RECURRING","API_URL_CARD_CANCEL","prepareRequestBody","body","generateSignature","merchantKey","hmac","crypto","checkSignature","responseText","signature","toISO8601DateString","date","getCurrencyFromMerchantId","merchantId","key","value","makeSimplePayRequest","apiUrl","requestBody","makeRequest","makeSimplePayRecurringRequest","makeSimplePayTokenRequest","makeSimplePayCancelCardRequest","type","bodyString","response","responseSignature","responseJSON","error","getPaymentResponse","r","rDecoded","rDecodedJSON","responseJson","handleIpnRequest","ipnBody","incomingSignature","receiveDate","responseBody","startPayment","paymentData","config","INTERVAL_IN_MONTHS","DEFAULT_UNTIL","DEFAULT_MAX_AMOUNT","DEFAULT_TIMES","startRecurringPayment","startTokenPayment","cancelCard","cardId"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "simplepay-js-sdk",
3
- "version": "0.12.2",
3
+ "version": "0.12.3",
4
4
  "description": "A Node.js utility for SimplePay payment integration",
5
5
  "repository": {
6
6
  "type": "git",
package/src/basic.spec.ts CHANGED
@@ -117,6 +117,30 @@ describe('SimplePay Basic Tests', () => {
117
117
 
118
118
  expect(() => getPaymentResponse(encodedResponse, invalidSignature)).toThrow('Invalid response signature')
119
119
  })
120
+
121
+ it('should treat space in signature as + (form-urlencoded back redirect)', () => {
122
+ setEnv()
123
+ const mockResponse = {
124
+ r: 0,
125
+ t: 504233881,
126
+ e: 'SUCCESS',
127
+ m: 'merchantEuroId',
128
+ o: 'test-order'
129
+ }
130
+ const encodedResponse = Buffer.from(JSON.stringify(mockResponse)).toString('base64')
131
+ const signature = generateSignature(JSON.stringify(mockResponse), 'secretEuroKey')
132
+ const signatureWithSpaces = signature.replace(/\+/g, ' ')
133
+
134
+ const result = getPaymentResponse(encodedResponse, signatureWithSpaces)
135
+
136
+ expect(result).toEqual({
137
+ responseCode: 0,
138
+ transactionId: 504233881,
139
+ event: 'SUCCESS',
140
+ merchantId: 'merchantEuroId',
141
+ orderRef: 'test-order'
142
+ })
143
+ })
120
144
  })
121
145
 
122
146
  describe('Basic Card Cancel Test', () => {
package/src/utils.ts CHANGED
@@ -16,7 +16,7 @@ export const getSimplePayConfig = (currency: Currency) => {
16
16
 
17
17
  const SIMPLEPAY_API_URL = 'https://secure.simplepay.hu/payment/v2'
18
18
  const SIMPLEPAY_SANDBOX_URL = 'https://sandbox.simplepay.hu/payment/v2'
19
- const SDK_VERSION = 'SimplePay_Rrd_0.12.2'
19
+ const SDK_VERSION = 'SimplePay_Rrd_0.12.3'
20
20
  const MERCHANT_KEY = process.env[`SIMPLEPAY_MERCHANT_KEY_${currency}`]
21
21
  const MERCHANT_ID = process.env[`SIMPLEPAY_MERCHANT_ID_${currency}`]
22
22
 
@@ -126,7 +126,7 @@ const makeRequest = async (apiUrl: string, requestBody: SimplePayRequestBody | S
126
126
 
127
127
  export const getPaymentResponse = (r: string, signature: string) => {
128
128
  simplepayLogger({ function: 'SimplePay/getPaymentResponse', r, signature })
129
- signature = decodeURIComponent(signature)
129
+ signature = signature.replace(/ /g, '+')
130
130
  const rDecoded = Buffer.from(r, 'base64').toString('utf-8')
131
131
  const rDecodedJSON = JSON.parse(rDecoded) as SimplePayAPIResult
132
132
  const currency = getCurrencyFromMerchantId(rDecodedJSON.m)