UNPKG

shora-ai-payment-sdk

Version:

The first open-source payment SDK designed specifically for AI agents and chatbots - ACP Compatible

190 lines (189 loc) 8.15 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.SecurityEnhancement = void 0; exports.createSecurityEnhancement = createSecurityEnhancement; exports.generateEncryptionKey = generateEncryptionKey; const crypto_js_1 = __importDefault(require("crypto-js")); const axios_1 = __importDefault(require("axios")); const pkg = require('../package.json'); class SecurityEnhancement { constructor(config) { this.auditLogs = []; this.requestContext = null; this.config = { pbkdf2Iterations: 100000, ...config }; } setRequestContext(ctx) { this.requestContext = ctx; } getClientIP() { return this.requestContext?.ip || '127.0.0.1'; } getUserAgent() { const sdkVersion = this.config.sdkVersion || pkg.version || 'unknown'; return this.requestContext?.userAgent || `ShoraAI-PaymentSDK/${sdkVersion}`; } encryptToken(token, additionalData) { const salt = crypto_js_1.default.lib.WordArray.random(256 / 8); const iv = crypto_js_1.default.lib.WordArray.random(128 / 8); const iterations = this.config.pbkdf2Iterations || 100000; const key = crypto_js_1.default.PBKDF2(this.config.encryptionKey, salt, { keySize: 256 / 32, iterations, hasher: crypto_js_1.default.algo.SHA256, }); const payload = { token, tenantId: this.config.tenantId, ts: Date.now(), }; if (additionalData !== undefined) { payload.additionalData = additionalData || null; } const encrypted = crypto_js_1.default.AES.encrypt(JSON.stringify(payload), key, { iv, mode: crypto_js_1.default.mode.CBC, padding: crypto_js_1.default.pad.Pkcs7, }); return { encrypted: encrypted.toString(), iv: iv.toString(crypto_js_1.default.enc.Hex), salt: salt.toString(crypto_js_1.default.enc.Hex), timestamp: Date.now(), }; } decryptToken(encryptedToken) { try { const salt = crypto_js_1.default.enc.Hex.parse(encryptedToken.salt); const iv = crypto_js_1.default.enc.Hex.parse(encryptedToken.iv); const iterations = this.config.pbkdf2Iterations || 100000; const key = crypto_js_1.default.PBKDF2(this.config.encryptionKey, salt, { keySize: 256 / 32, iterations, hasher: crypto_js_1.default.algo.SHA256, }); const decrypted = crypto_js_1.default.AES.decrypt(encryptedToken.encrypted, key, { iv, mode: crypto_js_1.default.mode.CBC, padding: crypto_js_1.default.pad.Pkcs7, }); const decryptedString = decrypted.toString(crypto_js_1.default.enc.Utf8); if (!decryptedString) { this.logAudit('decrypt_failed', 'Token decryption failed - invalid data'); return null; } const payload = JSON.parse(decryptedString); if (!payload || payload.tenantId !== this.config.tenantId) { this.logAudit('decrypt_failed', 'Token decryption failed - tenant mismatch'); return null; } this.logAudit('decrypt_success', 'Token decrypted successfully'); return payload.token; } catch (error) { this.logAudit('decrypt_error', 'Token decryption error: ' + String(error)); return null; } } logAudit(action, details, transactionId, userId, agentId, amount, currency, status = 'success', metadata) { if (!this.config.enableAuditLogging) return; const auditEntry = { timestamp: new Date().toISOString(), tenantId: this.config.tenantId, transactionId, action, userId, agentId, amount, currency, status, metadata: { ...metadata, details, sdkVersion: this.config.sdkVersion || pkg.version || 'unknown', pbkdf2Iterations: this.config.pbkdf2Iterations || 100000, environment: process.env.NODE_ENV || 'production', }, ipAddress: this.getClientIP(), userAgent: this.getUserAgent(), }; this.auditLogs.push(auditEntry); if (this.config.auditLogEndpoint) { this.sendAuditLog(auditEntry).catch((error) => { console.warn('sendAuditLog failed', error); }); } } getAuditLogs(startDate, endDate, action) { let filtered = this.auditLogs.filter((log) => log.tenantId === this.config.tenantId); if (startDate) { const start = new Date(startDate).getTime(); filtered = filtered.filter((log) => new Date(log.timestamp).getTime() >= start); } if (endDate) { const end = new Date(endDate).getTime(); filtered = filtered.filter((log) => new Date(log.timestamp).getTime() <= end); } if (action) { filtered = filtered.filter((log) => log.action === action); } return filtered.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()); } async sendAuditLog(auditEntry) { if (!this.config.auditLogEndpoint) return; try { await axios_1.default.post(this.config.auditLogEndpoint, auditEntry, { headers: { 'Content-Type': 'application/json' }, }); } catch (error) { console.warn('Failed to POST audit log:', error); } } generateSecurePaymentToken(paymentData) { const tokenData = { ...paymentData, tenantId: this.config.tenantId, nonce: crypto_js_1.default.lib.WordArray.random(128 / 8).toString(), expires: Date.now() + 30 * 60 * 1000, }; const encrypted = this.encryptToken(JSON.stringify(tokenData)); this.logAudit('payment_token_generated', `Secure payment token generated for ${paymentData.amount} ${paymentData.currency}`, undefined, paymentData.userId, paymentData.agentId, paymentData.amount, paymentData.currency, 'success', { tokenExpires: new Date(Date.now() + 30 * 60 * 1000).toISOString() }); return encrypted; } validatePaymentToken(encryptedToken) { const decrypted = this.decryptToken(encryptedToken); if (!decrypted) { this.logAudit('payment_token_validation_failed', 'Token decryption failed'); return { valid: false, error: 'Invalid token' }; } try { const data = JSON.parse(decrypted); if (data.expires && Date.now() > data.expires) { this.logAudit('payment_token_validation_failed', 'Token expired'); return { valid: false, error: 'Token expired' }; } if (data.tenantId !== this.config.tenantId) { this.logAudit('payment_token_validation_failed', 'Tenant mismatch'); return { valid: false, error: 'Tenant mismatch' }; } this.logAudit('payment_token_validated', 'Payment token validated successfully', undefined, data.userId, data.agentId, data.amount, data.currency); return { valid: true, data }; } catch (error) { this.logAudit('payment_token_validation_failed', 'Token parsing error: ' + String(error)); return { valid: false, error: 'Invalid token format' }; } } } exports.SecurityEnhancement = SecurityEnhancement; function createSecurityEnhancement(config) { return new SecurityEnhancement(config); } function generateEncryptionKey() { return crypto_js_1.default.lib.WordArray.random(256 / 8).toString(crypto_js_1.default.enc.Hex); }