awesome-node-checkout 1.1.0 → 1.2.1
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/CHANGELOG.md +48 -0
- package/README.md +88 -28
- package/dist/adapters/express/index.d.ts +40 -9
- package/dist/adapters/express/index.d.ts.map +1 -1
- package/dist/adapters/express/index.js +85 -15
- package/dist/adapters/express/index.js.map +1 -1
- package/dist/checkout-configurator.d.ts +9 -1
- package/dist/checkout-configurator.d.ts.map +1 -1
- package/dist/checkout-configurator.js +52 -3
- package/dist/checkout-configurator.js.map +1 -1
- package/dist/events/checkout-event-bus.d.ts +1 -0
- package/dist/events/checkout-event-bus.d.ts.map +1 -1
- package/dist/events/checkout-event-bus.js.map +1 -1
- package/dist/interfaces/payment-provider.interface.d.ts +8 -3
- package/dist/interfaces/payment-provider.interface.d.ts.map +1 -1
- package/dist/models/payment-request.model.d.ts +2 -0
- package/dist/models/payment-request.model.d.ts.map +1 -1
- package/dist/models/payment-result.model.d.ts +11 -0
- package/dist/models/payment-result.model.d.ts.map +1 -1
- package/dist/providers/nexi/nexi.provider.d.ts +26 -8
- package/dist/providers/nexi/nexi.provider.d.ts.map +1 -1
- package/dist/providers/nexi/nexi.provider.js +180 -45
- package/dist/providers/nexi/nexi.provider.js.map +1 -1
- package/dist/providers/paypal/paypal.provider.d.ts.map +1 -1
- package/dist/providers/paypal/paypal.provider.js +28 -4
- package/dist/providers/paypal/paypal.provider.js.map +1 -1
- package/dist/providers/satispay/satispay.provider.d.ts +39 -5
- package/dist/providers/satispay/satispay.provider.d.ts.map +1 -1
- package/dist/providers/satispay/satispay.provider.js +130 -23
- package/dist/providers/satispay/satispay.provider.js.map +1 -1
- package/dist/utils/parsing.util.d.ts +17 -0
- package/dist/utils/parsing.util.d.ts.map +1 -0
- package/dist/utils/parsing.util.js +60 -0
- package/dist/utils/parsing.util.js.map +1 -0
- package/package.json +9 -3
|
@@ -28,9 +28,21 @@ class CheckoutConfigurator {
|
|
|
28
28
|
constructor(config = {}) {
|
|
29
29
|
this.config = config;
|
|
30
30
|
this.providers = new Map();
|
|
31
|
+
this.maxPaymentOrders = 10000;
|
|
32
|
+
this.paymentOrders = new Map();
|
|
31
33
|
/** Event bus — subscribe to payment lifecycle events */
|
|
32
34
|
this.events = new checkout_event_bus_1.CheckoutEventBus();
|
|
33
35
|
}
|
|
36
|
+
/** Stores a paymentId -> orderId mapping with bounded capacity to prevent memory leaks */
|
|
37
|
+
setPaymentOrder(paymentId, orderId) {
|
|
38
|
+
if (this.paymentOrders.size >= this.maxPaymentOrders) {
|
|
39
|
+
const firstKey = this.paymentOrders.keys().next().value;
|
|
40
|
+
if (firstKey) {
|
|
41
|
+
this.paymentOrders.delete(firstKey);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
this.paymentOrders.set(paymentId, orderId);
|
|
45
|
+
}
|
|
34
46
|
/** Emits an event only when `config.emitEvents` is not explicitly `false`. */
|
|
35
47
|
async emit(event, data) {
|
|
36
48
|
if (this.config.emitEvents !== false) {
|
|
@@ -68,12 +80,17 @@ class CheckoutConfigurator {
|
|
|
68
80
|
async createPayment(providerName, request) {
|
|
69
81
|
const provider = this.getProvider(providerName);
|
|
70
82
|
const result = await provider.createPayment(request);
|
|
83
|
+
if (result.paymentId && request.orderId) {
|
|
84
|
+
this.setPaymentOrder(result.paymentId, request.orderId);
|
|
85
|
+
result.orderId = request.orderId;
|
|
86
|
+
}
|
|
71
87
|
await this.emit(result.success ? 'payment.created' : 'payment.failed', {
|
|
72
88
|
provider: providerName,
|
|
73
89
|
paymentId: result.paymentId,
|
|
74
90
|
orderId: request.orderId,
|
|
75
91
|
status: result.status,
|
|
76
92
|
error: result.error,
|
|
93
|
+
raw: result.raw,
|
|
77
94
|
});
|
|
78
95
|
return result;
|
|
79
96
|
}
|
|
@@ -81,11 +98,17 @@ class CheckoutConfigurator {
|
|
|
81
98
|
async executePayment(providerName, paymentId, data) {
|
|
82
99
|
const provider = this.getProvider(providerName);
|
|
83
100
|
const result = await provider.executePayment(paymentId, data);
|
|
101
|
+
const orderId = this.paymentOrders.get(paymentId);
|
|
102
|
+
if (orderId && !result.orderId) {
|
|
103
|
+
result.orderId = orderId;
|
|
104
|
+
}
|
|
84
105
|
await this.emit(result.success ? 'payment.completed' : 'payment.failed', {
|
|
85
106
|
provider: providerName,
|
|
86
107
|
paymentId,
|
|
108
|
+
orderId,
|
|
87
109
|
status: result.status,
|
|
88
110
|
error: result.error,
|
|
111
|
+
raw: result.raw,
|
|
89
112
|
});
|
|
90
113
|
return result;
|
|
91
114
|
}
|
|
@@ -98,11 +121,17 @@ class CheckoutConfigurator {
|
|
|
98
121
|
async refundPayment(providerName, paymentId, amount) {
|
|
99
122
|
const provider = this.getProvider(providerName);
|
|
100
123
|
const result = await provider.refundPayment(paymentId, amount);
|
|
124
|
+
const orderId = this.paymentOrders.get(paymentId);
|
|
125
|
+
if (orderId && !result.orderId) {
|
|
126
|
+
result.orderId = orderId;
|
|
127
|
+
}
|
|
101
128
|
await this.emit('payment.refunded', {
|
|
102
129
|
provider: providerName,
|
|
103
130
|
paymentId,
|
|
131
|
+
orderId,
|
|
104
132
|
status: result.status,
|
|
105
133
|
error: result.error,
|
|
134
|
+
raw: result.raw,
|
|
106
135
|
});
|
|
107
136
|
return result;
|
|
108
137
|
}
|
|
@@ -110,18 +139,30 @@ class CheckoutConfigurator {
|
|
|
110
139
|
* Handle an incoming webhook from the provider.
|
|
111
140
|
* @throws CheckoutError if the provider does not support webhooks.
|
|
112
141
|
*/
|
|
113
|
-
async handleWebhook(providerName, body, headers) {
|
|
142
|
+
async handleWebhook(providerName, body, headers = {}, query, context) {
|
|
114
143
|
const provider = this.getProvider(providerName);
|
|
115
144
|
if (!provider.handleWebhook) {
|
|
116
145
|
throw new errors_1.CheckoutError(`Provider '${providerName}' does not support webhook handling`, 'WEBHOOK_NOT_SUPPORTED', providerName);
|
|
117
146
|
}
|
|
118
|
-
const result = await provider.handleWebhook(body, headers);
|
|
147
|
+
const result = await provider.handleWebhook(body, headers, query, context);
|
|
148
|
+
const rawAny = result.raw;
|
|
149
|
+
const orderId = rawAny?.orderId ??
|
|
150
|
+
rawAny?.order_id ??
|
|
151
|
+
rawAny?.external_code ??
|
|
152
|
+
rawAny?.codTrans ??
|
|
153
|
+
query?.order_id ??
|
|
154
|
+
(result.paymentId ? this.paymentOrders.get(result.paymentId) : undefined);
|
|
155
|
+
if (orderId && !result.orderId) {
|
|
156
|
+
result.orderId = orderId;
|
|
157
|
+
}
|
|
119
158
|
await this.emit('webhook.received', {
|
|
120
159
|
provider: providerName,
|
|
121
160
|
paymentId: result.paymentId,
|
|
161
|
+
orderId,
|
|
122
162
|
status: result.status,
|
|
123
163
|
error: result.error,
|
|
124
|
-
data: body,
|
|
164
|
+
data: body ?? query,
|
|
165
|
+
raw: result.raw,
|
|
125
166
|
});
|
|
126
167
|
return result;
|
|
127
168
|
}
|
|
@@ -135,11 +176,19 @@ class CheckoutConfigurator {
|
|
|
135
176
|
throw new errors_1.CheckoutError(`Provider '${providerName}' does not support redirect handling`, 'REDIRECT_NOT_SUPPORTED', providerName);
|
|
136
177
|
}
|
|
137
178
|
const result = await provider.handleRedirect(query);
|
|
179
|
+
const orderId = (result.paymentId ? this.paymentOrders.get(result.paymentId) : undefined) ??
|
|
180
|
+
query?.order_id ??
|
|
181
|
+
query?.codTrans;
|
|
182
|
+
if (orderId && !result.orderId) {
|
|
183
|
+
result.orderId = orderId;
|
|
184
|
+
}
|
|
138
185
|
await this.emit(result.success ? 'payment.completed' : 'payment.failed', {
|
|
139
186
|
provider: providerName,
|
|
140
187
|
paymentId: result.paymentId,
|
|
188
|
+
orderId,
|
|
141
189
|
status: result.status,
|
|
142
190
|
error: result.error,
|
|
191
|
+
raw: result.raw,
|
|
143
192
|
});
|
|
144
193
|
return result;
|
|
145
194
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkout-configurator.js","sourceRoot":"","sources":["../src/checkout-configurator.ts"],"names":[],"mappings":";;;AAIA,4CAAgD;AAChD,oEAAwG;AAExG;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAa,oBAAoB;
|
|
1
|
+
{"version":3,"file":"checkout-configurator.js","sourceRoot":"","sources":["../src/checkout-configurator.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkout-event-bus.d.ts","sourceRoot":"","sources":["../../src/events/checkout-event-bus.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GACzB,iBAAiB,GACjB,mBAAmB,GACnB,gBAAgB,GAChB,kBAAkB,GAClB,kBAAkB,CAAC;AAEvB,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,KAAK,aAAa,GAAG,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE7E;;;;;;;;;GASG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAsD;IAEhF,EAAE,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI;IAM3D,GAAG,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI;IAQtD,IAAI,CACR,KAAK,EAAE,iBAAiB,EACxB,OAAO,EAAE,IAAI,CAAC,oBAAoB,EAAE,WAAW,CAAC,GAC/C,OAAO,CAAC,IAAI,CAAC;CAKjB"}
|
|
1
|
+
{"version":3,"file":"checkout-event-bus.d.ts","sourceRoot":"","sources":["../../src/events/checkout-event-bus.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GACzB,iBAAiB,GACjB,mBAAmB,GACnB,gBAAgB,GAChB,kBAAkB,GAClB,kBAAkB,CAAC;AAEvB,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,KAAK,aAAa,GAAG,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE7E;;;;;;;;;GASG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAsD;IAEhF,EAAE,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI;IAM3D,GAAG,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI;IAQtD,IAAI,CACR,KAAK,EAAE,iBAAiB,EACxB,OAAO,EAAE,IAAI,CAAC,oBAAoB,EAAE,WAAW,CAAC,GAC/C,OAAO,CAAC,IAAI,CAAC;CAKjB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkout-event-bus.js","sourceRoot":"","sources":["../../src/events/checkout-event-bus.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"checkout-event-bus.js","sourceRoot":"","sources":["../../src/events/checkout-event-bus.ts"],"names":[],"mappings":";;;AAoBA;;;;;;;;;GASG;AACH,MAAa,gBAAgB;IAA7B;QACmB,cAAS,GAA4C,IAAI,GAAG,EAAE,CAAC;IAwBlF,CAAC;IAtBC,EAAE,CAAC,KAAwB,EAAE,QAAuB;QAClD,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACjD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;QACnD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,GAAG,CAAC,KAAwB,EAAE,QAAuB;QACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC3C,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC;QACpE,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,IAAI,CACR,KAAwB,EACxB,OAAgD;QAEhD,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACjD,MAAM,WAAW,GAAyB,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC;QAChF,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IACzD,CAAC;CACF;AAzBD,4CAyBC"}
|
|
@@ -20,10 +20,15 @@ export interface IPaymentProvider {
|
|
|
20
20
|
/** Issue a full or partial refund on a completed payment */
|
|
21
21
|
refundPayment(paymentId: string, amount?: number): Promise<PaymentResult>;
|
|
22
22
|
/**
|
|
23
|
-
* Handle an incoming webhook notification from the provider.
|
|
24
|
-
* Optional — implement
|
|
23
|
+
* Handle an incoming webhook or server-to-server outcome notification from the provider.
|
|
24
|
+
* Optional — implement for providers that use the `webhook` flow or support
|
|
25
|
+
* server-to-server notifications.
|
|
25
26
|
*/
|
|
26
|
-
handleWebhook?(body
|
|
27
|
+
handleWebhook?(body?: Record<string, unknown>, headers?: Record<string, string>, query?: Record<string, string>, context?: {
|
|
28
|
+
method?: string;
|
|
29
|
+
path?: string;
|
|
30
|
+
rawBody?: Buffer | string;
|
|
31
|
+
}): Promise<WebhookResult>;
|
|
27
32
|
/**
|
|
28
33
|
* Handle the redirect callback from the provider (query params from returnUrl).
|
|
29
34
|
* Optional — implement only for providers that use the `redirect` flow.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"payment-provider.interface.d.ts","sourceRoot":"","sources":["../../src/interfaces/payment-provider.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAE9E,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE5D,MAAM,WAAW,gBAAgB;IAC/B,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAE3B,8FAA8F;IAC9F,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAE/D,mDAAmD;IACnD,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAEzF,2DAA2D;IAC3D,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAE7D,4DAA4D;IAC5D,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAE1E
|
|
1
|
+
{"version":3,"file":"payment-provider.interface.d.ts","sourceRoot":"","sources":["../../src/interfaces/payment-provider.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAE9E,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE5D,MAAM,WAAW,gBAAgB;IAC/B,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAE3B,8FAA8F;IAC9F,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAE/D,mDAAmD;IACnD,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAEzF,2DAA2D;IAC3D,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAE7D,4DAA4D;IAC5D,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAE1E;;;;OAIG;IACH,aAAa,CAAC,CACZ,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAChC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,GACtE,OAAO,CAAC,aAAa,CAAC,CAAC;IAE1B;;;OAGG;IACH,cAAc,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CACxE"}
|
|
@@ -13,6 +13,8 @@ export interface PaymentRequest {
|
|
|
13
13
|
returnUrl: string;
|
|
14
14
|
/** URL to redirect the user to if the payment is cancelled */
|
|
15
15
|
cancelUrl: string;
|
|
16
|
+
/** Optional webhook / server-to-server notification URL forwarded to providers that support it */
|
|
17
|
+
notifyUrl?: string;
|
|
16
18
|
/** External order identifier from the merchant's system */
|
|
17
19
|
orderId?: string;
|
|
18
20
|
/** Arbitrary key-value pairs forwarded to the provider when supported */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"payment-request.model.d.ts","sourceRoot":"","sources":["../../src/models/payment-request.model.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;IAEf,iDAAiD;IACjD,QAAQ,EAAE,MAAM,CAAC;IAEjB,gDAAgD;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAC;IAElB,8DAA8D;IAC9D,SAAS,EAAE,MAAM,CAAC;IAElB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC"}
|
|
1
|
+
{"version":3,"file":"payment-request.model.d.ts","sourceRoot":"","sources":["../../src/models/payment-request.model.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;IAEf,iDAAiD;IACjD,QAAQ,EAAE,MAAM,CAAC;IAEjB,gDAAgD;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAC;IAElB,8DAA8D;IAC9D,SAAS,EAAE,MAAM,CAAC;IAElB,kGAAkG;IAClG,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC"}
|
|
@@ -7,6 +7,12 @@ export interface PaymentResult {
|
|
|
7
7
|
approvalUrl?: string;
|
|
8
8
|
/** Current payment status (provider-specific string, e.g. 'COMPLETED', 'ACCEPTED') */
|
|
9
9
|
status?: string;
|
|
10
|
+
/** Amount reported by the provider, major units (same unit as PaymentRequest.amount) */
|
|
11
|
+
amount?: number;
|
|
12
|
+
/** ISO 4217 alpha code reported by the provider (e.g. 'EUR') */
|
|
13
|
+
currency?: string;
|
|
14
|
+
/** Order identifier associated with the payment if tracked */
|
|
15
|
+
orderId?: string;
|
|
10
16
|
/** Error message if success is false */
|
|
11
17
|
error?: string;
|
|
12
18
|
/** Raw provider response — useful for debugging or provider-specific fields */
|
|
@@ -16,7 +22,12 @@ export interface PaymentResult {
|
|
|
16
22
|
export interface WebhookResult {
|
|
17
23
|
success: boolean;
|
|
18
24
|
paymentId?: string;
|
|
25
|
+
orderId?: string;
|
|
19
26
|
status?: string;
|
|
27
|
+
/** Amount reported by the provider, major units (same unit as PaymentRequest.amount) */
|
|
28
|
+
amount?: number;
|
|
29
|
+
/** ISO 4217 alpha code reported by the provider (e.g. 'EUR') */
|
|
30
|
+
currency?: string;
|
|
20
31
|
error?: string;
|
|
21
32
|
raw?: any;
|
|
22
33
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"payment-result.model.d.ts","sourceRoot":"","sources":["../../src/models/payment-result.model.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IAEjB,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,sFAAsF;IACtF,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,+EAA+E;IAC/E,GAAG,CAAC,EAAE,GAAG,CAAC;CACX;AAED,yCAAyC;AACzC,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"payment-result.model.d.ts","sourceRoot":"","sources":["../../src/models/payment-result.model.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IAEjB,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,sFAAsF;IACtF,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,wFAAwF;IACxF,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,+EAA+E;IAC/E,GAAG,CAAC,EAAE,GAAG,CAAC;CACX;AAED,yCAAyC;AACzC,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,wFAAwF;IACxF,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,GAAG,CAAC;CACX"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BasePaymentProvider } from '../../abstract/base-payment-provider.abstract';
|
|
2
2
|
import { PaymentRequest } from '../../models/payment-request.model';
|
|
3
|
-
import { PaymentResult } from '../../models/payment-result.model';
|
|
3
|
+
import { PaymentResult, WebhookResult } from '../../models/payment-result.model';
|
|
4
4
|
export interface NexiProviderConfig {
|
|
5
5
|
merchantId: string;
|
|
6
6
|
macKey: string;
|
|
@@ -23,6 +23,13 @@ export declare class NexiProvider extends BasePaymentProvider {
|
|
|
23
23
|
readonly flow: "redirect";
|
|
24
24
|
private readonly apiUrl;
|
|
25
25
|
constructor(config: NexiProviderConfig);
|
|
26
|
+
/**
|
|
27
|
+
* Computes the SHA-1 MAC required by Nexi to authenticate the payment request.
|
|
28
|
+
* Format: `codTrans={val}divisa={val}importo={val}{macKey}`
|
|
29
|
+
*
|
|
30
|
+
* SHA-1 is used here because Nexi XPay mandates it for MAC computation.
|
|
31
|
+
*/
|
|
32
|
+
private sha1;
|
|
26
33
|
/**
|
|
27
34
|
* Computes the SHA-1 MAC required by Nexi to authenticate the payment request.
|
|
28
35
|
* Format: `codTrans={val}divisa={val}importo={val}{macKey}`
|
|
@@ -31,8 +38,8 @@ export declare class NexiProvider extends BasePaymentProvider {
|
|
|
31
38
|
*/
|
|
32
39
|
private generateMac;
|
|
33
40
|
/**
|
|
34
|
-
* Computes the SHA-1 MAC for the status (
|
|
35
|
-
* Format: `
|
|
41
|
+
* Computes the SHA-1 MAC for the status (bo/situazioneOrdine) API call.
|
|
42
|
+
* Format: `apiKey={alias}codiceTransazione={codiceTransazione}timeStamp={timeStamp}{macKey}`
|
|
36
43
|
*/
|
|
37
44
|
private generateStatusMac;
|
|
38
45
|
/**
|
|
@@ -41,23 +48,34 @@ export declare class NexiProvider extends BasePaymentProvider {
|
|
|
41
48
|
*/
|
|
42
49
|
private generateRefundMac;
|
|
43
50
|
/**
|
|
44
|
-
|
|
45
|
-
*
|
|
51
|
+
/**
|
|
52
|
+
* Validates that the MAC is a string of exactly 40 hexadecimal characters.
|
|
53
|
+
*/
|
|
54
|
+
private isValidHexMac;
|
|
55
|
+
/**
|
|
56
|
+
* Verifies the SHA-1 outcome MAC included in a Nexi POST-back response or server notification.
|
|
57
|
+
* Format: `codTrans={codTrans}esito={esito}importo={importo}divisa={divisa}data={data}orario={orario}codAut={codAut}{macKey}`
|
|
46
58
|
*/
|
|
47
59
|
private verifyResponseMac;
|
|
60
|
+
private safeVerifyResponseMac;
|
|
48
61
|
createPayment(request: PaymentRequest): Promise<PaymentResult>;
|
|
49
62
|
/**
|
|
50
63
|
* Validates the POST-back data from Nexi.
|
|
51
64
|
* `data` is the query/body object sent by Nexi to the returnUrl.
|
|
52
|
-
* The MAC is verified before the result is considered authoritative.
|
|
65
|
+
* The outcome MAC is mandatory and verified over all 7 fields before the result is considered authoritative.
|
|
53
66
|
*/
|
|
54
67
|
executePayment(paymentId: string, data?: Record<string, string>): Promise<PaymentResult>;
|
|
68
|
+
/**
|
|
69
|
+
* Handles the incoming server-to-server outcome notification (urlpost) from Nexi.
|
|
70
|
+
* The outcome MAC is mandatory and verified over all 7 fields.
|
|
71
|
+
*/
|
|
72
|
+
handleWebhook(body?: Record<string, unknown>, _headers?: Record<string, string>): Promise<WebhookResult>;
|
|
55
73
|
getPaymentDetails(paymentId: string): Promise<PaymentResult>;
|
|
56
74
|
refundPayment(paymentId: string, amount?: number): Promise<PaymentResult>;
|
|
57
75
|
/**
|
|
58
76
|
* Handles the POST-back from Nexi to the returnUrl.
|
|
59
|
-
* Nexi sends `esito`, `codTrans`, `importo`, `divisa`, `mac`,
|
|
60
|
-
* The MAC is verified
|
|
77
|
+
* Nexi sends `esito`, `codTrans`, `importo`, `divisa`, `mac`, `data`, `orario`, `codAut` etc.
|
|
78
|
+
* The outcome MAC is mandatory and verified over all 7 fields to ensure authenticity.
|
|
61
79
|
*/
|
|
62
80
|
handleRedirect(query: Record<string, string>): Promise<PaymentResult>;
|
|
63
81
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nexi.provider.d.ts","sourceRoot":"","sources":["../../../src/providers/nexi/nexi.provider.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,+CAA+C,CAAC;AACpF,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"nexi.provider.d.ts","sourceRoot":"","sources":["../../../src/providers/nexi/nexi.provider.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,+CAA+C,CAAC;AACpF,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAGjF,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,gCAAgC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,WAAW,CAAC,EAAE,SAAS,GAAG,YAAY,CAAC;CACxC;AAED;;;;;;;GAOG;AACH,qBAAa,YAAa,SAAQ,mBAAmB;IAMvC,OAAO,CAAC,QAAQ,CAAC,MAAM;IALnC,QAAQ,CAAC,IAAI,UAAU;IACvB,QAAQ,CAAC,IAAI,EAAG,UAAU,CAAU;IAEpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAEH,MAAM,EAAE,kBAAkB;IAQvD;;;;;OAKG;IACH,OAAO,CAAC,IAAI;IAIZ;;;;;OAKG;IACH,OAAO,CAAC,WAAW;IAInB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IASzB;;;OAGG;IACH,OAAO,CAAC,aAAa;IAIrB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAwBzB,OAAO,CAAC,qBAAqB;IAiBvB,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAqCpE;;;;OAIG;IACG,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC;IA6C9F;;;OAGG;IACG,aAAa,CACjB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GACpC,OAAO,CAAC,aAAa,CAAC;IAuCnB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAwF5D,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAkC/E;;;;OAIG;IACG,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC;CAG5E"}
|
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.NexiProvider = void 0;
|
|
37
37
|
const crypto = __importStar(require("crypto"));
|
|
38
38
|
const base_payment_provider_abstract_1 = require("../../abstract/base-payment-provider.abstract");
|
|
39
|
+
const parsing_util_1 = require("../../utils/parsing.util");
|
|
39
40
|
/**
|
|
40
41
|
* Nexi eCommerce provider.
|
|
41
42
|
* Flow: `redirect` — builds a signed checkout URL, redirects the user to Nexi,
|
|
@@ -61,34 +62,64 @@ class NexiProvider extends base_payment_provider_abstract_1.BasePaymentProvider
|
|
|
61
62
|
*
|
|
62
63
|
* SHA-1 is used here because Nexi XPay mandates it for MAC computation.
|
|
63
64
|
*/
|
|
64
|
-
|
|
65
|
-
const raw = `codTrans=${codTrans}divisa=${divisa}importo=${importoCents}${this.config.macKey}`;
|
|
65
|
+
sha1(raw) {
|
|
66
66
|
return crypto.createHash('sha1').update(raw).digest('hex');
|
|
67
67
|
}
|
|
68
68
|
/**
|
|
69
|
-
* Computes the SHA-1 MAC
|
|
70
|
-
* Format: `
|
|
69
|
+
* Computes the SHA-1 MAC required by Nexi to authenticate the payment request.
|
|
70
|
+
* Format: `codTrans={val}divisa={val}importo={val}{macKey}`
|
|
71
|
+
*
|
|
72
|
+
* SHA-1 is used here because Nexi XPay mandates it for MAC computation.
|
|
71
73
|
*/
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
generateMac(codTrans, divisa, importoCents) {
|
|
75
|
+
return this.sha1(`codTrans=${codTrans}divisa=${divisa}importo=${importoCents}${this.config.macKey}`);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Computes the SHA-1 MAC for the status (bo/situazioneOrdine) API call.
|
|
79
|
+
* Format: `apiKey={alias}codiceTransazione={codiceTransazione}timeStamp={timeStamp}{macKey}`
|
|
80
|
+
*/
|
|
81
|
+
generateStatusMac(alias, codiceTransazione, timeStamp) {
|
|
82
|
+
return this.sha1(`apiKey=${alias}codiceTransazione=${codiceTransazione}timeStamp=${timeStamp}${this.config.macKey}`);
|
|
75
83
|
}
|
|
76
84
|
/**
|
|
77
85
|
* Computes the SHA-1 MAC for the refund (storno) API call.
|
|
78
86
|
* Format: `alias={alias}codTrans={codTrans}importo={importo}timestamp={timestamp}{macKey}`
|
|
79
87
|
*/
|
|
80
88
|
generateRefundMac(alias, codTrans, importo, timestamp) {
|
|
81
|
-
|
|
82
|
-
|
|
89
|
+
return this.sha1(`alias=${alias}codTrans=${codTrans}importo=${importo}timestamp=${timestamp}${this.config.macKey}`);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
/**
|
|
93
|
+
* Validates that the MAC is a string of exactly 40 hexadecimal characters.
|
|
94
|
+
*/
|
|
95
|
+
isValidHexMac(mac) {
|
|
96
|
+
return typeof mac === 'string' && /^[0-9a-fA-F]{40}$/.test(mac);
|
|
83
97
|
}
|
|
84
98
|
/**
|
|
85
|
-
* Verifies the SHA-1 MAC included in a Nexi POST-back response.
|
|
86
|
-
* Format: `codTrans={
|
|
99
|
+
* Verifies the SHA-1 outcome MAC included in a Nexi POST-back response or server notification.
|
|
100
|
+
* Format: `codTrans={codTrans}esito={esito}importo={importo}divisa={divisa}data={data}orario={orario}codAut={codAut}{macKey}`
|
|
87
101
|
*/
|
|
88
|
-
verifyResponseMac(codTrans, esito, importo, divisa, mac) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
102
|
+
verifyResponseMac(codTrans, esito, importo, divisa, dataStr, orario, codAut, mac) {
|
|
103
|
+
if (!this.isValidHexMac(mac)) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
const raw = `codTrans=${codTrans}esito=${esito}importo=${importo}divisa=${divisa}` +
|
|
107
|
+
`data=${dataStr}orario=${orario}codAut=${codAut}${this.config.macKey}`;
|
|
108
|
+
const expected = this.sha1(raw);
|
|
109
|
+
const expBuf = Buffer.from(expected, 'hex');
|
|
110
|
+
const macBuf = Buffer.from(mac, 'hex');
|
|
111
|
+
if (expBuf.length !== macBuf.length || expBuf.length === 0) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
return crypto.timingSafeEqual(expBuf, macBuf);
|
|
115
|
+
}
|
|
116
|
+
safeVerifyResponseMac(codTrans, esito, importo, divisa, dataStr, orario, codAut, mac) {
|
|
117
|
+
try {
|
|
118
|
+
return this.verifyResponseMac(codTrans, esito, importo, divisa, dataStr, orario, codAut, mac);
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
92
123
|
}
|
|
93
124
|
async createPayment(request) {
|
|
94
125
|
try {
|
|
@@ -104,6 +135,9 @@ class NexiProvider extends base_payment_provider_abstract_1.BasePaymentProvider
|
|
|
104
135
|
url_back: request.cancelUrl,
|
|
105
136
|
mac,
|
|
106
137
|
};
|
|
138
|
+
if (request.notifyUrl) {
|
|
139
|
+
params.urlpost = request.notifyUrl;
|
|
140
|
+
}
|
|
107
141
|
if (this.config.group) {
|
|
108
142
|
params.gruppo = this.config.group;
|
|
109
143
|
}
|
|
@@ -122,7 +156,7 @@ class NexiProvider extends base_payment_provider_abstract_1.BasePaymentProvider
|
|
|
122
156
|
/**
|
|
123
157
|
* Validates the POST-back data from Nexi.
|
|
124
158
|
* `data` is the query/body object sent by Nexi to the returnUrl.
|
|
125
|
-
* The MAC is verified before the result is considered authoritative.
|
|
159
|
+
* The outcome MAC is mandatory and verified over all 7 fields before the result is considered authoritative.
|
|
126
160
|
*/
|
|
127
161
|
async executePayment(paymentId, data) {
|
|
128
162
|
try {
|
|
@@ -130,28 +164,34 @@ class NexiProvider extends base_payment_provider_abstract_1.BasePaymentProvider
|
|
|
130
164
|
const codTrans = data?.codTrans ?? paymentId;
|
|
131
165
|
const importo = data?.importo ?? '';
|
|
132
166
|
const divisa = data?.divisa ?? '';
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
167
|
+
const dataStr = data?.data ?? '';
|
|
168
|
+
const orario = data?.orario ?? '';
|
|
169
|
+
const codAut = data?.codAut ?? '';
|
|
170
|
+
const mac = data?.mac;
|
|
171
|
+
if (!mac) {
|
|
172
|
+
return {
|
|
173
|
+
success: false,
|
|
174
|
+
paymentId: codTrans,
|
|
175
|
+
status: 'FAILED',
|
|
176
|
+
error: 'MAC missing',
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
if (!this.isValidHexMac(mac) || !this.safeVerifyResponseMac(codTrans, esito, importo, divisa, dataStr, orario, codAut, mac)) {
|
|
180
|
+
return {
|
|
181
|
+
success: false,
|
|
182
|
+
paymentId: codTrans,
|
|
183
|
+
status: 'FAILED',
|
|
184
|
+
error: 'MAC verification failed: response may have been tampered with',
|
|
185
|
+
};
|
|
150
186
|
}
|
|
187
|
+
const amount = (0, parsing_util_1.parseAmountFromCents)(importo);
|
|
188
|
+
const currency = (0, parsing_util_1.parseNexiCurrency)(divisa);
|
|
151
189
|
return {
|
|
152
190
|
success: esito === 'OK',
|
|
153
191
|
paymentId: codTrans,
|
|
154
192
|
status: esito === 'OK' ? 'COMPLETED' : 'FAILED',
|
|
193
|
+
amount,
|
|
194
|
+
currency,
|
|
155
195
|
raw: data,
|
|
156
196
|
};
|
|
157
197
|
}
|
|
@@ -159,25 +199,120 @@ class NexiProvider extends base_payment_provider_abstract_1.BasePaymentProvider
|
|
|
159
199
|
return this.errorResult(error, 'Failed to execute Nexi payment');
|
|
160
200
|
}
|
|
161
201
|
}
|
|
202
|
+
/**
|
|
203
|
+
* Handles the incoming server-to-server outcome notification (urlpost) from Nexi.
|
|
204
|
+
* The outcome MAC is mandatory and verified over all 7 fields.
|
|
205
|
+
*/
|
|
206
|
+
async handleWebhook(body, _headers = {}) {
|
|
207
|
+
try {
|
|
208
|
+
if (!body) {
|
|
209
|
+
return { success: false, error: 'MAC verification failed' };
|
|
210
|
+
}
|
|
211
|
+
const f = (k) => String(body?.[k] ?? '');
|
|
212
|
+
const codTrans = f('codTrans');
|
|
213
|
+
const esito = f('esito');
|
|
214
|
+
const importo = f('importo');
|
|
215
|
+
const divisa = f('divisa');
|
|
216
|
+
const dataStr = f('data');
|
|
217
|
+
const orario = f('orario');
|
|
218
|
+
const codAut = f('codAut');
|
|
219
|
+
const mac = body?.['mac'];
|
|
220
|
+
if (!this.isValidHexMac(mac) || !this.safeVerifyResponseMac(codTrans, esito, importo, divisa, dataStr, orario, codAut, mac)) {
|
|
221
|
+
return {
|
|
222
|
+
success: false,
|
|
223
|
+
paymentId: codTrans || undefined,
|
|
224
|
+
error: 'MAC verification failed',
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
const amount = (0, parsing_util_1.parseAmountFromCents)(importo);
|
|
228
|
+
const currency = (0, parsing_util_1.parseNexiCurrency)(divisa);
|
|
229
|
+
return {
|
|
230
|
+
success: esito === 'OK',
|
|
231
|
+
paymentId: codTrans,
|
|
232
|
+
status: esito === 'OK' ? 'COMPLETED' : 'FAILED',
|
|
233
|
+
amount,
|
|
234
|
+
currency,
|
|
235
|
+
raw: body,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
catch (error) {
|
|
239
|
+
return { success: false, error: 'MAC verification failed' };
|
|
240
|
+
}
|
|
241
|
+
}
|
|
162
242
|
async getPaymentDetails(paymentId) {
|
|
163
243
|
try {
|
|
164
|
-
const
|
|
165
|
-
const mac = this.generateStatusMac(this.config.merchantId, paymentId,
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
244
|
+
const timeStamp = String(Date.now());
|
|
245
|
+
const mac = this.generateStatusMac(this.config.merchantId, paymentId, timeStamp);
|
|
246
|
+
const requestBody = {
|
|
247
|
+
apiKey: this.config.merchantId,
|
|
248
|
+
codiceTransazione: paymentId,
|
|
249
|
+
timeStamp,
|
|
170
250
|
mac,
|
|
171
251
|
};
|
|
172
|
-
const response = await fetch(`${this.apiUrl}/ecomm/api/
|
|
252
|
+
const response = await fetch(`${this.apiUrl}/ecomm/api/bo/situazioneOrdine`, {
|
|
173
253
|
method: 'POST',
|
|
174
|
-
headers: { 'Content-Type': 'application/
|
|
175
|
-
body:
|
|
254
|
+
headers: { 'Content-Type': 'application/json' },
|
|
255
|
+
body: JSON.stringify(requestBody),
|
|
176
256
|
});
|
|
177
257
|
if (!response.ok)
|
|
178
258
|
throw new Error(`Nexi API error: ${response.statusText}`);
|
|
179
259
|
const result = await response.json();
|
|
180
|
-
|
|
260
|
+
const esito = String(result['esito'] ?? '');
|
|
261
|
+
if (esito !== 'OK') {
|
|
262
|
+
const errMsg = result['errore']?.messaggio ?? 'Payment details request failed';
|
|
263
|
+
return { success: false, paymentId, error: errMsg, raw: result };
|
|
264
|
+
}
|
|
265
|
+
// Verify response MAC
|
|
266
|
+
const idOperazione = String(result['idOperazione'] ?? '');
|
|
267
|
+
const respTimeStamp = String(result['timeStamp'] ?? '');
|
|
268
|
+
const expectedMac = this.sha1(`esito=${esito}idOperazione=${idOperazione}timeStamp=${respTimeStamp}${this.config.macKey}`);
|
|
269
|
+
const respMac = result['mac'];
|
|
270
|
+
if (!this.isValidHexMac(respMac)) {
|
|
271
|
+
return {
|
|
272
|
+
success: false,
|
|
273
|
+
paymentId,
|
|
274
|
+
error: 'MAC verification failed: response may have been tampered with',
|
|
275
|
+
raw: result,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
const expBuf = Buffer.from(expectedMac, 'hex');
|
|
279
|
+
const macBuf = Buffer.from(respMac, 'hex');
|
|
280
|
+
let macValid = false;
|
|
281
|
+
try {
|
|
282
|
+
macValid = expBuf.length === macBuf.length && expBuf.length > 0 && crypto.timingSafeEqual(expBuf, macBuf);
|
|
283
|
+
}
|
|
284
|
+
catch {
|
|
285
|
+
macValid = false;
|
|
286
|
+
}
|
|
287
|
+
if (!macValid) {
|
|
288
|
+
return {
|
|
289
|
+
success: false,
|
|
290
|
+
paymentId,
|
|
291
|
+
error: 'MAC verification failed: response may have been tampered with',
|
|
292
|
+
raw: result,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
const report = Array.isArray(result['report']) ? result['report'] : [];
|
|
296
|
+
const item = report.find((r) => r?.codiceTransazione === paymentId);
|
|
297
|
+
if (!item) {
|
|
298
|
+
return {
|
|
299
|
+
success: false,
|
|
300
|
+
paymentId,
|
|
301
|
+
error: 'Report not found',
|
|
302
|
+
raw: result,
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
const stato = item.stato;
|
|
306
|
+
const amount = (0, parsing_util_1.parseAmountFromCents)(item.importo);
|
|
307
|
+
const currency = (0, parsing_util_1.parseNexiCurrency)(item.divisa);
|
|
308
|
+
return {
|
|
309
|
+
success: true,
|
|
310
|
+
paymentId,
|
|
311
|
+
status: stato,
|
|
312
|
+
amount,
|
|
313
|
+
currency,
|
|
314
|
+
raw: result,
|
|
315
|
+
};
|
|
181
316
|
}
|
|
182
317
|
catch (error) {
|
|
183
318
|
return this.errorResult(error, 'Failed to get Nexi payment details');
|
|
@@ -216,8 +351,8 @@ class NexiProvider extends base_payment_provider_abstract_1.BasePaymentProvider
|
|
|
216
351
|
}
|
|
217
352
|
/**
|
|
218
353
|
* Handles the POST-back from Nexi to the returnUrl.
|
|
219
|
-
* Nexi sends `esito`, `codTrans`, `importo`, `divisa`, `mac`,
|
|
220
|
-
* The MAC is verified
|
|
354
|
+
* Nexi sends `esito`, `codTrans`, `importo`, `divisa`, `mac`, `data`, `orario`, `codAut` etc.
|
|
355
|
+
* The outcome MAC is mandatory and verified over all 7 fields to ensure authenticity.
|
|
221
356
|
*/
|
|
222
357
|
async handleRedirect(query) {
|
|
223
358
|
return this.executePayment(query['codTrans'] ?? '', query);
|