strapi-plugin-payone-provider 5.7.21 → 5.7.22
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/admin/src/pages/App/components/configuration/ConfigurationFields.jsx +106 -105
- package/admin/src/pages/App/components/transaction-history/TransactionTable.jsx +35 -17
- package/admin/src/pages/hooks/useSettings.js +7 -0
- package/package.json +1 -1
- package/server/config/index.js +21 -0
- package/server/controllers/payone.js +17 -28
- package/server/routes/index.js +3 -10
- package/server/services/index.js +3 -1
- package/server/services/newHostedTokenizationService.js +59 -0
- package/server/services/payone.js +1 -1
- package/server/services/settingsService.js +12 -1
- package/server/utils/sanitize.js +14 -1
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
CardBody,
|
|
6
6
|
Flex,
|
|
7
7
|
Typography,
|
|
8
|
+
Accordion
|
|
8
9
|
} from "@strapi/design-system";
|
|
9
10
|
import { Cog } from "@strapi/icons";
|
|
10
11
|
import RenderInput from "../RenderInput";
|
|
@@ -39,110 +40,110 @@ const ConfigurationFields = ({
|
|
|
39
40
|
}}
|
|
40
41
|
>
|
|
41
42
|
<Flex direction="column" alignItems={"stretch"} gap={6}>
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
43
|
+
<Flex direction="row" gap={2}>
|
|
44
|
+
<RenderInput
|
|
45
|
+
label={t("config.fields.aid", "Account ID (aid)")}
|
|
46
|
+
name="aid"
|
|
47
|
+
value={settings.aid}
|
|
48
|
+
onChange={(e) => onInputChange("aid", e.target.value)}
|
|
49
|
+
required
|
|
50
|
+
inputType="textInput"
|
|
51
|
+
tooltipContent={t("config.fields.aidTooltip", "Your Payone account ID")}
|
|
52
|
+
/>
|
|
53
|
+
<RenderInput
|
|
54
|
+
label={t("config.fields.portalid", "Portal ID")}
|
|
55
|
+
name="portalid"
|
|
56
|
+
value={settings.portalid}
|
|
57
|
+
onChange={(e) => onInputChange("portalid", e.target.value)}
|
|
58
|
+
required
|
|
59
|
+
inputType="textInput"
|
|
60
|
+
tooltipContent={t("config.fields.portalidTooltip", "Your Payone portal ID")}
|
|
61
|
+
/>
|
|
62
|
+
</Flex>
|
|
63
|
+
<Flex direction="row" gap={2}>
|
|
64
|
+
<RenderInput
|
|
65
|
+
label={t("config.fields.mid", "Merchant ID (mid)")}
|
|
66
|
+
name="mid"
|
|
67
|
+
value={settings.mid}
|
|
68
|
+
onChange={(e) => onInputChange("mid", e.target.value)}
|
|
69
|
+
required
|
|
70
|
+
inputType="textInput"
|
|
71
|
+
tooltipContent={t("config.fields.midTooltip", "Your Payone merchant ID")}
|
|
72
|
+
/>
|
|
73
|
+
<RenderInput
|
|
74
|
+
label={t("config.fields.key", "Portal Key")}
|
|
75
|
+
name="key"
|
|
76
|
+
type="password"
|
|
77
|
+
value={settings.key}
|
|
78
|
+
onChange={(e) => onInputChange("key", e.target.value)}
|
|
79
|
+
required
|
|
80
|
+
inputType="textInput"
|
|
81
|
+
tooltipContent={t("config.fields.keyTooltip", "Your Payone portal key (will be encrypted)")}
|
|
82
|
+
/>
|
|
83
|
+
</Flex>
|
|
84
|
+
<Flex direction="row" gap={2}>
|
|
85
|
+
<RenderInput
|
|
86
|
+
label={t("config.fields.domainName", "Domain Name")}
|
|
87
|
+
name="domainName"
|
|
88
|
+
value={settings.domainName}
|
|
89
|
+
onChange={(e) => onInputChange("domainName", e.target.value)}
|
|
90
|
+
inputType="textInput"
|
|
91
|
+
tooltipContent={t("config.fields.domainNameTooltip", "Your Payone domain name")}
|
|
92
|
+
/>
|
|
93
|
+
<RenderInput
|
|
94
|
+
label={t("config.fields.displayName", "Display Name")}
|
|
95
|
+
name="displayName"
|
|
96
|
+
value={settings.displayName}
|
|
97
|
+
onChange={(e) => onInputChange("displayName", e.target.value)}
|
|
98
|
+
inputType="textInput"
|
|
99
|
+
tooltipContent={t("config.fields.displayNameTooltip", "Display name for payment methods (optional)")}
|
|
100
|
+
/>
|
|
101
|
+
</Flex>
|
|
102
|
+
<Flex direction="row" gap={2}>
|
|
103
|
+
<RenderInput
|
|
104
|
+
label={t("config.fields.mode", "Mode")}
|
|
105
|
+
name="mode"
|
|
106
|
+
value={settings.mode || "test"}
|
|
107
|
+
onChange={(e) => onInputChange("mode", e.target.value)}
|
|
108
|
+
required
|
|
109
|
+
inputType="select"
|
|
110
|
+
tooltipContent={t("config.fields.modeTooltip", "Select the API mode")}
|
|
111
|
+
options={[
|
|
112
|
+
{ value: "test", label: t("config.fields.modeTest", "Test") },
|
|
113
|
+
{ value: "live", label: t("config.fields.modeLive", "Live") },
|
|
114
|
+
]}
|
|
115
|
+
/>
|
|
116
|
+
<RenderInput
|
|
117
|
+
label={t("config.fields.enable3DSecure", "Enable 3D Secure")}
|
|
118
|
+
name="enable3DSecure"
|
|
119
|
+
value={settings.enable3DSecure ? "yes" : "no"}
|
|
120
|
+
onChange={(e) =>
|
|
121
|
+
onInputChange("enable3DSecure", e.target.value === "yes")
|
|
122
|
+
}
|
|
123
|
+
required
|
|
124
|
+
inputType="select"
|
|
125
|
+
tooltipContent={t("config.fields.enable3DSecureTooltip", "Enable 3D Secure authentication for credit card payments")}
|
|
126
|
+
options={[
|
|
127
|
+
{ value: "yes", label: t("config.fields.enabled", "Enabled") },
|
|
128
|
+
{ value: "no", label: t("config.fields.disabled", "Disabled") },
|
|
129
|
+
]}
|
|
130
|
+
/>
|
|
131
|
+
</Flex>
|
|
132
|
+
<Flex direction="row">
|
|
133
|
+
<RenderInput
|
|
134
|
+
label={t("config.fields.apiVersion", "API Version")}
|
|
135
|
+
name="api_version"
|
|
136
|
+
value={settings.api_version || "3.10"}
|
|
137
|
+
onChange={(e) => onInputChange("api_version", e.target.value)}
|
|
138
|
+
required
|
|
139
|
+
inputType="textInput"
|
|
140
|
+
tooltipContent={t("config.fields.apiVersionTooltip", "Payone API version")}
|
|
141
|
+
/>
|
|
142
|
+
</Flex>
|
|
142
143
|
</Flex>
|
|
143
144
|
|
|
144
|
-
<Flex direction="column" alignItems="stretch" gap={4} marginTop={6}>
|
|
145
|
-
<Typography variant="pi" textColor="neutral600" marginBottom={
|
|
145
|
+
<Flex direction="column" alignItems="stretch" height={"100%"} gap={4} marginTop={6}>
|
|
146
|
+
<Typography variant="pi" textColor="neutral600" marginBottom={8}>
|
|
146
147
|
{t("config.paymentMethods.title", "Enable or disable payment methods for your Payone integration")}
|
|
147
148
|
</Typography>
|
|
148
149
|
|
|
@@ -194,7 +195,7 @@ const ConfigurationFields = ({
|
|
|
194
195
|
labelStyle={{ fontSize: "16px" }}
|
|
195
196
|
tooltipContent={t("config.paymentMethods.applePayTooltip", "Enable or disable Apple Pay payments")}
|
|
196
197
|
/>
|
|
197
|
-
<RenderInput
|
|
198
|
+
{/* <RenderInput
|
|
198
199
|
label={t("config.paymentMethods.sofort", "Sofort Banking")}
|
|
199
200
|
name="enableSofort"
|
|
200
201
|
value={settings.enableSofort === true}
|
|
@@ -205,7 +206,7 @@ const ConfigurationFields = ({
|
|
|
205
206
|
labelDirection="row"
|
|
206
207
|
labelStyle={{ fontSize: "16px" }}
|
|
207
208
|
tooltipContent={t("config.paymentMethods.sofortTooltip", "Enable or disable Sofort Banking payments")}
|
|
208
|
-
/>
|
|
209
|
+
/> */}
|
|
209
210
|
<RenderInput
|
|
210
211
|
label={t("config.paymentMethods.sepa", "SEPA Direct Debit")}
|
|
211
212
|
name="enableSepaDirectDebit"
|
|
@@ -219,7 +220,7 @@ const ConfigurationFields = ({
|
|
|
219
220
|
tooltipContent={t("config.paymentMethods.sepaTooltip", "Enable or disable SEPA Direct Debit payments")}
|
|
220
221
|
/>
|
|
221
222
|
|
|
222
|
-
<Flex direction="row" gap={2}
|
|
223
|
+
<Flex direction="row" gap={2} style={{marginTop: "8rem"}}>
|
|
223
224
|
<Button
|
|
224
225
|
variant="secondary"
|
|
225
226
|
startIcon={<Cog />}
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
Checkbox,
|
|
8
8
|
SimpleMenu,
|
|
9
9
|
MenuItem,
|
|
10
|
+
Accordion,
|
|
10
11
|
} from "@strapi/design-system";
|
|
11
12
|
import { Table, Pagination } from "@strapi/strapi/admin";
|
|
12
13
|
import { ChevronDownIcon, ChevronUpIcon } from "../icons";
|
|
@@ -189,12 +190,21 @@ const TransactionTable = () => {
|
|
|
189
190
|
|
|
190
191
|
return (
|
|
191
192
|
<Flex direction="column" alignItems="stretch" gap={4} minHeight={"800px"}>
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
193
|
+
|
|
194
|
+
<Accordion.Root type="multiple">
|
|
195
|
+
<Accordion.Item value="filters">
|
|
196
|
+
<Accordion.Header>
|
|
197
|
+
<Accordion.Trigger>Filters</Accordion.Trigger>
|
|
198
|
+
</Accordion.Header>
|
|
199
|
+
<Accordion.Content style={{padding:"16px"}}>
|
|
200
|
+
<FiltersPanel
|
|
201
|
+
filters={filters}
|
|
202
|
+
handleFiltersChange={handleFiltersChange}
|
|
203
|
+
loadTransactionHistory={loadTransactionHistory}
|
|
204
|
+
/>
|
|
205
|
+
</Accordion.Content>
|
|
206
|
+
</Accordion.Item>
|
|
207
|
+
</Accordion.Root>
|
|
198
208
|
<Flex
|
|
199
209
|
justifyContent="flex-end"
|
|
200
210
|
gap={3}
|
|
@@ -211,24 +221,32 @@ const TransactionTable = () => {
|
|
|
211
221
|
{toggleableHeaders.map((header) => (
|
|
212
222
|
<MenuItem
|
|
213
223
|
key={header.name}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
224
|
+
onClick={(e) => {
|
|
225
|
+
e?.preventDefault?.();
|
|
226
|
+
toggleColumn(header.name);
|
|
227
|
+
}}
|
|
217
228
|
>
|
|
218
229
|
<Flex alignItems="center" gap={2}>
|
|
219
|
-
<
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
230
|
+
<span
|
|
231
|
+
onClick={(e) => {
|
|
232
|
+
e?.stopPropagation?.();
|
|
233
|
+
}}
|
|
234
|
+
>
|
|
235
|
+
<Checkbox
|
|
236
|
+
name={`column-${header.name}`}
|
|
237
|
+
checked={visibleColumns[header.name]}
|
|
238
|
+
onCheckedChange={() => toggleColumn(header.name)}
|
|
239
|
+
/>
|
|
240
|
+
</span>
|
|
224
241
|
<span>{header.label}</span>
|
|
225
242
|
</Flex>
|
|
226
243
|
</MenuItem>
|
|
227
244
|
))}
|
|
228
245
|
<MenuItem
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
246
|
+
onClick={(e) => {
|
|
247
|
+
e?.preventDefault?.();
|
|
248
|
+
showAllColumns();
|
|
249
|
+
}}
|
|
232
250
|
>
|
|
233
251
|
{t("table.showAllColumns", "Show all columns")}
|
|
234
252
|
</MenuItem>
|
|
@@ -11,6 +11,13 @@ const useSettings = () => {
|
|
|
11
11
|
key: "",
|
|
12
12
|
mode: "test",
|
|
13
13
|
api_version: "3.10",
|
|
14
|
+
serverApiMerchantId: "",
|
|
15
|
+
serverApiKeyId: "",
|
|
16
|
+
serverApiSecret: "",
|
|
17
|
+
serverApiVersionPath: "/v2",
|
|
18
|
+
defaultCountryCode: "DE",
|
|
19
|
+
defaultCurrencyCode: "EUR",
|
|
20
|
+
defaultLocale: "de_DE",
|
|
14
21
|
enable3DSecure: false,
|
|
15
22
|
enableCreditCard: false,
|
|
16
23
|
enablePayPal: false,
|
package/package.json
CHANGED
package/server/config/index.js
CHANGED
|
@@ -11,6 +11,19 @@ module.exports = {
|
|
|
11
11
|
key: "",
|
|
12
12
|
mode: "test",
|
|
13
13
|
api_version: "3.10",
|
|
14
|
+
// PAYONE Server API (Hosted Tokenization / Server-to-server)
|
|
15
|
+
// merchantId/PSPID used in REST endpoints: /v2/{merchantId}/...
|
|
16
|
+
serverApiMerchantId: "",
|
|
17
|
+
// API Key ID + Secret used for HMAC auth (GCS v1HMAC)
|
|
18
|
+
serverApiKeyId: "",
|
|
19
|
+
serverApiSecret: "",
|
|
20
|
+
// Keep configurable, default PAYONE REST version path
|
|
21
|
+
serverApiVersionPath: "/v2",
|
|
22
|
+
|
|
23
|
+
// Defaults (Germany)
|
|
24
|
+
defaultCountryCode: "DE",
|
|
25
|
+
defaultCurrencyCode: "EUR",
|
|
26
|
+
defaultLocale: "de_DE",
|
|
14
27
|
merchantName: "",
|
|
15
28
|
displayName: "",
|
|
16
29
|
domainName: "",
|
|
@@ -40,6 +53,14 @@ module.exports = {
|
|
|
40
53
|
.string()
|
|
41
54
|
.matches(/^\d+\.\d+$/)
|
|
42
55
|
.defined(),
|
|
56
|
+
serverApiMerchantId: yup.string().optional(),
|
|
57
|
+
serverApiKeyId: yup.string().optional(),
|
|
58
|
+
serverApiSecret: yup.string().optional(),
|
|
59
|
+
serverApiVersionPath: yup.string().optional(),
|
|
60
|
+
|
|
61
|
+
defaultCountryCode: yup.string().optional(),
|
|
62
|
+
defaultCurrencyCode: yup.string().optional(),
|
|
63
|
+
defaultLocale: yup.string().optional(),
|
|
43
64
|
merchantName: yup.string().optional(),
|
|
44
65
|
displayName: yup.string().optional(),
|
|
45
66
|
domainName: yup.string().optional(),
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
const crypto = require("crypto");
|
|
4
3
|
const PLUGIN_NAME = "strapi-plugin-payone-provider";
|
|
5
4
|
const { rowsToCsv, csvToRows, TRANSACTION_ATTRS } = require("../utils/csvTransactions");
|
|
6
5
|
|
|
@@ -8,6 +7,10 @@ const getPayoneService = (strapi) => {
|
|
|
8
7
|
return strapi.plugin(PLUGIN_NAME).service("payone");
|
|
9
8
|
};
|
|
10
9
|
|
|
10
|
+
const getNewHostedTokenizationService = (strapi) => {
|
|
11
|
+
return strapi.plugin(PLUGIN_NAME).service("newHostedTokenizationService");
|
|
12
|
+
};
|
|
13
|
+
|
|
11
14
|
const buildFiltersFromQuery = (rawFilters = {}) => {
|
|
12
15
|
const filters = {};
|
|
13
16
|
if (rawFilters && typeof rawFilters === "object") {
|
|
@@ -45,6 +48,9 @@ const hideKey = (settings) => {
|
|
|
45
48
|
if (settings && settings.key) {
|
|
46
49
|
settings.key = "***HIDDEN***";
|
|
47
50
|
}
|
|
51
|
+
if (settings && settings.serverApiSecret) {
|
|
52
|
+
settings.serverApiSecret = "***HIDDEN***";
|
|
53
|
+
}
|
|
48
54
|
return settings;
|
|
49
55
|
};
|
|
50
56
|
|
|
@@ -71,7 +77,6 @@ module.exports = ({ strapi }) => ({
|
|
|
71
77
|
displayName: settings?.displayName || null,
|
|
72
78
|
portalid: settings?.portalid || null,
|
|
73
79
|
accountId: settings?.aid || null,
|
|
74
|
-
portalKey: settings?.key || null,
|
|
75
80
|
paymentMethods: {
|
|
76
81
|
creditCard: settings?.enableCreditCard,
|
|
77
82
|
paypal: settings?.enablePayPal,
|
|
@@ -100,6 +105,9 @@ module.exports = ({ strapi }) => ({
|
|
|
100
105
|
if (bodyData.key === "***HIDDEN***" || !bodyData.key) {
|
|
101
106
|
bodyData.key = currentSettings?.key;
|
|
102
107
|
}
|
|
108
|
+
if (bodyData.serverApiSecret === "***HIDDEN***" || !bodyData.serverApiSecret) {
|
|
109
|
+
bodyData.serverApiSecret = currentSettings?.serverApiSecret;
|
|
110
|
+
}
|
|
103
111
|
|
|
104
112
|
const settings = await getPayoneService(strapi).updateSettings(bodyData);
|
|
105
113
|
ctx.body = { ...hideKey(settings) };
|
|
@@ -394,36 +402,17 @@ module.exports = ({ strapi }) => ({
|
|
|
394
402
|
ctx.type = "text/plain";
|
|
395
403
|
},
|
|
396
404
|
|
|
397
|
-
async
|
|
405
|
+
async hostedTokenizationJwt(ctx) {
|
|
398
406
|
try {
|
|
399
|
-
|
|
400
|
-
const settings = await getPayoneService(strapi).getSettings();
|
|
401
|
-
const hmacKey = settings?.key || "";
|
|
402
|
-
|
|
403
|
-
if (!hmacKey) {
|
|
404
|
-
ctx.throw(400, "Payone key is not configured in plugin settings");
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
// Validate required settings
|
|
408
|
-
if (!settings?.aid || !settings?.mid || !settings?.portalid || !settings?.mode) {
|
|
409
|
-
ctx.throw(400, "Required settings (aid, mid, portalid, mode) are not configured");
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
// Construct the string from settings values
|
|
413
|
-
// Format: ${aid}UTF-8${mid}${mode}${portalid}creditcardcheckJSONyes
|
|
414
|
-
const textToHash = `${settings.aid}UTF-8${settings.mid}${settings.mode}${settings.portalid}creditcardcheckJSONyes`;
|
|
415
|
-
|
|
416
|
-
// Create HMAC SHA-384 hash
|
|
417
|
-
const hmac = crypto.createHmac("sha384", hmacKey);
|
|
418
|
-
hmac.update(textToHash);
|
|
419
|
-
const hash = hmac.digest("hex");
|
|
420
|
-
|
|
407
|
+
const result = await getNewHostedTokenizationService(strapi).createHostedTokenizationJwt();
|
|
421
408
|
ctx.body = {
|
|
422
|
-
|
|
423
|
-
|
|
409
|
+
data: {
|
|
410
|
+
token: result?.token || null,
|
|
411
|
+
expirationDate: result?.expirationDate || null,
|
|
412
|
+
},
|
|
424
413
|
};
|
|
425
414
|
} catch (error) {
|
|
426
415
|
handleError(ctx, error);
|
|
427
416
|
}
|
|
428
|
-
}
|
|
417
|
+
},
|
|
429
418
|
});
|
package/server/routes/index.js
CHANGED
|
@@ -100,14 +100,7 @@ module.exports = {
|
|
|
100
100
|
policies: ["admin::isAuthenticatedAdmin"]
|
|
101
101
|
}
|
|
102
102
|
},
|
|
103
|
-
|
|
104
|
-
method: "POST",
|
|
105
|
-
path: "/hash384",
|
|
106
|
-
handler: "payone.hash384",
|
|
107
|
-
config: {
|
|
108
|
-
policies: ["admin::isAuthenticatedAdmin"]
|
|
109
|
-
}
|
|
110
|
-
}
|
|
103
|
+
// legacy hosted-iFrame endpoints removed
|
|
111
104
|
]
|
|
112
105
|
},
|
|
113
106
|
|
|
@@ -188,8 +181,8 @@ module.exports = {
|
|
|
188
181
|
},
|
|
189
182
|
{
|
|
190
183
|
method: "POST",
|
|
191
|
-
path: "/
|
|
192
|
-
handler: "payone.
|
|
184
|
+
path: "/hosted-tokenization/jwt",
|
|
185
|
+
handler: "payone.hostedTokenizationJwt",
|
|
193
186
|
config: {
|
|
194
187
|
policies: ["plugin::strapi-plugin-payone-provider.is-auth"],
|
|
195
188
|
auth: false
|
package/server/services/index.js
CHANGED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const axios = require("axios");
|
|
4
|
+
const crypto = require("crypto");
|
|
5
|
+
const settingsService = require("./settingsService");
|
|
6
|
+
|
|
7
|
+
const PAYONE_POST_GATEWAY_URL = "https://api.pay1.de/post-gateway/";
|
|
8
|
+
|
|
9
|
+
function sha384HexLower(value) {
|
|
10
|
+
return crypto.createHash("sha384").update(String(value), "utf8").digest("hex").toLowerCase();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function portalKeyToJwtKey(portalKeyOrHash) {
|
|
14
|
+
const key = String(portalKeyOrHash || "").trim();
|
|
15
|
+
if (/^[0-9a-f]{96}$/i.test(key)) return key.toLowerCase();
|
|
16
|
+
return sha384HexLower(key);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async function getSettingsOrThrow(strapi) {
|
|
20
|
+
const settings = await settingsService.getSettings(strapi);
|
|
21
|
+
if (!settings) {
|
|
22
|
+
const err = new Error("PAYONE plugin settings missing");
|
|
23
|
+
err.status = 400;
|
|
24
|
+
throw err;
|
|
25
|
+
}
|
|
26
|
+
return settings;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function createHostedTokenizationJwt(strapi) {
|
|
30
|
+
const settings = await getSettingsOrThrow(strapi);
|
|
31
|
+
|
|
32
|
+
const { mid, portalid, key } = settings;
|
|
33
|
+
if (!mid || !portalid || !key) {
|
|
34
|
+
const err = new Error("Missing required settings for getJWT (mid, portalid, key)");
|
|
35
|
+
err.status = 400;
|
|
36
|
+
throw err;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const form = new URLSearchParams();
|
|
40
|
+
form.append("request", "getJWT");
|
|
41
|
+
form.append("mid", String(mid));
|
|
42
|
+
form.append("portalid", String(portalid));
|
|
43
|
+
form.append("key", portalKeyToJwtKey(key));
|
|
44
|
+
|
|
45
|
+
const response = await axios.post(PAYONE_POST_GATEWAY_URL, form.toString(), {
|
|
46
|
+
headers: {
|
|
47
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
48
|
+
Accept: "application/json",
|
|
49
|
+
},
|
|
50
|
+
timeout: 30000,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return response.data;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
module.exports = ({ strapi }) => ({
|
|
57
|
+
createHostedTokenizationJwt: async () => createHostedTokenizationJwt(strapi),
|
|
58
|
+
});
|
|
59
|
+
|
|
@@ -35,7 +35,18 @@ const updateSettings = async (strapi, settings) => {
|
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
const validateSettings = (settings) => {
|
|
38
|
-
|
|
38
|
+
// Legacy post-gateway (PAY1): requires aid/portalid/key
|
|
39
|
+
const hasPostGateway = !!(settings && settings.aid && settings.portalid && settings.key);
|
|
40
|
+
|
|
41
|
+
// PAYONE Server API (Hosted Tokenization / REST): requires merchantId + apiKeyId + apiSecret
|
|
42
|
+
const hasServerApi = !!(
|
|
43
|
+
settings &&
|
|
44
|
+
(settings.serverApiMerchantId || settings.mid) &&
|
|
45
|
+
settings.serverApiKeyId &&
|
|
46
|
+
settings.serverApiSecret
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
return hasPostGateway || hasServerApi;
|
|
39
50
|
};
|
|
40
51
|
|
|
41
52
|
module.exports = {
|
package/server/utils/sanitize.js
CHANGED
|
@@ -14,7 +14,20 @@ const SENSITIVE_KEYS = [
|
|
|
14
14
|
"accessname",
|
|
15
15
|
"token",
|
|
16
16
|
"redirecturl",
|
|
17
|
-
"Identifier"
|
|
17
|
+
"Identifier",
|
|
18
|
+
"pseudocardpan",
|
|
19
|
+
"aid",
|
|
20
|
+
"mid",
|
|
21
|
+
"portalid",
|
|
22
|
+
"portalId",
|
|
23
|
+
"creditcardtoken",
|
|
24
|
+
"creditcardtokenid",
|
|
25
|
+
"creditcardtokenvalue",
|
|
26
|
+
"creditcardtokentype",
|
|
27
|
+
"creditcardtokenexpiry",
|
|
28
|
+
"creditcardtokencvv",
|
|
29
|
+
"creditcardtokenholder",
|
|
30
|
+
"creditcardtokenbank",
|
|
18
31
|
];
|
|
19
32
|
|
|
20
33
|
const maskValue = (val) => {
|