payment-kit 1.18.4 → 1.18.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.
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import env from '@blocklet/sdk/lib/env';
|
|
4
4
|
|
|
5
|
+
import Stripe from 'stripe';
|
|
5
6
|
import logger from '../../libs/logger';
|
|
6
7
|
import { STRIPE_API_VERSION, STRIPE_ENDPOINT, STRIPE_EVENTS } from '../../libs/util';
|
|
7
8
|
import { PaymentMethod } from '../../store/models';
|
|
@@ -48,3 +49,29 @@ export async function ensureWebhookRegistered() {
|
|
|
48
49
|
}
|
|
49
50
|
}
|
|
50
51
|
}
|
|
52
|
+
|
|
53
|
+
// validate stripe keys
|
|
54
|
+
export async function validateStripeKeys(secretKey: string) {
|
|
55
|
+
try {
|
|
56
|
+
const stripe = new Stripe(secretKey, { apiVersion: STRIPE_API_VERSION });
|
|
57
|
+
await stripe.accounts.retrieve();
|
|
58
|
+
return true;
|
|
59
|
+
} catch (error) {
|
|
60
|
+
logger.error('Invalid Stripe API keys:', error);
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// cleanup old stripe webhook
|
|
66
|
+
export async function cleanupStripeWebhook(stripe: Stripe) {
|
|
67
|
+
try {
|
|
68
|
+
const { data } = await stripe.webhookEndpoints.list({ limit: 100 });
|
|
69
|
+
const existingWebhook = data.find((webhook) => webhook.metadata?.appPid === env.appPid);
|
|
70
|
+
if (existingWebhook) {
|
|
71
|
+
await stripe.webhookEndpoints.del(existingWebhook.id);
|
|
72
|
+
logger.info('stripe webhook deleted', { id: existingWebhook.id });
|
|
73
|
+
}
|
|
74
|
+
} catch (err) {
|
|
75
|
+
logger.error('Failed to clean old webhook:', err);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -7,7 +7,7 @@ import { InferAttributes, Op, WhereOptions } from 'sequelize';
|
|
|
7
7
|
import cloneDeep from 'lodash/cloneDeep';
|
|
8
8
|
import merge from 'lodash/merge';
|
|
9
9
|
import { Joi } from '@arcblock/validator';
|
|
10
|
-
import { ensureWebhookRegistered } from '../integrations/stripe/setup';
|
|
10
|
+
import { ensureWebhookRegistered, cleanupStripeWebhook, validateStripeKeys } from '../integrations/stripe/setup';
|
|
11
11
|
import logger from '../libs/logger';
|
|
12
12
|
import { authenticate } from '../libs/security';
|
|
13
13
|
import { PaymentCurrency } from '../store/models/payment-currency';
|
|
@@ -51,6 +51,10 @@ router.post('/', auth, async (req, res) => {
|
|
|
51
51
|
if (!raw.settings.stripe?.secret_key) {
|
|
52
52
|
return res.status(400).json({ error: 'stripe secret key is required' });
|
|
53
53
|
}
|
|
54
|
+
const isValid = await validateStripeKeys(raw.settings.stripe.secret_key);
|
|
55
|
+
if (!isValid) {
|
|
56
|
+
return res.status(400).json({ error: 'Invalid Stripe API keys' });
|
|
57
|
+
}
|
|
54
58
|
|
|
55
59
|
raw.settings = pick(PaymentMethod.encryptSettings(raw.settings), ['stripe']) as PaymentMethodSettings;
|
|
56
60
|
raw.logo = getUrl('/methods/stripe.png');
|
|
@@ -295,7 +299,7 @@ router.put('/:id', auth, async (req, res) => {
|
|
|
295
299
|
if ('logo' in method.dataValues || raw.logo !== undefined) {
|
|
296
300
|
updateData.logo = raw.logo ?? method.logo;
|
|
297
301
|
}
|
|
298
|
-
|
|
302
|
+
let updateSettings = 'settings' in req.body ? req.body.settings : null;
|
|
299
303
|
if (EVM_CHAIN_TYPES.includes(method.type as string) && updateSettings) {
|
|
300
304
|
const paymentType = method.type as EVMChainType;
|
|
301
305
|
if (!updateSettings[paymentType]?.api_host) {
|
|
@@ -322,7 +326,29 @@ router.put('/:id', auth, async (req, res) => {
|
|
|
322
326
|
}
|
|
323
327
|
updateData.settings = pick(PaymentMethod.encryptSettings(updateSettings), [paymentType]) as PaymentMethodSettings;
|
|
324
328
|
}
|
|
329
|
+
if (method.type === 'stripe') {
|
|
330
|
+
if (!updateSettings.stripe?.publishable_key) {
|
|
331
|
+
return res.status(400).json({ error: 'stripe publishable key is required' });
|
|
332
|
+
}
|
|
333
|
+
if (!updateSettings.stripe?.secret_key) {
|
|
334
|
+
return res.status(400).json({ error: 'stripe secret key is required' });
|
|
335
|
+
}
|
|
336
|
+
if (method.settings?.stripe?.secret_key !== updateSettings.stripe.secret_key) {
|
|
337
|
+
const isValid = await validateStripeKeys(updateSettings.stripe.secret_key);
|
|
338
|
+
if (!isValid) {
|
|
339
|
+
return res.status(400).json({ error: 'Invalid Stripe API keys' });
|
|
340
|
+
}
|
|
341
|
+
updateSettings.stripe.webhook_signing_secret = null;
|
|
342
|
+
updateSettings = PaymentMethod.encryptSettings(updateSettings);
|
|
343
|
+
cleanupStripeWebhook(method.getStripeClient());
|
|
344
|
+
}
|
|
345
|
+
updateData.settings = pick(updateSettings, ['stripe']) as PaymentMethodSettings;
|
|
346
|
+
}
|
|
347
|
+
|
|
325
348
|
const updatedMethod = await method.update(updateData);
|
|
349
|
+
if (method.type === 'stripe') {
|
|
350
|
+
ensureWebhookRegistered().catch(console.error);
|
|
351
|
+
}
|
|
326
352
|
return res.json(updatedMethod);
|
|
327
353
|
} catch (err) {
|
|
328
354
|
return res.status(400).json({ error: err.message });
|
|
@@ -175,15 +175,21 @@ export class PaymentMethod extends Model<InferAttributes<PaymentMethod>, InferCr
|
|
|
175
175
|
throw new Error('payment method config insufficient for stripe');
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
-
|
|
179
|
-
|
|
178
|
+
const { secret_key: secretKey } = PaymentMethod.decryptSettings(this.settings).stripe || {};
|
|
179
|
+
if (!secretKey) {
|
|
180
|
+
throw new Error('stripe secret key is required');
|
|
180
181
|
}
|
|
182
|
+
const clientKey = `${this.id}:${secretKey}`;
|
|
183
|
+
const existingClient = stripeClients.get(clientKey) as Stripe;
|
|
181
184
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
stripeClients.set(this.id, client);
|
|
185
|
+
if (existingClient) {
|
|
186
|
+
return existingClient;
|
|
187
|
+
}
|
|
186
188
|
|
|
189
|
+
try {
|
|
190
|
+
stripeClients.delete(this.id);
|
|
191
|
+
const client = new Stripe(secretKey, { apiVersion: STRIPE_API_VERSION });
|
|
192
|
+
stripeClients.set(clientKey, client);
|
|
187
193
|
return client as Stripe;
|
|
188
194
|
} catch (e) {
|
|
189
195
|
return {} as Stripe;
|
package/blocklet.yml
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payment-kit",
|
|
3
|
-
"version": "1.18.
|
|
3
|
+
"version": "1.18.5",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "blocklet dev --open",
|
|
6
6
|
"eject": "vite eject",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"@arcblock/validator": "^1.19.9",
|
|
54
54
|
"@blocklet/js-sdk": "^1.16.38",
|
|
55
55
|
"@blocklet/logger": "^1.16.38",
|
|
56
|
-
"@blocklet/payment-react": "1.18.
|
|
56
|
+
"@blocklet/payment-react": "1.18.5",
|
|
57
57
|
"@blocklet/sdk": "^1.16.38",
|
|
58
58
|
"@blocklet/ui-react": "^2.11.34",
|
|
59
59
|
"@blocklet/uploader": "^0.1.66",
|
|
@@ -121,7 +121,7 @@
|
|
|
121
121
|
"devDependencies": {
|
|
122
122
|
"@abtnode/types": "^1.16.38",
|
|
123
123
|
"@arcblock/eslint-config-ts": "^0.3.3",
|
|
124
|
-
"@blocklet/payment-types": "1.18.
|
|
124
|
+
"@blocklet/payment-types": "1.18.5",
|
|
125
125
|
"@types/cookie-parser": "^1.4.7",
|
|
126
126
|
"@types/cors": "^2.8.17",
|
|
127
127
|
"@types/debug": "^4.1.12",
|
|
@@ -167,5 +167,5 @@
|
|
|
167
167
|
"parser": "typescript"
|
|
168
168
|
}
|
|
169
169
|
},
|
|
170
|
-
"gitHead": "
|
|
170
|
+
"gitHead": "83cca0f1ac5814964c8bedd04f34a3a2a986f554"
|
|
171
171
|
}
|
|
@@ -73,6 +73,9 @@ export default function PaymentMethodEdit({ onClose, value }: { onClose: () => v
|
|
|
73
73
|
'settings.base.explorer_host',
|
|
74
74
|
'settings.ethereum.api_host',
|
|
75
75
|
'settings.ethereum.explorer_host',
|
|
76
|
+
'settings.stripe.publishable_key',
|
|
77
|
+
'settings.stripe.secret_key',
|
|
78
|
+
'settings.stripe.dashboard',
|
|
76
79
|
]}
|
|
77
80
|
/>
|
|
78
81
|
</FormProvider>
|