|
import { Database } from '../database/database.js'; |
|
import { MongoStorage } from "@canmertinyo/rate-limiter-mongo"; |
|
import { rateLimiter } from "@canmertinyo/rate-limiter-core"; |
|
import { ApiKey } from '../models.js'; |
|
import * as config from '../config.js'; |
|
|
|
const authenticateApiKeyPremium = async (req, res, next) => { |
|
const apiKey = req.headers['x-api-key']; |
|
|
|
if (!apiKey) { |
|
return res.status(401).json({ error: 'Premium API Key required' }); |
|
} |
|
|
|
try { |
|
const keyData = await ApiKey.findOne({ key: apiKey }); |
|
if (!keyData) { |
|
return res.status(403).json({ error: 'Invalid or non-premium API Key' }); |
|
} |
|
|
|
if (keyData.expiresAt && new Date() > keyData.expiresAt) { |
|
return res.status(403).json({ error: 'Premium API Key has expired' }); |
|
} |
|
|
|
next(); |
|
} catch (err) { |
|
res.status(500).json({ error: 'Server error' }); |
|
} |
|
}; |
|
|
|
const authenticateApiKey = async (req, res, next) => { |
|
const apiKey = req.headers['x-api-key']; |
|
const dbClient = new Database("AkenoXJs"); |
|
const db = dbClient.collection("api_keys"); |
|
if (!apiKey) { |
|
return res.status(401).json({ error: 'API Key required' }); |
|
} |
|
|
|
try { |
|
const keyDoc = await db.findOne({key: apiKey}); |
|
if (!keyDoc) { |
|
return res.status(403).json({ error: 'Invalid API Key' }); |
|
} |
|
next(); |
|
} catch (err) { |
|
res.status(500).json({ error: 'Server error' }); |
|
} |
|
}; |
|
|
|
|
|
const apiLimiter = rateLimiter({ |
|
|
|
|
|
|
|
|
|
|
|
|
|
ms: 2 * 60 * 1000, |
|
maxRequest: 100, |
|
keyGenerator: (req) => req.headers["x-api-key"], |
|
|
|
|
|
message: (req, res) => { |
|
const retryAfterMs = res.getHeaders()["retry-after"] * 1000 || 2 * 60 * 1000; |
|
const remainingSeconds = Math.ceil(retryAfterMs / 1000); |
|
const remainingMinutes = Math.floor(remainingSeconds / 60); |
|
return { |
|
error: `Too many requests from this API Key. Try again later: ${remainingMinutes}m ${remainingSeconds % 60}s.` |
|
}; |
|
} |
|
}); |
|
|
|
class CheckMilWare { |
|
constructor() { |
|
this.dbClient = new Database("AkenoXJs"); |
|
} |
|
|
|
async handle(req, res, next) { |
|
try { |
|
|
|
|
|
|
|
|
|
|
|
|
|
res.removeHeader("Link"); |
|
res.removeHeader("Connection"); |
|
const xForwardedFor = req.headers['x-forwarded-for']; |
|
const xRealIP = req.headers['x-real-ip']; |
|
const cfConnectingIP = req.headers['cf-connecting-ip']; |
|
let realIP = req.ip; |
|
|
|
if (xForwardedFor) { |
|
realIP = xForwardedFor.split(',')[0].trim(); |
|
} else if (xRealIP) { |
|
realIP = xRealIP; |
|
} else if (cfConnectingIP) { |
|
realIP = cfConnectingIP; |
|
} |
|
|
|
req.realIP = realIP; |
|
|
|
const isBlocked = await this.dbClient.CheckIsBlocked(realIP); |
|
if (isBlocked && isBlocked.blocked) { |
|
return res.status(403).send("Access denied: IP is blocked"); |
|
} |
|
|
|
if (req.path === '/.env') { |
|
console.log("Check path /env"); |
|
await this.dbClient.AddIpisBlocked(realIP); |
|
return res.status(403).send("Access denied: IP is blocked.."); |
|
} |
|
console.log(`Real IP address is: ${realIP} |
|
path method: ${req.path} |
|
method: ${req.method} |
|
header used: ${xForwardedFor ? "x-forwarded-for" : xRealIP ? "x-real-ip" : cfConnectingIP ? "cf-connecting-ip" : "req.ip"} |
|
`); |
|
|
|
next(); |
|
} catch (error) { |
|
console.error("Error in middleware: " + error); |
|
res.status(500).send("Something bad happened"); |
|
} |
|
} |
|
} |
|
|
|
export { |
|
CheckMilWare, |
|
authenticateApiKey, |
|
authenticateApiKeyPremium, |
|
apiLimiter |
|
}; |