HEX
Server: nginx/1.18.0
System: Linux test-ipsremont 5.4.0-214-generic #234-Ubuntu SMP Fri Mar 14 23:50:27 UTC 2025 x86_64
User: ips (1000)
PHP: 8.0.30
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: /var/www/quadcode.com/node_modules/sveltekit-rate-limiter/dist/server/index.js
import { nanoid } from 'nanoid';
import TTLCache from '@isaacs/ttlcache';
///// Plugins /////////////////////////////////////////////////////////////////
class IPRateLimiter {
    rate;
    constructor(rate) {
        this.rate = rate;
    }
    async hash(event) {
        return event.getClientAddress();
    }
}
class IPUserAgentRateLimiter {
    rate;
    constructor(rate) {
        this.rate = rate;
    }
    async hash(event) {
        const ua = event.request.headers.get('user-agent');
        if (!ua)
            return false;
        return event.getClientAddress() + ua;
    }
}
class CookieRateLimiter {
    rate;
    cookieOptions;
    secret;
    requirePreflight;
    cookieId;
    hashFunction;
    constructor(options) {
        this.cookieId = options.name;
        this.secret = options.secret;
        this.rate = options.rate;
        this.requirePreflight = options.preflight;
        this.hashFunction = options.hashFunction ?? defaultHashFunction;
        this.cookieOptions = {
            path: '/',
            httpOnly: true,
            maxAge: 60 * 60 * 24 * 7,
            sameSite: 'strict',
            ...options.serializeOptions
        };
    }
    async hash(event) {
        const currentId = await this.userIdFromCookie(event.cookies.get(this.cookieId), event);
        return currentId ? currentId : false;
    }
    async preflight(event) {
        const data = event.cookies.get(this.cookieId);
        if (data) {
            const userId = await this.userIdFromCookie(data, event);
            if (userId)
                return userId;
        }
        const userId = nanoid();
        event.cookies.set(this.cookieId, userId + ';' + (await this.hashFunction(this.secret + userId)), this.cookieOptions);
        return userId;
    }
    async userIdFromCookie(cookie, event) {
        const empty = () => {
            return this.requirePreflight ? null : this.preflight(event);
        };
        if (!cookie)
            return empty();
        const [userId, secretHash] = cookie.split(';');
        if (!userId || !secretHash)
            return empty();
        if ((await this.hashFunction(this.secret + userId)) != secretHash) {
            return empty();
        }
        return userId;
    }
}
let defaultHashFunction;
if (globalThis?.crypto?.subtle) {
    defaultHashFunction = _subtleSha256;
}
async function _subtleSha256(str) {
    const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(str));
    return [...new Uint8Array(digest)]
        .map((b) => b.toString(16).padStart(2, '0'))
        .join('');
}
export class RateLimiter {
    store;
    plugins;
    onLimited;
    hashFunction;
    cookieLimiter;
    static TTLTime(unit) {
        switch (unit) {
            case 's':
                return 1000;
            case 'm':
                return 60000;
            case 'h':
                return 60 * 60000;
            case '2s':
                return 2000;
            case '5s':
                return 5000;
            case '10s':
                return 10000;
            case '15s':
                return 15000;
            case '30s':
                return 30000;
            case '45s':
                return 45000;
            case '15m':
                return 15 * 60000;
            case '30m':
                return 30 * 60000;
            case '100ms':
                return 100;
            case '250ms':
                return 250;
            case '500ms':
                return 500;
            case '2h':
                return 2 * 60 * 60000;
            case '6h':
                return 6 * 60 * 60000;
            case '12h':
                return 12 * 60 * 60000;
            case 'd':
                return 24 * 60 * 60000;
            case 'ms':
                return 1;
        }
        throw new Error('Invalid unit for TTLTime: ' + unit);
    }
    /**
     * Check if a request event is rate limited.
     * @param {RequestEvent} event
     * @returns {Promise<boolean>} true if request is limited, false otherwise
     */
    async isLimited(event) {
        return (await this._isLimited(event)).limited;
    }
    /**
     * Clear all rate limits.
     */
    async clear() {
        return await this.store.clear();
    }
    /**
     * Check if a request event is rate limited.
     * @param {RequestEvent} event
     * @returns {Promise<boolean>} true if request is limited, false otherwise
     */
    async _isLimited(event) {
        let limited = false;
        for (const plugin of this.plugins) {
            const id = await plugin.hash(event);
            if (id === false) {
                if (this.onLimited) {
                    const status = await this.onLimited(event, 'rejected');
                    if (status === true)
                        return { limited: false, hash: null, unit: plugin.rate[1] };
                }
                return { limited: true, hash: null, unit: plugin.rate[1] };
            }
            else if (id === true) {
                return { limited: false, hash: null, unit: plugin.rate[1] };
            }
            else if (id === null) {
                limited = true;
                continue;
            }
            else {
                limited = false;
            }
            if (!id) {
                throw new Error('Empty hash returned from rate limiter ' + plugin.constructor.name);
            }
            const hash = await this.hashFunction(id);
            const rate = await this.store.add(hash, plugin.rate[1]);
            if (rate > plugin.rate[0]) {
                if (this.onLimited) {
                    const status = await this.onLimited(event, 'rate');
                    if (status === true)
                        return { limited: false, hash, unit: plugin.rate[1] };
                }
                return { limited: true, hash, unit: plugin.rate[1] };
            }
        }
        return {
            limited,
            hash: null,
            unit: this.plugins[this.plugins.length - 1].rate[1]
        };
    }
    constructor(options = {}) {
        this.plugins = [...(options.plugins ?? [])];
        this.onLimited = options.onLimited;
        this.hashFunction = options.hashFunction ?? defaultHashFunction;
        if (!this.hashFunction) {
            throw new Error('No RateLimiter hash function found. Please set one with the hashFunction option.');
        }
        const IPRates = options.IP ?? options.rates?.IP;
        if (IPRates)
            this.plugins.push(new IPRateLimiter(IPRates));
        const IPUARates = options.IPUA ?? options.rates?.IPUA;
        if (IPUARates)
            this.plugins.push(new IPUserAgentRateLimiter(IPUARates));
        const cookieRates = options.cookie ?? options.rates?.cookie;
        if (cookieRates) {
            this.plugins.push((this.cookieLimiter = new CookieRateLimiter({
                hashFunction: this.hashFunction,
                ...cookieRates
            })));
        }
        if (!this.plugins.length) {
            throw new Error('No plugins set for RateLimiter!');
        }
        // Sort plugins by rate, if early cancelling
        this.plugins.sort((a, b) => {
            const diff = RateLimiter.TTLTime(a.rate[1]) - RateLimiter.TTLTime(b.rate[1]);
            return diff == 0 ? a.rate[0] - b.rate[0] : diff;
        });
        const maxTTL = this.plugins.reduce((acc, plugin) => {
            const rate = plugin.rate[1];
            if (rate == 'ms') {
                console.warn('RateLimiter: The "ms" unit is not reliable due to OS timing issues.');
            }
            const time = RateLimiter.TTLTime(rate);
            return Math.max(time, acc);
        }, 0);
        this.store = options.store ?? new TTLStore(maxTTL, options.maxItems);
    }
}
export class RetryAfterRateLimiter extends RateLimiter {
    retryAfter;
    constructor(options = {}, retryAfterStore) {
        super(options);
        this.retryAfter = retryAfterStore ?? new RetryAfterStore();
    }
    static toSeconds(rateMs) {
        return Math.max(0, Math.floor(rateMs / 1000));
    }
    static unitToSeconds(unit) {
        return RetryAfterRateLimiter.toSeconds(RateLimiter.TTLTime(unit));
    }
    /**
     * Clear all rate limits.
     */
    async clear() {
        await this.retryAfter.clear();
        return await super.clear();
    }
    /**
     * Check if a request event is rate limited.
     * @param {RequestEvent} event
     * @returns {Promise<limited: boolean, retryAfter: number>} Rate limit status for the event.
     */
    async check(event) {
        const result = await this._isLimited(event);
        if (!result.limited)
            return { limited: false, retryAfter: 0 };
        if (result.hash === null) {
            return {
                limited: true,
                retryAfter: RetryAfterRateLimiter.unitToSeconds(result.unit)
            };
        }
        const retryAfter = RetryAfterRateLimiter.toSeconds((await this.retryAfter.add(result.hash, result.unit)) - Date.now());
        return { limited: true, retryAfter };
    }
}
///// Stores ///////////////////////////////////////////////////////////////////
class TTLStore {
    cache;
    constructor(maxTTL, maxItems = Infinity) {
        this.cache = new TTLCache({
            ttl: maxTTL,
            max: maxItems,
            noUpdateTTL: true
        });
    }
    async clear() {
        return this.cache.clear();
    }
    async add(hash, unit) {
        const currentRate = this.cache.get(hash) ?? 0;
        return this.set(hash, currentRate + 1, unit);
    }
    set(hash, rate, unit) {
        this.cache.set(hash, rate, { ttl: RateLimiter.TTLTime(unit) });
        return rate;
    }
}
class RetryAfterStore {
    cache;
    constructor(maxItems = Infinity) {
        this.cache = new TTLCache({
            max: maxItems,
            noUpdateTTL: true
        });
    }
    async clear() {
        return this.cache.clear();
    }
    async add(hash, unit) {
        const currentRate = this.cache.get(hash);
        if (currentRate)
            return this.cache.get(hash) ?? 0;
        const ttl = RateLimiter.TTLTime(unit);
        const retryAfter = Date.now() + ttl;
        this.cache.set(hash, retryAfter, { ttl });
        return retryAfter;
    }
}