strapi-plugin-payone-provider 1.5.4 → 1.5.5

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.
@@ -498,16 +498,28 @@ const ApplePayButton = ({
498
498
  merchantSessionPromise.then(session => {
499
499
  console.log("[Apple Pay] Merchant session received:", {
500
500
  hasMerchantIdentifier: !!session.merchantIdentifier,
501
+ merchantIdentifier: session.merchantIdentifier,
501
502
  domainName: session.domainName,
502
- displayName: session.displayName
503
+ displayName: session.displayName,
504
+ epochTimestamp: session.epochTimestamp,
505
+ expiresAt: session.expiresAt,
506
+ fullSession: session
503
507
  });
508
+
509
+ // Validate merchant session
510
+ if (!session || (!session.merchantIdentifier && !session.merchantSessionIdentifier)) {
511
+ console.error("[Apple Pay] Invalid merchant session - missing merchantIdentifier");
512
+ console.error("[Apple Pay] Session object:", JSON.stringify(session, null, 2));
513
+ throw new Error("Invalid merchant session: missing merchantIdentifier");
514
+ }
504
515
  }).catch(err => {
505
516
  console.error("[Apple Pay] Merchant session error:", err);
506
- // Don't call onError here - let the dialog handle it
517
+ // Re-throw so Payment Request API knows validation failed
518
+ throw err;
507
519
  });
508
520
 
509
521
  // Complete with the merchant session promise
510
- // If it fails, Apple Pay will handle it gracefully
522
+ // If the promise rejects, Payment Request API will close the dialog
511
523
  event.complete(merchantSessionPromise);
512
524
  } catch (error) {
513
525
  console.error("[Apple Pay] Merchant validation error:", error);
@@ -550,17 +562,42 @@ const ApplePayButton = ({
550
562
  let response;
551
563
  try {
552
564
  response = await request.show();
565
+ console.log("[Apple Pay] Payment sheet shown successfully");
553
566
  } catch (error) {
554
- console.error("[Apple Pay] Error showing payment sheet:", error);
567
+ console.error("[Apple Pay] Error showing payment sheet:", {
568
+ name: error.name,
569
+ message: error.message,
570
+ stack: error.stack
571
+ });
572
+
555
573
  // Check if error is due to cancellation (user cancelled)
556
- if (error.message && error.message.includes('Cancelled')) {
574
+ // Payment Request API throws "AbortError" when user cancels
575
+ if (error.name === 'AbortError' ||
576
+ (error.message && (
577
+ error.message.includes('Cancelled') ||
578
+ error.message.includes('cancel') ||
579
+ error.message.includes('abort')
580
+ ))) {
557
581
  console.log("[Apple Pay] User cancelled the payment");
558
582
  // Don't call onError for user cancellation
559
583
  return;
560
584
  }
561
- // Only call onError if it's defined and it's not a cancellation
562
- if (typeof onError === 'function') {
563
- onError(error);
585
+
586
+ // If it's a merchant validation error, log it specifically
587
+ if (error.message && (
588
+ error.message.includes('merchant') ||
589
+ error.message.includes('validation') ||
590
+ error.message.includes('identifier')
591
+ )) {
592
+ console.error("[Apple Pay] Merchant validation failed - this may cause the dialog to close");
593
+ if (typeof onError === 'function') {
594
+ onError(new Error("Merchant validation failed. Please check your Apple Pay configuration and merchant identifier in Payone settings."));
595
+ }
596
+ } else {
597
+ // For other errors, call onError
598
+ if (typeof onError === 'function') {
599
+ onError(error);
600
+ }
564
601
  }
565
602
  return;
566
603
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "strapi-plugin-payone-provider",
3
- "version": "1.5.4",
3
+ "version": "1.5.5",
4
4
  "description": "Strapi plugin for Payone payment gateway integration",
5
5
  "license": "MIT",
6
6
  "maintainers": [
@@ -214,43 +214,168 @@ const validateApplePayMerchant = async (strapi, params) => {
214
214
  strapi.log.info("[Apple Pay] Session initialization result:", {
215
215
  status: sessionResponse.status || sessionResponse.Status,
216
216
  hasMerchantIdentifier: !!(sessionResponse.merchantIdentifier || sessionResponse.merchantSessionIdentifier),
217
+ hasApplePaySession: !!(sessionResponse["add_paydata[applepay_payment_session]"] ||
218
+ sessionResponse["add_paydata[applepay_payment_session]"] ||
219
+ sessionResponse.add_paydata?.applepay_payment_session),
217
220
  fullResponse: JSON.stringify(sessionResponse, null, 2)
218
221
  });
219
222
 
220
- // If session initialization is successful, return merchant session
221
- // Payone will provide the merchant identifier and validation data
223
+ // If session initialization is successful, extract merchant session from Payone response
224
+ // Payone returns: add_paydata[applepay_payment_session] = BASE64 encoded merchant session
222
225
  // Check for both uppercase and lowercase status
223
226
  const responseStatus = sessionResponse.status || sessionResponse.Status;
224
- if (responseStatus === "APPROVED" || responseStatus === "REDIRECT" ||
225
- responseStatus === "approved" || responseStatus === "redirect") {
226
- strapi.log.info("[Apple Pay] Session approved, creating merchant session object");
227
- // Get merchant identifier from Payone response or settings
228
- const merchantIdentifier = sessionResponse.merchantIdentifier ||
229
- sessionResponse.merchantSessionIdentifier ||
230
- settings.merchantIdentifier ||
231
- settings.mid ||
232
- settings.portalid ||
233
- `merchant.${domainName}`;
234
-
235
- // Return merchant session object
236
- // In a real implementation, you would get this from Payone's response
237
- const merchantSession = {
238
- epochTimestamp: Date.now(),
239
- expiresAt: Date.now() + (5 * 60 * 1000), // 5 minutes
240
- merchantSessionIdentifier: sessionResponse.merchantSessionIdentifier || `merchant.${domainName}`,
241
- nonce: sessionResponse.nonce || generateNonce(),
242
- merchantIdentifier: merchantIdentifier,
243
- domainName: domainName,
244
- displayName: merchantName
245
- };
246
-
247
- strapi.log.info("[Apple Pay] Merchant session created:", {
248
- merchantIdentifier: merchantSession.merchantIdentifier,
249
- domainName: merchantSession.domainName,
250
- expiresAt: new Date(merchantSession.expiresAt).toISOString()
227
+ if (responseStatus === "APPROVED" || responseStatus === "OK" ||
228
+ responseStatus === "approved" || responseStatus === "ok") {
229
+
230
+ // Extract BASE64 encoded merchant session from Payone response
231
+ // Payone returns it in: add_paydata[applepay_payment_session]
232
+ // Try all possible variations of the field name
233
+ const applePaySessionBase64 =
234
+ sessionResponse["add_paydata[applepay_payment_session]"] ||
235
+ sessionResponse["add_paydata[applepay_payment_session]"] ||
236
+ sessionResponse["add_paydata_applepay_payment_session"] ||
237
+ sessionResponse.add_paydata?.applepay_payment_session ||
238
+ sessionResponse.add_paydata?.["applepay_payment_session"] ||
239
+ sessionResponse["addPaydata[applepay_payment_session]"] ||
240
+ sessionResponse["addPaydata_applepay_payment_session"] ||
241
+ null;
242
+
243
+ strapi.log.info("[Apple Pay] Checking for merchant session in response:", {
244
+ hasWorkorderid: !!sessionResponse.workorderid,
245
+ workorderid: sessionResponse.workorderid,
246
+ allKeys: Object.keys(sessionResponse).filter(k => k.includes('applepay') || k.includes('session') || k.includes('paydata')),
247
+ responseKeys: Object.keys(sessionResponse)
251
248
  });
252
249
 
253
- return merchantSession;
250
+ strapi.log.info("[Apple Pay] Extracted Apple Pay session data:", {
251
+ hasBase64Session: !!applePaySessionBase64,
252
+ sessionLength: applePaySessionBase64?.length,
253
+ workorderid: sessionResponse.workorderid
254
+ });
255
+
256
+ if (applePaySessionBase64) {
257
+ try {
258
+ // Decode BASE64 merchant session
259
+ const merchantSessionJson = Buffer.from(applePaySessionBase64, 'base64').toString('utf-8');
260
+ const merchantSession = JSON.parse(merchantSessionJson);
261
+
262
+ strapi.log.info("[Apple Pay] Decoded merchant session:", {
263
+ merchantIdentifier: merchantSession.merchantIdentifier,
264
+ domainName: merchantSession.domainName,
265
+ displayName: merchantSession.displayName,
266
+ hasEpochTimestamp: !!merchantSession.epochTimestamp,
267
+ hasExpiresAt: !!merchantSession.expiresAt,
268
+ fullSession: merchantSession
269
+ });
270
+
271
+ // Validate decoded merchant session
272
+ if (!merchantSession.merchantIdentifier) {
273
+ strapi.log.warn("[Apple Pay] Decoded merchant session missing merchantIdentifier, using fallback");
274
+ // Use fallback merchant identifier
275
+ merchantSession.merchantIdentifier = settings.merchantIdentifier ||
276
+ settings.mid ||
277
+ settings.portalid ||
278
+ `merchant.${domainName}`;
279
+ }
280
+
281
+ // Ensure epochTimestamp and expiresAt are in seconds (not milliseconds)
282
+ if (merchantSession.epochTimestamp && merchantSession.epochTimestamp > 1000000000000) {
283
+ // If timestamp is in milliseconds, convert to seconds
284
+ merchantSession.epochTimestamp = Math.floor(merchantSession.epochTimestamp / 1000);
285
+ }
286
+ if (merchantSession.expiresAt && merchantSession.expiresAt > 1000000000000) {
287
+ // If timestamp is in milliseconds, convert to seconds
288
+ merchantSession.expiresAt = Math.floor(merchantSession.expiresAt / 1000);
289
+ }
290
+
291
+ // Validate final merchant session
292
+ if (!merchantSession.merchantIdentifier || merchantSession.merchantIdentifier === 'undefined' || merchantSession.merchantIdentifier === 'null') {
293
+ throw new Error("Decoded merchant session has invalid merchantIdentifier");
294
+ }
295
+
296
+ strapi.log.info("[Apple Pay] Validated merchant session:", {
297
+ merchantIdentifier: merchantSession.merchantIdentifier,
298
+ domainName: merchantSession.domainName,
299
+ epochTimestamp: merchantSession.epochTimestamp,
300
+ expiresAt: merchantSession.expiresAt
301
+ });
302
+
303
+ return merchantSession;
304
+ } catch (decodeError) {
305
+ strapi.log.error("[Apple Pay] Failed to decode merchant session:", {
306
+ error: decodeError.message,
307
+ base64Length: applePaySessionBase64?.length,
308
+ base64Preview: applePaySessionBase64?.substring(0, 100)
309
+ });
310
+
311
+ // If decoding fails, we cannot proceed - merchant session is invalid
312
+ throw new Error(`Failed to decode Apple Pay merchant session: ${decodeError.message}`);
313
+ }
314
+ } else {
315
+ // If no session data in response, we need to create a valid merchant session
316
+ // According to Payone docs, merchant identifier should be obtained from PMI
317
+ // after domain verification and onboarding
318
+ strapi.log.warn("[Apple Pay] No Apple Pay session data in response, creating merchant session from settings");
319
+
320
+ // Get merchant identifier from settings
321
+ // According to Payone docs, merchant identifier should be visible in PMI after onboarding
322
+ // Path: CONFIGURATION/PAYMENT PORTALS - choose an onboarded Portal - Payment type configuration tab
323
+ let merchantIdentifier = settings.merchantIdentifier ||
324
+ settings.mid ||
325
+ settings.portalid;
326
+
327
+ // If still no merchant identifier, try to construct one from domain
328
+ // But this is not ideal - merchant identifier should come from Payone PMI
329
+ if (!merchantIdentifier) {
330
+ strapi.log.warn("[Apple Pay] No merchant identifier found in settings, using domain-based fallback");
331
+ merchantIdentifier = `merchant.${domainName}`;
332
+ }
333
+
334
+ // Ensure merchant identifier is a string and not empty
335
+ merchantIdentifier = merchantIdentifier.toString().trim();
336
+ if (!merchantIdentifier || merchantIdentifier === 'undefined' || merchantIdentifier === 'null') {
337
+ strapi.log.error("[Apple Pay] Invalid merchant identifier:", merchantIdentifier);
338
+ throw new Error("Merchant identifier is invalid. Please configure a valid merchant identifier in Payone Merchant Interface (PMI) after Apple Pay onboarding. Path: CONFIGURATION → PAYMENT PORTALS → [Your Portal] → Payment type configuration tab");
339
+ }
340
+
341
+ // Create a valid merchant session object
342
+ // This format is required by Apple Pay Payment Request API
343
+ // IMPORTANT: epochTimestamp and expiresAt must be in seconds (Unix timestamp), not milliseconds
344
+ const merchantSession = {
345
+ epochTimestamp: Math.floor(Date.now() / 1000), // Unix timestamp in seconds
346
+ expiresAt: Math.floor((Date.now() + (5 * 60 * 1000)) / 1000), // 5 minutes from now, in seconds
347
+ merchantSessionIdentifier: `merchant.${domainName}`,
348
+ nonce: generateNonce(),
349
+ merchantIdentifier: merchantIdentifier, // Already validated and converted to string
350
+ domainName: domainName,
351
+ displayName: merchantName
352
+ };
353
+
354
+ // Validate merchant session before returning
355
+ if (!merchantSession.merchantIdentifier || merchantSession.merchantIdentifier === 'undefined' || merchantSession.merchantIdentifier === 'null') {
356
+ strapi.log.error("[Apple Pay] Created merchant session is missing or invalid merchantIdentifier!", {
357
+ merchantIdentifier: merchantSession.merchantIdentifier,
358
+ settings: {
359
+ hasMerchantIdentifier: !!settings.merchantIdentifier,
360
+ hasMid: !!settings.mid,
361
+ hasPortalid: !!settings.portalid,
362
+ mid: settings.mid,
363
+ portalid: settings.portalid
364
+ }
365
+ });
366
+ throw new Error("Merchant identifier is required but not found in settings. Please configure merchant identifier in Payone Merchant Interface (PMI) after Apple Pay onboarding.");
367
+ }
368
+
369
+ strapi.log.info("[Apple Pay] Created merchant session from settings:", {
370
+ merchantIdentifier: merchantSession.merchantIdentifier,
371
+ domainName: merchantSession.domainName,
372
+ displayName: merchantSession.displayName,
373
+ epochTimestamp: merchantSession.epochTimestamp,
374
+ expiresAt: merchantSession.expiresAt
375
+ });
376
+
377
+ return merchantSession;
378
+ }
254
379
  }
255
380
 
256
381
  // If initialization failed, return empty object
@@ -24,8 +24,20 @@ const parseResponse = (responseText, logger) => {
24
24
  const params = new URLSearchParams(responseText);
25
25
  const response = {};
26
26
  for (const [key, value] of params) {
27
+ // Store both lowercase and original case
27
28
  response[key.toLowerCase()] = value;
28
29
  response[key] = value;
30
+
31
+ // Also handle add_paydata fields with brackets
32
+ // Payone returns: add_paydata[applepay_payment_session]=BASE64_STRING
33
+ // URLSearchParams handles brackets, but we need to ensure we can access it
34
+ if (key.includes('add_paydata') || key.includes('addPaydata')) {
35
+ // Store with original key format
36
+ response[key] = value;
37
+ // Also try normalized versions
38
+ const normalizedKey = key.replace(/\[/g, '_').replace(/\]/g, '');
39
+ response[normalizedKey] = value;
40
+ }
29
41
  }
30
42
  return response;
31
43
  };