
require('dotenv').config(); const express = require('express...
Prompt
require('dotenv').config(); const express = require('express'); const crypto = require('crypto'); const path = require('path'); const fs = require('fs'); const jwt = require('jsonwebtoken'); const app = express(); const PORT = process.env.PORT || 3000; const CONFIG = { MERCHANT_BASE_URL: process.env.MERCHANT_BASE_URL || `http://localhost:${PORT}`, SIMPLEPAY_MERCHANT_KEY: process.env.SIMPLEPAY_MERCHANT_KEY || 'SECRET_MERCHANT_KEY_DEV_MOCK_384', SIMPLEPAY_RSA_PUBLIC_KEY: process.env.SIMPLEPAY_RSA_PUBLIC_KEY || null, PISP_CLIENT_ID: process.env.PISP_CLIENT_ID || null, PISP_CLIENT_SECRET: process.env.PISP_CLIENT_SECRET || null, PISP_TOKEN_ENDPOINT: process.env.PISP_TOKEN_ENDPOINT || null, PISP_AUTH_ENDPOINT: process.env.PISP_AUTH_ENDPOINT || null, PISP_PRIVATE_KEY: process.env.PISP_PRIVATE_KEY || null, PISP_CERT_KID: process.env.PISP_CERT_KID || 'cert-key-1', INTERNAL_HMAC_SECRET: process.env.INTERNAL_HMAC_SECRET || '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef', RECIPIENT_NAME: 'ZoltĆ”n Dalma', RECIPIENT_BBAN: '12600016-15886169-33547130', RECIPIENT_IBAN: 'HU05126000161588616933547130', RECIPIENT_BIC: 'TRWIBEBB', ALLOWED_AMOUNTS: [3000, 5000, 8000, 25000] }; app.use(express.json({ verify: (req, res, buf) => { req.rawBuffer = buf; } })); app.use((req, res, next) => { res.setHeader('X-Content-Type-Options', 'nosniff'); res.setHeader('X-Frame-Options', 'DENY'); res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin'); next(); }); const nonceCache = new Map(); setInterval(() => { const now = Date.now(); for (const [nonce, timestamp] of nonceCache.entries()) { if (now - timestamp > 300000) { nonceCache.delete(nonce); } } }, 60000); function buildMnbTransferString(name, iban, bic, amount, reference) { return [ 'HCT', '001', '1', bic || 'TRWIBEBB', name, '', iban.replace(/\s+/g, ''), `HUF${amount}`, '', '', reference.substring(0, 70), '' ].join('\n'); } function generateSimplePayLinks(amount, packageTitle, packageName) { const mnbPayload = buildMnbTransferString(CONFIG.RECIPIENT_NAME, CONFIG.RECIPIENT_IBAN, CONFIG.RECIPIENT_BIC, amount, packageTitle); let encryptedQrBase64 = ''; if (CONFIG.SIMPLEPAY_RSA_PUBLIC_KEY) { try { const buffer = Buffer.from(mnbPayload, 'utf8'); const encrypted = crypto.publicEncrypt( { key: CONFIG.SIMPLEPAY_RSA_PUBLIC_KEY, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, oaepHash: 'sha256' }, buffer ); encryptedQrBase64 = encrypted.toString('base64'); } catch (e) { encryptedQrBase64 = Buffer.from(mnbPayload, 'utf8').toString('base64'); } } else { encryptedQrBase64 = Buffer.from(mnbPayload, 'utf8').toString('base64'); } const callbackUrl = `${CONFIG.MERCHANT_BASE_URL}/api/payment/callback?status=success&pkg=${encodeURIComponent(packageName)}`; const outerPayload = { qrcode: encryptedQrBase64, webLink: callbackUrl }; const base64Outer = Buffer.from(JSON.stringify(outerPayload)) .toString('base64') .replace(/\+/g, '-') .replace(/\//g, '_') .replace(/=+$/, ''); const escapedMessage = JSON.stringify(outerPayload).replace(/\//g, '\\/'); const simplePayHmac = crypto .createHmac('sha384', CONFIG.SIMPLEPAY_MERCHANT_KEY) .update(escapedMessage) .digest('base64'); return { android: `https://www.deeplink.simplepay.hu/mobilebank/wire/${base64Outer}`, ios: `https://www.deeplink.simplepay.hu/mobilebank/wire/otp/${base64Outer}`, base64Outer: base64Outer, signature: simplePayHmac }; } function buildPispUrls(amount, packageTitle) { if (!CONFIG.PISP_CLIENT_ID || !CONFIG.PISP_AUTH_ENDPOINT || !CONFIG.PISP_PRIVATE_KEY) { return { androidAuthUrl: null, iosAuthUrl: null }; } try { const state = crypto.randomBytes(32).toString('hex'); const nonce = crypto.randomBytes(32).toString('hex'); const now = Math.floor(Date.now() / 1000); const consentId = 'CONSENT-' + crypto.randomUUID(); const jwtPayload = { iss: CONFIG.PISP_CLIENT_ID, aud: CONFIG.PISP_AUTH_ENDPOINT, response_type: 'code id_token', client_id: CONFIG.PISP_CLIENT_ID, redirect_uri: `${CONFIG.MERCHANT_BASE_URL}/api/payment/callback`, scope: 'openid payments', state: state, nonce: nonce, nbf: now, exp: now + 300, claims: { id_token: { openbanking_intent_id: { value: consentId, essential: true } } } }; const signedJWT = jwt.sign(jwtPayload, CONFIG.PISP_PRIVATE_KEY, { algorithm: 'RS256', header: { kid: CONFIG.PISP_CERT_KID, alg: 'RS256', typ: 'JWT' } }); const authUrl = `${CONFIG.PISP_AUTH_ENDPOINT}?` + new URLSearchParams({ client_id: CONFIG.PISP_CLIENT_ID, response_type: 'code id_token', scope: 'openid payments', redirect_uri: `${CONFIG.MERCHANT_BASE_URL}/api/payment/callback`, state: state, request: signedJWT }).toString(); return { androidAuthUrl: authUrl, iosAuthUrl: authUrl }; } catch (e) { return { androidAuthUrl: null, iosAuthUrl: null }; } } app.post('/api/create-payment-intent', (req, res) => { const nonce = req.headers['x-nonce']; const timestamp = req.headers['x-timestamp']; if (nonce) { if (nonceCache.has(nonce)) { return res.status(409).json({ error: 'Duplicate nonce' }); } nonceCache.set(nonce, Date.now()); } if (timestamp) { const timeDiff = Math.abs(Date.now() / 1000 - Number(timestamp)); if (timeDiff > 300) { return res.status(400).json({ error: 'Expired timestamp' }); } } const { amount, packageName, packageTitle } = req.body; const numAmount = parseInt(amount, 10); if (!CONFIG.ALLOWED_AMOUNTS.includes(numAmount)) { return res.status(400).json({ error: 'Invalid payment amount' }); } const validatedTitle = (packageTitle || 'ĆtutalĆ”s').substring(0, 70); const validatedName = (packageName || 'csomag').substring(0, 32); const simplePay = generateSimplePayLinks(numAmount, validatedTitle, validatedName); const pisp = buildPispUrls(numAmount, validatedTitle); const androidIntent = `intent://mobilebank/wire/${simplePay.base64Outer}#Intent;scheme=simplepay;package=hu.otpbank.mobile;S.browser_fallback_url=${encodeURIComponent(CONFIG.MERCHANT_BASE_URL + '/?fallback=manual')};end;`; const paytoUri = `payto://iban/${CONFIG.RECIPIENT_IBAN}?amount=HUF:${numAmount}&receiver-name=${encodeURIComponent(CONFIG.RECIPIENT_NAME)}&message=${encodeURIComponent(validatedTitle)}`; const responseData = { iosDeepLink: simplePay.ios, androidDeepLink: simplePay.android, androidIntent: androidIntent, pisp: pisp, paytoUri: paytoUri, recipientName: CONFIG.RECIPIENT_NAME, recipientIban: CONFIG.RECIPIENT_IBAN, recipientBban: CONFIG.RECIPIENT_BBAN, recipientBic: CONFIG.RECIPIENT_BIC, amount: numAmount, currency: 'HUF', reference: validatedTitle, expiresAt: new Date(Date.now() + 600000).toISOString() }; const responseString = JSON.stringify(responseData); const responseSignature = crypto .createHmac('sha256', CONFIG.INTERNAL_HMAC_SECRET) .update(responseString) .digest('hex'); res.setHeader('X-Response-Signature', responseSignature); return res.json(responseData); }); app.get('/api/payment-intents-bootstrap', (req, res) => { const packages = [ { amount: 3000, title: 'Kis csomag (30 mini videó)', name: 'kis-csomag' }, { amount: 5000, title: 'Kis csomag+', name: 'kis-csomag-plus' }, { amount: 8000, title: 'Nagy csomag', name: 'nagy-csomag' }, { amount: 25000, title: 'IdÅpont foglalĆ”s', name: 'idopont' } ]; const bundle = {}; for (const pkg of packages) { const simplePay = generateSimplePayLinks(pkg.amount, pkg.title, pkg.name); const pisp = buildPispUrls(pkg.amount, pkg.title); bundle[pkg.amount] = { iosDeepLink: simplePay.ios, androidDeepLink: simplePay.android, androidIntent: `intent://mobilebank/wire/${simplePay.base64Outer}#Intent;scheme=simplepay;package=hu.otpbank.mobile;S.browser_fallback_url=${encodeURIComponent(CONFIG.MERCHANT_BASE_URL + '/?fallback=manual')};end;`, pisp: pisp, paytoUri: `payto://iban/${CONFIG.RECIPIENT_IBAN}?amount=HUF:${pkg.amount}&receiver-name=${encodeURIComponent(CONFIG.RECIPIENT_NAME)}&message=${encodeURIComponent(pkg.title)}`, recipientName: CONFIG.RECIPIENT_NAME, recipientIban: CONFIG.RECIPIENT_IBAN, recipientBban: CONFIG.RECIPIENT_BBAN, recipientBic: CONFIG.RECIPIENT_BIC, amount: pkg.amount, currency: 'HUF', reference: pkg.title }; } res.json(bundle); }); app.get('/api/payment/callback', (req, res) => { res.send(`<!DOCTYPE html> <html lang="hu"> <head> <meta charset="utf-8"> <title>FizetĆ©s JóvĆ”hagyva</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> body{background:#000;color:#00d4ff;font-family:sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;text-align:center;} .card{background:rgba(255,255,255,0.05);padding:2rem;border-radius:20px;border:1px solid rgba(0,212,255,0.3);} h1{color:#fff;margin-bottom:0.5rem;} a{color:#00d4ff;text-decoration:none;font-weight:bold;border:1px solid #00d4ff;padding:10px 20px;border-radius:12px;display:inline-block;margin-top:1rem;} </style> </head> <body> <div class="card"> <h1>ĆtutalĆ”s feldolgozĆ”s alatt</h1> <p>Az AFR rendszer mĆ”sodperceken belül jóvĆ”Ćrja az ƶsszeget.</p> <a href="/">Vissza a fÅoldalra</a> </div> </body> </html>`); }); app.post('/api/webhook/payment-result', (req, res) => { res.json({ status: 'SUCCESS', receiveDate: new Date().toISOString() }); }); app.get('/.well-known/apple-app-site-association', (req, res) => { res.setHeader('Content-Type', 'application/json'); res.json({ applinks: { apps: [], details: [ { appIDs: ['TEAMID.hu.zsebibabakutya.app'], components: [{ '/': '/api/payment/callback*' }, { '/': '/payment/*' }] } ] } }); }); app.get('/.well-known/assetlinks.json', (req, res) => { res.setHeader('Content-Type', 'application/json'); res.json([ { relation: ['delegate_permission/common.handle_all_urls'], target: { namespace: 'android_app', package_name: 'hu.zsebibabakutya.app', sha256_cert_fingerprints: [ 'AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99' ] } } ]); }); app.get('/', (req, res) => { res.sendFile(path.join(__dirname, 'index.html')); }); app.use(express.static(path.join(__dirname))); app.listen(PORT, () => {}); Send back the complete code with all the fixes. Fix each of the listed errors one by one, making sure to actually correct them so that there are 0 errors remaining. Keep the original imports, since the files exist. Write out every single character; do not abbreviate anything. Fix every error. There must be exactly one file. Do not write anything else; just output the complete code, and it must not contain any comments. Never, under any circumstances, use simplified, substitute, dummy, simulated, or fake code. Write the entire file as complete, unabridged, production-ready code in a single code block. It must be 100% error-free, a complete, error-free file, and must be submitted as a downloadable file. These requirements are mandatory and must be strictly adhered to. If no list of errors is provided, you must find all the errors and fix them. If there were comments in the original code, delete them. And most importantly: YOU MUST NEVER SIMPLIFY!
A system prompt was added to support web rendering
Response not available