"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CacheTimes = exports.Confirmations = void 0;
exports.LogMiddleware = LogMiddleware;
exports.SetCache = SetCache;
exports.CacheMiddleware = CacheMiddleware;
exports.RateLimiter = RateLimiter;
const logger_1 = __importDefault(require("../logger"));
const rateLimit_1 = require("../models/rateLimit");
const config_1 = require("../services/config");
function LogObj(logOut) {
    logger_1.default.info(`${logOut.time} | ${logOut.ip} | ${logOut.phase} | ${logOut.took} | ${logOut.method} | ${logOut.status} | ${logOut.url} | ${logOut.openConnections} open`);
}
let openConnections = 0;
function LogPhase(req, res, phase) {
    const ip = req.header('CF-Connecting-IP') || req.socket.remoteAddress || req.hostname;
    const logOut = {
        time: req.startTime ? req.startTime.toTimeString() : new Date().toTimeString(),
        ip: ip.padStart(22, ' '),
        phase: phase.padStart(8, ' '),
        method: req.method.padStart(6, ' '),
        status: '...'.padStart(5, ' '),
        url: `${req.baseUrl}${req.url}`,
        took: '...'.padStart(10, ' '),
        openConnections: openConnections.toString().padStart(6, ' ')
    };
    if (req.startTime && ['END', 'CLOSED'].includes(phase)) {
        const endTime = new Date();
        const startTime = req.startTime ? req.startTime : endTime;
        const totalTime = endTime.getTime() - startTime.getTime();
        const totalTimeMsg = `${totalTime} ms`.padStart(10, ' ');
        logOut.took = totalTimeMsg.padStart(10, ' ');
        logOut.status = res.statusCode.toString().padStart(5, ' ');
    }
    LogObj(logOut);
}
function LogMiddleware() {
    return (req, res, next) => {
        req.startTime = new Date();
        openConnections++;
        LogPhase(req, res, 'START');
        res.on('finish', () => {
            LogPhase(req, res, 'END');
        });
        res.on('close', () => {
            openConnections--;
            LogPhase(req, res, 'CLOSED');
        });
        next();
    };
}
var Confirmations;
(function (Confirmations) {
    Confirmations[Confirmations["None"] = 0] = "None";
    Confirmations[Confirmations["Shallow"] = 1] = "Shallow";
    Confirmations[Confirmations["Deep"] = 100] = "Deep";
})(Confirmations || (exports.Confirmations = Confirmations = {}));
var CacheTimes;
(function (CacheTimes) {
    CacheTimes[CacheTimes["None"] = 0] = "None";
    CacheTimes[CacheTimes["Second"] = 1] = "Second";
    CacheTimes[CacheTimes["Minute"] = 60] = "Minute";
    CacheTimes[CacheTimes["Hour"] = 3600] = "Hour";
    CacheTimes[CacheTimes["Day"] = 86400] = "Day";
    CacheTimes[CacheTimes["Month"] = 2592000] = "Month";
    CacheTimes[CacheTimes["Year"] = 31536000] = "Year";
})(CacheTimes || (exports.CacheTimes = CacheTimes = {}));
function SetCache(res, serverSeconds, browserSeconds = 0) {
    res.setHeader('Cache-Control', `s-maxage=${serverSeconds}, max-age=${browserSeconds}`);
}
function CacheMiddleware(serverSeconds = CacheTimes.Second, browserSeconds = CacheTimes.None) {
    return (_, res, next) => {
        SetCache(res, serverSeconds, browserSeconds);
        next();
    };
}
function isWhiteListed(whitelist = [], ip) {
    return whitelist.some(listItem => ip.startsWith(listItem));
}
function RateLimiter(method, perSecond, perMinute, perHour) {
    return async (req, res, next) => {
        try {
            const identifier = req.header('CF-Connecting-IP') || req.socket.remoteAddress || '';
            const rateLimiter = config_1.Config.for('api').rateLimiter;
            const whitelist = rateLimiter && rateLimiter.whitelist;
            const isDisabled = rateLimiter && rateLimiter.disabled;
            if (isDisabled || isWhiteListed(whitelist, identifier)) {
                return next();
            }
            const [perSecondResult, perMinuteResult, perHourResult] = await rateLimit_1.RateLimitStorage.incrementAndCheck(identifier, method);
            if (perSecondResult.value.count > perSecond ||
                perMinuteResult.value.count > perMinute ||
                perHourResult.value.count > perHour) {
                return res.status(429).send('Rate Limited');
            }
        }
        catch {
            logger_1.default.error('Rate Limiter failed');
        }
        return next();
    };
}
//# sourceMappingURL=middleware.js.map