"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.validateWordPressPermissions = validateWordPressPermissions; const migrate_1 = require("../db/migrate"); const ipaddr_js_1 = __importDefault(require("ipaddr.js")); /** * Validates if an IP address matches any of the allowed IP patterns * Supports CIDR notation and wildcards */ function isIpAllowed(clientIp, allowedIps) { try { const clientAddr = ipaddr_js_1.default.process(clientIp); for (const allowedIp of allowedIps) { const trimmed = allowedIp.trim(); if (!trimmed) continue; // Check for CIDR notation if (trimmed.includes('/')) { try { const [subnet, bits] = trimmed.split('/'); const range = ipaddr_js_1.default.parseCIDR(trimmed); if (clientAddr.match(range)) { return true; } } catch (e) { console.warn(`Invalid CIDR notation: ${trimmed}`); continue; } } else { // Exact match try { const allowedAddr = ipaddr_js_1.default.process(trimmed); if (clientAddr.toString() === allowedAddr.toString()) { return true; } } catch (e) { console.warn(`Invalid IP address: ${trimmed}`); continue; } } } return false; } catch (error) { console.error('Error processing client IP:', error); return false; } } /** * Validates if a domain matches any of the allowed domain patterns * Supports wildcard subdomains (*.example.com) */ function isDomainAllowed(origin, allowedDomains) { try { // Extract domain from origin URL const url = new URL(origin); const domain = url.hostname; for (const allowedDomain of allowedDomains) { const trimmed = allowedDomain.trim(); if (!trimmed) continue; // Wildcard subdomain support if (trimmed.startsWith('*.')) { const baseDomain = trimmed.substring(2); if (domain === baseDomain || domain.endsWith('.' + baseDomain)) { return true; } } else { // Exact match if (domain === trimmed) { return true; } } } return false; } catch (error) { console.error('Error processing domain:', error); return false; } } /** * WordPress API Permissions Middleware * Validates API access based on WordPress permissions table */ async function validateWordPressPermissions(req, res, next) { // Get API key from header const apiKey = req.headers['x-api-key']; // If no API key provided, skip WordPress validation if (!apiKey) { return next(); } try { // Query WordPress permissions table const result = await migrate_1.pool.query(` SELECT id, user_name, api_key, allowed_ips, allowed_domains, is_active FROM wp_dutchie_api_permissions WHERE api_key = $1 AND is_active = 1 `, [apiKey]); if (result.rows.length === 0) { return res.status(401).json({ error: 'Invalid API key' }); } const permission = result.rows[0]; // Get client IP const clientIp = req.headers['x-forwarded-for']?.split(',')[0].trim() || req.headers['x-real-ip'] || req.ip || req.connection.remoteAddress || ''; // Validate IP if configured if (permission.allowed_ips) { const allowedIps = permission.allowed_ips.split('\n').filter((ip) => ip.trim()); if (allowedIps.length > 0 && !isIpAllowed(clientIp, allowedIps)) { return res.status(403).json({ error: 'IP address not allowed', client_ip: clientIp }); } } // Validate domain if configured const origin = req.get('origin') || req.get('referer') || ''; if (permission.allowed_domains && origin) { const allowedDomains = permission.allowed_domains.split('\n').filter((d) => d.trim()); if (allowedDomains.length > 0 && !isDomainAllowed(origin, allowedDomains)) { return res.status(403).json({ error: 'Domain not allowed', origin: origin }); } } // Update last_used_at timestamp (async, don't wait) migrate_1.pool.query(` UPDATE wp_dutchie_api_permissions SET last_used_at = CURRENT_TIMESTAMP WHERE id = $1 `, [permission.id]).catch((err) => { console.error('Error updating last_used_at:', err); }); // Set apiToken on request for tracking middleware // Default rate limit of 100 requests/minute for WordPress permissions req.apiToken = { id: permission.id, name: permission.user_name, rate_limit: 100 }; next(); } catch (error) { console.error('WordPress permissions validation error:', error); return res.status(500).json({ error: 'Internal server error during API validation' }); } }