@unchainedshop/plugins
Version:
Official plugin collection for the Unchained Engine with payment, delivery, and pricing adapters
65 lines (64 loc) • 2.51 kB
JavaScript
import { createLogger } from '@unchainedshop/logger';
import { timingSafeStringEqual } from '@unchainedshop/utils';
import { buildSignature } from "./buildSignature.js";
const logger = createLogger('unchained:saferpay');
export async function saferpayWebhookHandler(request, context) {
try {
const { modules, services } = context;
const url = new URL(request.url);
const orderPaymentId = url.searchParams.get('orderPaymentId');
const signature = url.searchParams.get('signature');
const transactionId = url.searchParams.get('transactionId');
const isValidRequest = typeof orderPaymentId === 'string' &&
typeof signature === 'string' &&
typeof transactionId === 'string' &&
orderPaymentId &&
transactionId &&
signature;
if (!isValidRequest) {
logger.warn('Missing required query parameters');
return new Response(null, { status: 404 });
}
logger.info(`Checkout with orderPaymentId: ${orderPaymentId}`);
const orderPayment = await modules.orders.payments.findOrderPayment({
orderPaymentId,
});
if (!orderPayment) {
throw new Error(`Order payment not found with orderPaymentId: ${orderPaymentId}`);
}
const correctSignature = await buildSignature(transactionId, orderPaymentId);
if (!(await timingSafeStringEqual(correctSignature, signature))) {
throw new Error('Invalid signature');
}
const order = await services.orders.checkoutOrder(orderPayment.orderId, {
paymentContext: {
transactionId,
},
});
if (!order) {
throw new Error(`Order with id ${orderPayment.orderId} not found`);
}
logger.info('Checkout successful', {
orderPaymentId,
orderId: order._id,
});
return new Response(JSON.stringify({
message: 'checkout successful',
orderPaymentId,
orderId: order._id,
}), {
status: 200,
headers: { 'Content-Type': 'application/json' },
});
}
catch (error) {
logger.error('Saferpay webhook error:', error);
return new Response(JSON.stringify({
message: error.message,
name: error.name,
}), {
status: 500,
headers: { 'Content-Type': 'application/json' },
});
}
}