@aikidosec/firewall
Version:
Zen by Aikido is an embedded Application Firewall that autonomously protects Node.js apps against common and critical attacks, provides rate limiting, detects malicious traffic (including bots), and more.
131 lines (130 loc) • 3.57 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LRUMap = void 0;
class LRUMap {
constructor(max = 1000, ttlInMsecs = 0) {
if (isNaN(max) || max < 0) {
throw new Error("Invalid max value");
}
if (isNaN(ttlInMsecs) || ttlInMsecs < 0) {
throw new Error("Invalid ttl value");
}
this.first = null;
this.items = new Map();
this.last = null;
this.max = max;
this.ttl = ttlInMsecs;
}
get size() {
return this.items.size;
}
bumpLru(item) {
if (this.last === item) {
return; // Item is already the last one, no need to bump
}
const last = this.last;
const next = item.next;
const prev = item.prev;
if (this.first === item) {
this.first = next;
}
item.next = null;
item.prev = last;
if (last)
last.next = item;
if (prev !== null) {
prev.next = next;
}
if (next !== null) {
next.prev = prev;
}
this.last = item;
}
clear() {
this.items = new Map();
this.first = null;
this.last = null;
}
delete(key) {
if (this.items.has(key)) {
const item = this.items.get(key);
this.items.delete(key);
if (item.prev !== null) {
item.prev.next = item.next;
}
if (item.next !== null) {
item.next.prev = item.prev;
}
if (this.first === item) {
this.first = item.next;
}
if (this.last === item) {
this.last = item.prev;
}
}
}
evict() {
if (this.size > 0) {
const item = this.first;
this.items.delete(item.key);
if (this.size === 0) {
this.first = null;
this.last = null;
}
else {
this.first = item.next;
if (this.first)
this.first.prev = null;
}
}
}
get(key) {
if (this.items.has(key)) {
const item = this.items.get(key);
// Item has already expired
if (this.ttl > 0 && item.expiry <= performance.now()) {
this.delete(key);
return;
}
// Item is still fresh
this.bumpLru(item);
return item.value;
}
}
keys() {
return this.items.keys();
}
set(key, value) {
// Replace existing item
if (this.items.has(key)) {
const item = this.items.get(key);
item.value = value;
item.expiry = this.ttl > 0 ? performance.now() + this.ttl : this.ttl;
if (this.last !== item) {
this.bumpLru(item);
}
return;
}
// Add new item
if (this.max > 0 && this.size === this.max) {
this.evict();
}
const item = {
expiry: this.ttl > 0 ? performance.now() + this.ttl : this.ttl,
key: key,
prev: this.last,
next: null,
value,
};
this.items.set(key, item);
if (this.size === 1) {
this.first = item;
}
else {
if (this.last)
this.last.next = item;
}
this.last = item;
}
}
exports.LRUMap = LRUMap;