@aikidosec/firewall
Version:
Zen by Aikido is an embedded Web Application Firewall that autonomously protects Node.js apps against common and critical attacks
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;