bitcore-node
Version:
A blockchain indexing node with extended capabilities using bitcore
106 lines • 4.52 kB
JavaScript
;
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();
}
let [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 (err) {
logger_1.default.error('Rate Limiter failed');
}
return next();
};
}
//# sourceMappingURL=middleware.js.map