Files
Alberto-Audrix 32a36cceff
CI / lint-and-test (push) Canceled after 0s
first commit
2026-07-28 08:55:05 +07:00

110 lines
2.8 KiB
JavaScript

const crypto = require('crypto');
const { query } = require('../database/db');
/**
* Hash an API key using SHA-256
*/
function hashApiKey(key) {
return crypto.createHash('sha256').update(key).digest('hex');
}
/**
* Generate a new API key with 'cpa_' prefix
*/
function generateApiKey() {
const randomBytes = crypto.randomBytes(24);
return 'cpa_' + randomBytes.toString('hex');
}
/**
* Middleware to validate API key from X-API-Key header
*/
async function validateApiKey(req, res, next) {
const apiKey = req.headers['x-api-key'];
if (!apiKey) {
return res.status(401).json({
success: false,
error: 'API key is required. Provide X-API-Key header.'
});
}
if (!apiKey.startsWith('cpa_')) {
return res.status(401).json({
success: false,
error: 'Invalid API key format'
});
}
try {
const keyHash = hashApiKey(apiKey);
const result = await query(
`SELECT id, name, is_active, expires_at, rate_limit, allowed_ips
FROM api_keys
WHERE key_hash = $1`,
[keyHash]
);
const keyRecord = result.rows[0];
if (!keyRecord) {
return res.status(401).json({
success: false,
error: 'Invalid API key'
});
}
if (!keyRecord.is_active) {
return res.status(401).json({
success: false,
error: 'API key is inactive'
});
}
if (keyRecord.expires_at) {
const expiryDate = new Date(keyRecord.expires_at);
if (expiryDate < new Date()) {
return res.status(401).json({
success: false,
error: 'API key has expired'
});
}
}
if (keyRecord.allowed_ips) {
const allowedIps = keyRecord.allowed_ips.split(',').map(ip => ip.trim());
const clientIp = req.ip || req.connection.remoteAddress;
if (!allowedIps.includes(clientIp)) {
return res.status(403).json({
success: false,
error: 'IP address not allowed for this API key'
});
}
}
// Update last_used_at
await query('UPDATE api_keys SET last_used_at = CURRENT_TIMESTAMP WHERE id = $1', [keyRecord.id]);
req.apiKey = {
id: keyRecord.id,
name: keyRecord.name,
rateLimit: keyRecord.rate_limit
};
next();
} catch (error) {
console.error('API key validation error:', error);
return res.status(500).json({
success: false,
error: 'Authentication error'
});
}
}
module.exports = {
validateApiKey,
generateApiKey,
hashApiKey
};