strapi-plugin-payone-provider 5.6.10 → 5.6.12
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/README.md +99 -608
- package/admin/src/components/PluginIcon/index.jsx +14 -3
- package/admin/src/pages/App/components/AppHeader.jsx +1 -1
- package/admin/src/pages/App/components/AppTabs.jsx +8 -5
- package/admin/src/pages/App/components/StatusBadge.jsx +69 -17
- package/admin/src/pages/App/components/configuration/ConfigurationPanel.jsx +2 -2
- package/admin/src/pages/App/components/icons/index.jsx +1 -0
- package/admin/src/pages/App/components/transaction-history/FiltersPanel.jsx +4 -3
- package/admin/src/pages/App/components/transaction-history/TransactionTable.jsx +6 -5
- package/admin/src/pages/App/components/transaction-history/details/TransactionDetails.jsx +10 -10
- package/admin/src/pages/hooks/useSettings.js +0 -1
- package/admin/src/pages/utils/api.js +3 -2
- package/admin/src/pages/utils/transactionTableUtils.js +2 -1
- package/package.json +2 -2
- package/server/bootstrap.js +5 -6
- package/server/content-types/index.js +5 -0
- package/server/content-types/transactions/index.js +5 -0
- package/server/content-types/transactions/schema.json +87 -0
- package/server/controllers/payone.js +24 -13
- package/server/index.js +2 -0
- package/server/policies/is-payone-notification.js +12 -23
- package/server/services/transactionService.js +137 -104
- package/server/services/transactionStatusService.js +55 -61
- package/server/utils/requestBuilder.js +4 -32
- package/server/utils/sanitize.js +42 -0
|
@@ -1,139 +1,172 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const { sanitizeSensitive } = require("../utils/sanitize");
|
|
4
4
|
|
|
5
|
-
const
|
|
6
|
-
const pluginStore = getPluginStore(strapi);
|
|
7
|
-
let transactionHistory =
|
|
8
|
-
(await pluginStore.get({ key: "transactionHistory" })) || [];
|
|
9
|
-
|
|
10
|
-
const logEntry = {
|
|
11
|
-
id: Date.now().toString(),
|
|
12
|
-
timestamp: new Date().toISOString(),
|
|
13
|
-
txid: transactionData.txid || null,
|
|
14
|
-
reference: transactionData.reference || null,
|
|
15
|
-
invoiceid: transactionData.invoiceid || null,
|
|
16
|
-
request_type:
|
|
17
|
-
transactionData.request_type || transactionData.request || "unknown",
|
|
18
|
-
amount: transactionData.amount || null,
|
|
19
|
-
currency: transactionData.currency || "EUR",
|
|
20
|
-
status: transactionData.status || transactionData.Status || "unknown",
|
|
21
|
-
error_code:
|
|
22
|
-
transactionData.error_code || transactionData.Error?.ErrorCode || null,
|
|
23
|
-
error_message:
|
|
24
|
-
transactionData.error_message ||
|
|
25
|
-
transactionData.Error?.ErrorMessage ||
|
|
26
|
-
null,
|
|
27
|
-
customer_message:
|
|
28
|
-
transactionData.customer_message ||
|
|
29
|
-
transactionData.Error?.CustomerMessage ||
|
|
30
|
-
null,
|
|
31
|
-
body: transactionData || null,
|
|
32
|
-
created_at: new Date().toISOString(),
|
|
33
|
-
updated_at: new Date().toISOString()
|
|
34
|
-
};
|
|
5
|
+
const TRANSACTION_UID = "plugin::strapi-plugin-payone-provider.transaction";
|
|
35
6
|
|
|
36
|
-
|
|
7
|
+
const logTransaction = async (strapi, transactionData) => {
|
|
8
|
+
try {
|
|
9
|
+
const data = {
|
|
10
|
+
txid: transactionData.txid || 'NO TXID',
|
|
11
|
+
reference: transactionData.reference || 'NO REFERENCE',
|
|
12
|
+
invoiceid: transactionData.raw_request.invoiceid || 'NO INVOICE ID',
|
|
13
|
+
request_type: transactionData.request_type || "unknown",
|
|
14
|
+
amount: transactionData.amount || "0",
|
|
15
|
+
currency: transactionData.currency || "EUR",
|
|
16
|
+
status: transactionData.status || transactionData.raw_response.Status || "unknown",
|
|
17
|
+
error_code: transactionData.error_code || "NO ERROR CODE",
|
|
18
|
+
error_message: transactionData.error_message || "NO ERROR MESSAGE",
|
|
19
|
+
customer_message: transactionData.customer_message || "NO CUSTOMER MESSAGE",
|
|
20
|
+
body: transactionData ? { ...transactionData, raw_request: sanitizeSensitive(transactionData.raw_request), raw_response: sanitizeSensitive(transactionData.raw_response) } : {},
|
|
21
|
+
raw_request: sanitizeSensitive(transactionData.raw_request || {}),
|
|
22
|
+
raw_response: sanitizeSensitive(transactionData.raw_response || {}),
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const entry = await strapi.db.query(TRANSACTION_UID).create({ data });
|
|
26
|
+
console.info("Transaction logged to DB:", {
|
|
27
|
+
id: entry.id,
|
|
28
|
+
txid: entry.txid,
|
|
29
|
+
status: entry.status
|
|
30
|
+
});
|
|
37
31
|
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
return entry;
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error("Failed to log transaction:", error);
|
|
40
35
|
}
|
|
36
|
+
};
|
|
41
37
|
|
|
42
|
-
await pluginStore.set({
|
|
43
|
-
key: "transactionHistory",
|
|
44
|
-
value: transactionHistory
|
|
45
|
-
});
|
|
46
38
|
|
|
47
|
-
|
|
48
|
-
|
|
39
|
+
const hasFilterValue = (v) =>
|
|
40
|
+
typeof v === "string" && v.trim() !== "" && v.trim().toLowerCase() !== "all";
|
|
49
41
|
|
|
42
|
+
const buildWhereFromFilters = (filters = {}) => {
|
|
43
|
+
const conditions = [];
|
|
50
44
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return txid.includes(search) || reference.includes(search);
|
|
45
|
+
if (hasFilterValue(filters.search)) {
|
|
46
|
+
const search = String(filters.search).trim();
|
|
47
|
+
conditions.push({
|
|
48
|
+
$or: [
|
|
49
|
+
{ txid: { $containsi: search } },
|
|
50
|
+
{ reference: { $containsi: search } },
|
|
51
|
+
],
|
|
59
52
|
});
|
|
60
53
|
}
|
|
61
54
|
|
|
62
|
-
if (filters.status) {
|
|
63
|
-
|
|
64
|
-
(t) => (t.status || "").toUpperCase() === filters.status.toUpperCase()
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (filters.request_type) {
|
|
69
|
-
result = result.filter((t) => t.request_type === filters.request_type);
|
|
55
|
+
if (hasFilterValue(filters.status)) {
|
|
56
|
+
conditions.push({ status: { $eqi: String(filters.status).trim() } });
|
|
70
57
|
}
|
|
71
58
|
|
|
72
|
-
if (filters.
|
|
73
|
-
|
|
74
|
-
const clearingtype = t.raw_request?.clearingtype;
|
|
75
|
-
const wallettype = t.raw_request?.wallettype;
|
|
76
|
-
|
|
77
|
-
switch (filters.payment_method) {
|
|
78
|
-
case "credit_card":
|
|
79
|
-
return clearingtype === "cc";
|
|
80
|
-
case "paypal":
|
|
81
|
-
return clearingtype === "wlt" && wallettype === "PPE";
|
|
82
|
-
case "google_pay":
|
|
83
|
-
return clearingtype === "wlt" && ["GPY", "GOOGLEPAY"].includes(wallettype);
|
|
84
|
-
case "apple_pay":
|
|
85
|
-
return clearingtype === "wlt" && ["APL", "APPLEPAY"].includes(wallettype);
|
|
86
|
-
case "sofort":
|
|
87
|
-
return clearingtype === "sb";
|
|
88
|
-
case "sepa":
|
|
89
|
-
return clearingtype === "elv";
|
|
90
|
-
default:
|
|
91
|
-
return true;
|
|
92
|
-
}
|
|
93
|
-
});
|
|
59
|
+
if (hasFilterValue(filters.request_type)) {
|
|
60
|
+
conditions.push({ request_type: String(filters.request_type).trim() });
|
|
94
61
|
}
|
|
95
62
|
|
|
96
|
-
if (filters.date_from) {
|
|
63
|
+
if (hasFilterValue(filters.date_from)) {
|
|
97
64
|
const dateFrom = new Date(filters.date_from);
|
|
98
65
|
dateFrom.setHours(0, 0, 0, 0);
|
|
99
|
-
|
|
100
|
-
(t) => new Date(t.timestamp) >= dateFrom
|
|
101
|
-
);
|
|
66
|
+
conditions.push({ createdAt: { $gte: dateFrom.toISOString() } });
|
|
102
67
|
}
|
|
103
68
|
|
|
104
|
-
if (filters.date_to) {
|
|
69
|
+
if (hasFilterValue(filters.date_to)) {
|
|
105
70
|
const dateTo = new Date(filters.date_to);
|
|
106
71
|
dateTo.setHours(23, 59, 59, 999);
|
|
107
|
-
|
|
108
|
-
(t) => new Date(t.timestamp) <= dateTo
|
|
109
|
-
);
|
|
72
|
+
conditions.push({ createdAt: { $lte: dateTo.toISOString() } });
|
|
110
73
|
}
|
|
111
74
|
|
|
112
|
-
|
|
113
|
-
|
|
75
|
+
if (hasFilterValue(filters.payment_method)) {
|
|
76
|
+
switch (filters.payment_method) {
|
|
77
|
+
case "credit_card":
|
|
78
|
+
conditions.push({ raw_request: { $containsi: '"clearingtype":"cc"' } });
|
|
79
|
+
break;
|
|
80
|
+
case "paypal":
|
|
81
|
+
conditions.push({
|
|
82
|
+
$and: [
|
|
83
|
+
{ raw_request: { $containsi: '"clearingtype":"wlt"' } },
|
|
84
|
+
{ raw_request: { $containsi: '"wallettype":"PPE"' } },
|
|
85
|
+
],
|
|
86
|
+
});
|
|
87
|
+
break;
|
|
88
|
+
case "google_pay":
|
|
89
|
+
conditions.push({
|
|
90
|
+
$and: [
|
|
91
|
+
{ raw_request: { $containsi: '"clearingtype":"wlt"' } },
|
|
92
|
+
{
|
|
93
|
+
$or: [
|
|
94
|
+
{ raw_request: { $containsi: '"wallettype":"GPY"' } },
|
|
95
|
+
{ raw_request: { $containsi: '"wallettype":"GOOGLEPAY"' } },
|
|
96
|
+
],
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
});
|
|
100
|
+
break;
|
|
101
|
+
case "apple_pay":
|
|
102
|
+
conditions.push({
|
|
103
|
+
$and: [
|
|
104
|
+
{ raw_request: { $containsi: '"clearingtype":"wlt"' } },
|
|
105
|
+
{
|
|
106
|
+
$or: [
|
|
107
|
+
{ raw_request: { $containsi: '"wallettype":"APL"' } },
|
|
108
|
+
{ raw_request: { $containsi: '"wallettype":"APPLEPAY"' } },
|
|
109
|
+
],
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
});
|
|
113
|
+
break;
|
|
114
|
+
case "sofort":
|
|
115
|
+
conditions.push({ raw_request: { $containsi: '"clearingtype":"sb"' } });
|
|
116
|
+
break;
|
|
117
|
+
case "sepa":
|
|
118
|
+
conditions.push({ raw_request: { $containsi: '"clearingtype":"elv"' } });
|
|
119
|
+
break;
|
|
120
|
+
default:
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
114
124
|
|
|
115
|
-
|
|
116
|
-
|
|
125
|
+
if (conditions.length === 0) return undefined;
|
|
126
|
+
if (conditions.length === 1) return conditions[0];
|
|
127
|
+
return { $and: conditions };
|
|
128
|
+
};
|
|
117
129
|
|
|
118
|
-
|
|
119
|
-
|
|
130
|
+
const ALLOWED_SORT_FIELDS = [
|
|
131
|
+
"txid",
|
|
132
|
+
"reference",
|
|
133
|
+
"amount",
|
|
134
|
+
"request_type",
|
|
135
|
+
"status",
|
|
136
|
+
"createdAt",
|
|
137
|
+
"updatedAt",
|
|
138
|
+
];
|
|
139
|
+
|
|
140
|
+
const getTransactionHistory = async (
|
|
141
|
+
strapi,
|
|
142
|
+
{ filters = {}, pagination = {}, sort_by, sort_order }
|
|
143
|
+
) => {
|
|
144
|
+
const page = Math.max(1, Number(pagination.page) || 1);
|
|
145
|
+
const pageSize = Math.min(100, Math.max(1, Number(pagination.pageSize) || 10));
|
|
146
|
+
const offset = (page - 1) * pageSize;
|
|
147
|
+
|
|
148
|
+
const where = buildWhereFromFilters(filters);
|
|
149
|
+
|
|
150
|
+
const sortField =
|
|
151
|
+
sort_by && ALLOWED_SORT_FIELDS.includes(sort_by) ? sort_by : "createdAt";
|
|
152
|
+
const order = sort_order === "asc" ? "asc" : "desc";
|
|
153
|
+
|
|
154
|
+
const queryOptions = {
|
|
155
|
+
orderBy: { [sortField]: order },
|
|
156
|
+
limit: pageSize,
|
|
157
|
+
offset,
|
|
158
|
+
};
|
|
159
|
+
if (where !== undefined) queryOptions.where = where;
|
|
120
160
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
161
|
+
const [data, total] = await strapi.db
|
|
162
|
+
.query(TRANSACTION_UID)
|
|
163
|
+
.findWithCount(queryOptions);
|
|
124
164
|
|
|
125
|
-
const total = transactions.length;
|
|
126
165
|
const pageCount = Math.max(1, Math.ceil(total / pageSize));
|
|
127
|
-
|
|
128
|
-
const validPage = Math.min(Math.max(1, page), pageCount);
|
|
129
|
-
|
|
130
|
-
const start = (validPage - 1) * pageSize;
|
|
131
|
-
const end = Math.min(start + pageSize, total);
|
|
132
|
-
|
|
133
|
-
const paginatedData = start < total ? transactions.slice(start, end) : [];
|
|
166
|
+
const validPage = Math.min(page, pageCount);
|
|
134
167
|
|
|
135
168
|
return {
|
|
136
|
-
data
|
|
169
|
+
data,
|
|
137
170
|
pagination: {
|
|
138
171
|
page: validPage,
|
|
139
172
|
pageSize,
|
|
@@ -1,87 +1,81 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const {
|
|
3
|
+
const { getSettings } = require("./settingsService");
|
|
4
|
+
const { sanitizeSensitive } = require("../utils/sanitize");
|
|
5
5
|
|
|
6
|
-
const
|
|
7
|
-
const {
|
|
8
|
-
portalid = "",
|
|
9
|
-
aid = "",
|
|
10
|
-
txid = "",
|
|
11
|
-
sequencenumber = "",
|
|
12
|
-
price = "",
|
|
13
|
-
currency = "",
|
|
14
|
-
mode = "",
|
|
15
|
-
} = notificationData;
|
|
6
|
+
const TRANSACTION_UID = "plugin::strapi-plugin-payone-provider.transaction";
|
|
16
7
|
|
|
17
|
-
|
|
18
|
-
const
|
|
8
|
+
const genreateUpdateData = (notificationData, existing, safeNotification) => {
|
|
9
|
+
const amount = String(notificationData.clearing_amount) || String(Math.round(parseFloat(notificationData.price) * 100)) || existing.amount;
|
|
10
|
+
const raw_request = {
|
|
11
|
+
...existing.raw_request,
|
|
12
|
+
...notificationData,
|
|
13
|
+
mode: notificationData.mode,
|
|
14
|
+
amount,
|
|
15
|
+
clearingtype: notificationData.clearingtype || existing.clearingtype,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
status: notificationData.transaction_status || existing.status,
|
|
20
|
+
currency: notificationData.currency || existing.currency,
|
|
21
|
+
reference: notificationData.reference || existing.reference,
|
|
22
|
+
amount,
|
|
23
|
+
body: {
|
|
24
|
+
...existing.body,
|
|
25
|
+
status: notificationData.transaction_status,
|
|
26
|
+
amount,
|
|
27
|
+
raw_request: sanitizeSensitive(raw_request),
|
|
28
|
+
payone_notification_data: safeNotification,
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const validateData = (notificationData, settings) => {
|
|
34
|
+
const isExist = (settings.portalid && settings.aid && settings.key) && (notificationData.portalid && notificationData.aid && notificationData.key);
|
|
35
|
+
const isMatch = notificationData.portalid === settings.portalid && notificationData.aid === settings.aid && notificationData.key === settings.key;
|
|
36
|
+
|
|
37
|
+
if (!isExist) {
|
|
38
|
+
console.log("[Payone TransactionStatus] Settings not found or payone data missing");
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
19
41
|
|
|
20
|
-
|
|
42
|
+
if (!isMatch) {
|
|
43
|
+
console.log("[Payone TransactionStatus] Payone data mismatch with settings");
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return true;
|
|
21
48
|
};
|
|
22
49
|
|
|
50
|
+
|
|
23
51
|
const processTransactionStatus = async (strapi, notificationData) => {
|
|
24
52
|
try {
|
|
25
53
|
const settings = await getSettings(strapi);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (!settings || !settings.key) {
|
|
29
|
-
console.log("[Payone TransactionStatus] Settings not found or key missing");
|
|
54
|
+
if (!validateData(notificationData, settings)) {
|
|
30
55
|
return;
|
|
31
56
|
}
|
|
32
57
|
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
console.log(`[Payone TransactionStatus] Hash verification failed txid: ${txid}`);
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
58
|
+
const txid = notificationData.txid;
|
|
59
|
+
const existing = await strapi.db.query(TRANSACTION_UID).findOne({ where: { txid } });
|
|
38
60
|
|
|
39
|
-
if (
|
|
40
|
-
console.log(`[Payone TransactionStatus]
|
|
61
|
+
if (!existing) {
|
|
62
|
+
console.log(`[Payone TransactionStatus] Transaction ${txid} not found. Notification ignored.`);
|
|
41
63
|
return;
|
|
42
64
|
}
|
|
43
65
|
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
Object.assign(transaction, {
|
|
51
|
-
...notificationData,
|
|
52
|
-
status: notificationData?.transaction_status,
|
|
53
|
-
txaction: notificationData?.txaction,
|
|
54
|
-
txtime: notificationData?.txtime,
|
|
55
|
-
sequencenumber: notificationData?.sequencenumber,
|
|
56
|
-
balance: notificationData?.balance,
|
|
57
|
-
receivable: notificationData?.receivable,
|
|
58
|
-
price: notificationData?.price,
|
|
59
|
-
amount: notificationData?.price ? parseFloat(notificationData?.price) * 100 : transaction?.amount,
|
|
60
|
-
userid: notificationData?.userid,
|
|
61
|
-
updated_at: new Date().toISOString(),
|
|
62
|
-
body: {
|
|
63
|
-
...transaction?.body,
|
|
64
|
-
...notificationData,
|
|
65
|
-
status: notificationData?.transaction_status
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
await pluginStore.set({
|
|
70
|
-
key: "transactionHistory",
|
|
71
|
-
value: transactionHistory,
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
console.log(`[Payone TransactionStatus] Successfully updated transaction txid: ${txid}`);
|
|
75
|
-
} else {
|
|
76
|
-
console.log(`[Payone TransactionStatus] Transaction ${txid} not found in history. Notification ignored.`);
|
|
77
|
-
}
|
|
66
|
+
const safeNotification = sanitizeSensitive({ ...notificationData });
|
|
67
|
+
const data = genreateUpdateData(notificationData, existing, safeNotification);
|
|
68
|
+
await strapi.db.query(TRANSACTION_UID).update({
|
|
69
|
+
where: { id: existing.id },
|
|
70
|
+
data,
|
|
71
|
+
});
|
|
78
72
|
|
|
73
|
+
console.log(`[Payone TransactionStatus] Successfully updated transaction txid: ${txid}`);
|
|
79
74
|
} catch (error) {
|
|
80
75
|
console.log(`[Payone TransactionStatus] Error processing notification: ${error}`);
|
|
81
76
|
}
|
|
82
77
|
};
|
|
83
78
|
|
|
84
79
|
module.exports = {
|
|
85
|
-
verifyHash,
|
|
86
80
|
processTransactionStatus,
|
|
87
81
|
};
|
|
@@ -2,38 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const crypto = require("crypto");
|
|
4
4
|
const { normalizeCustomerId } = require("./normalize");
|
|
5
|
-
const calculateKeyHash = (settings, params) => {
|
|
6
|
-
const portalKey = settings.portalKey || settings.key;
|
|
7
|
-
const portalid = String(settings.portalid || "");
|
|
8
|
-
const aid = String(settings.aid || "");
|
|
9
|
-
const mode = String(settings.mode || "test");
|
|
10
|
-
|
|
11
|
-
const requestType = params.request || "";
|
|
12
|
-
|
|
13
|
-
// For Capture and Refund operations
|
|
14
|
-
if (requestType === "capture" || requestType === "refund") {
|
|
15
|
-
const txid = String(params.txid || "");
|
|
16
|
-
const sequencenumber = String(params.sequencenumber || "");
|
|
17
|
-
const amount = String(params.amount || "");
|
|
18
|
-
const currency = String(params.currency || "EUR");
|
|
19
|
-
|
|
20
|
-
const hashString = `${portalid}${aid}${txid}${sequencenumber}${amount}${currency}${mode}${portalKey}`;
|
|
21
|
-
return crypto.createHash("md5").update(hashString).digest("hex");
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// For Preauthorization and Authorization operations
|
|
25
|
-
if (requestType === "preauthorization" || requestType === "authorization") {
|
|
26
|
-
const amount = String(params.amount || "");
|
|
27
|
-
const currency = String(params.currency || "EUR");
|
|
28
|
-
const reference = String(params.reference || "");
|
|
29
5
|
|
|
30
|
-
const hashString = `${portalid}${aid}${amount}${currency}${reference}${mode}${portalKey}`;
|
|
31
|
-
return crypto.createHash("md5").update(hashString).digest("hex");
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const hashString = `${portalid}${aid}${mode}${portalKey}`;
|
|
35
|
-
return crypto.createHash("md5").update(hashString).digest("hex");
|
|
36
|
-
};
|
|
37
6
|
|
|
38
7
|
const buildClientRequestParams = (settings, params, logger = null) => {
|
|
39
8
|
const requestParams = {
|
|
@@ -51,7 +20,10 @@ const buildClientRequestParams = (settings, params, logger = null) => {
|
|
|
51
20
|
logger
|
|
52
21
|
);
|
|
53
22
|
|
|
54
|
-
requestParams.key =
|
|
23
|
+
requestParams.key = crypto
|
|
24
|
+
.createHash("md5")
|
|
25
|
+
.update(settings.portalKey || settings.key)
|
|
26
|
+
.digest("hex");
|
|
55
27
|
|
|
56
28
|
const isCreditCard = requestParams.clearingtype === "cc";
|
|
57
29
|
const enable3DSecure = settings.enable3DSecure !== false;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const SENSITIVE_KEYS = [
|
|
4
|
+
"cardpan",
|
|
5
|
+
"cardexpiredate",
|
|
6
|
+
"cardcvc2",
|
|
7
|
+
"iban",
|
|
8
|
+
"bic",
|
|
9
|
+
"bankaccount",
|
|
10
|
+
"bankcode",
|
|
11
|
+
"bankaccountholder",
|
|
12
|
+
"key",
|
|
13
|
+
"accesscode",
|
|
14
|
+
"accessname",
|
|
15
|
+
"token",
|
|
16
|
+
"redirecturl",
|
|
17
|
+
"Identifier"
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
const maskValue = (val) => {
|
|
21
|
+
if (typeof val !== "string") return val;
|
|
22
|
+
return "*".repeat(Math.min(val.length, 20));
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const sanitizeSensitive = (obj) => {
|
|
26
|
+
if (!obj || typeof obj !== "object") return obj;
|
|
27
|
+
if (Array.isArray(obj)) return obj.map(sanitizeSensitive);
|
|
28
|
+
const out = {};
|
|
29
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
30
|
+
const keyLower = k.toLowerCase();
|
|
31
|
+
if (SENSITIVE_KEYS.includes(keyLower) && v != null) {
|
|
32
|
+
out[k] = maskValue(String(v));
|
|
33
|
+
} else if (v != null && typeof v === "object" && !Array.isArray(v)) {
|
|
34
|
+
out[k] = sanitizeSensitive(v);
|
|
35
|
+
} else {
|
|
36
|
+
out[k] = v;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
module.exports = { sanitizeSensitive };
|