Spaces:
Running
Running
| /** | |
| * GoldRate Engine — API Key Authentication Middleware | |
| * | |
| * Validates API keys against Supabase api_keys table. | |
| * Keys have 30-day expiry and are tied to a price source (SLN or IBJA). | |
| * | |
| * Pass your key as: | |
| * Header: x-api-key: your_key | |
| * OR Query: ?apikey=your_key | |
| * | |
| * After auth, req.priceSource is set to 'SLN' or 'IBJA' | |
| */ | |
| const { getIsConnected, getClient } = require('./db'); | |
| // In-memory cache for validated keys (avoid DB hit every request) | |
| const keyCache = new Map(); | |
| const KEY_CACHE_TTL = 5 * 60 * 1000; // 5 minutes | |
| function authMiddleware(req, res, next) { | |
| const apiKey = req.headers['x-api-key'] || req.query.apikey; | |
| if (!apiKey) { | |
| return res.status(401).json({ | |
| success: false, | |
| error: 'API key required. Pass it as header "x-api-key" or query "?apikey=YOUR_KEY"' | |
| }); | |
| } | |
| // Master key from .env (never expires, for admin/frontend use) | |
| if (apiKey === process.env.API_KEY) { | |
| req.priceSource = 'SLN'; // Default to SLN for master key | |
| req.isMasterKey = true; | |
| return next(); | |
| } | |
| // Check key cache first | |
| const cached = keyCache.get(apiKey); | |
| if (cached && (Date.now() - cached.cachedAt) < KEY_CACHE_TTL) { | |
| const now = new Date(); | |
| if (!cached.is_active) { | |
| return res.status(403).json({ | |
| success: false, | |
| error: 'API key has been deactivated. Contact us to get a new key.', | |
| contact: process.env.CONTACT_PHONE || '9360345770' | |
| }); | |
| } | |
| if (new Date(cached.expires_at) < now) { | |
| return res.status(403).json({ | |
| success: false, | |
| error: 'API key expired. Contact us to renew.', | |
| contact: process.env.CONTACT_PHONE || '9360345770' | |
| }); | |
| } | |
| req.priceSource = cached.source; | |
| req.keyOwner = cached.owner_name; | |
| return next(); | |
| } | |
| // Look up in Supabase | |
| if (!getIsConnected()) { | |
| // If DB not connected, reject non-master keys | |
| return res.status(403).json({ | |
| success: false, | |
| error: 'Invalid API key' | |
| }); | |
| } | |
| const supabase = getClient(); | |
| supabase | |
| .from('api_keys') | |
| .select('*') | |
| .eq('api_key', apiKey) | |
| .single() | |
| .then(({ data, error }) => { | |
| if (error || !data) { | |
| return res.status(403).json({ | |
| success: false, | |
| error: 'Invalid API key. Contact us to get one.', | |
| contact: process.env.CONTACT_PHONE || '9360345770' | |
| }); | |
| } | |
| // Cache the key data | |
| keyCache.set(apiKey, { ...data, cachedAt: Date.now() }); | |
| // Check if active | |
| if (!data.is_active) { | |
| return res.status(403).json({ | |
| success: false, | |
| error: 'API key has been deactivated. Contact us to get a new key.', | |
| contact: process.env.CONTACT_PHONE || '9360345770' | |
| }); | |
| } | |
| // Check expiry | |
| const now = new Date(); | |
| if (new Date(data.expires_at) < now) { | |
| return res.status(403).json({ | |
| success: false, | |
| error: 'API key expired. Contact us to renew.', | |
| expired_at: data.expires_at, | |
| contact: process.env.CONTACT_PHONE || '9360345770' | |
| }); | |
| } | |
| // Valid key — set source | |
| req.priceSource = data.source; // 'SLN' or 'IBJA' | |
| req.keyOwner = data.owner_name; | |
| next(); | |
| }) | |
| .catch(() => { | |
| return res.status(500).json({ | |
| success: false, | |
| error: 'Authentication service error. Please try again.' | |
| }); | |
| }); | |
| } | |
| module.exports = { authMiddleware }; | |