mirror of
https://gitlab.com/soapbox-pub/ditto.git
synced 2025-12-06 11:29:46 +00:00
streamingController: rate-limit with ttl-cache
This commit is contained in:
parent
766290bd45
commit
44dfd15502
1 changed files with 24 additions and 1 deletions
|
|
@ -9,9 +9,10 @@ import { MuteListPolicy } from '@/policies/MuteListPolicy.ts';
|
||||||
import { getFeedPubkeys } from '@/queries.ts';
|
import { getFeedPubkeys } from '@/queries.ts';
|
||||||
import { hydrateEvents } from '@/storages/hydrate.ts';
|
import { hydrateEvents } from '@/storages/hydrate.ts';
|
||||||
import { Storages } from '@/storages.ts';
|
import { Storages } from '@/storages.ts';
|
||||||
import { bech32ToPubkey } from '@/utils.ts';
|
import { bech32ToPubkey, Time } from '@/utils.ts';
|
||||||
import { renderReblog, renderStatus } from '@/views/mastodon/statuses.ts';
|
import { renderReblog, renderStatus } from '@/views/mastodon/statuses.ts';
|
||||||
import { renderNotification } from '@/views/mastodon/notifications.ts';
|
import { renderNotification } from '@/views/mastodon/notifications.ts';
|
||||||
|
import TTLCache from '@isaacs/ttlcache';
|
||||||
|
|
||||||
const debug = Debug('ditto:streaming');
|
const debug = Debug('ditto:streaming');
|
||||||
|
|
||||||
|
|
@ -36,6 +37,11 @@ const streamSchema = z.enum([
|
||||||
|
|
||||||
type Stream = z.infer<typeof streamSchema>;
|
type Stream = z.infer<typeof streamSchema>;
|
||||||
|
|
||||||
|
const LIMITER_WINDOW = Time.minutes(5);
|
||||||
|
const LIMITER_LIMIT = 100;
|
||||||
|
|
||||||
|
const limiter = new TTLCache<string, number>();
|
||||||
|
|
||||||
const streamingController: AppController = async (c) => {
|
const streamingController: AppController = async (c) => {
|
||||||
const upgrade = c.req.header('upgrade');
|
const upgrade = c.req.header('upgrade');
|
||||||
const token = c.req.header('sec-websocket-protocol');
|
const token = c.req.header('sec-websocket-protocol');
|
||||||
|
|
@ -56,6 +62,7 @@ const streamingController: AppController = async (c) => {
|
||||||
const store = await Storages.db();
|
const store = await Storages.db();
|
||||||
const pubsub = await Storages.pubsub();
|
const pubsub = await Storages.pubsub();
|
||||||
|
|
||||||
|
const ip = c.req.header('x-real-ip');
|
||||||
const policy = pubkey ? new MuteListPolicy(pubkey, await Storages.admin()) : undefined;
|
const policy = pubkey ? new MuteListPolicy(pubkey, await Storages.admin()) : undefined;
|
||||||
|
|
||||||
function send(name: string, payload: object) {
|
function send(name: string, payload: object) {
|
||||||
|
|
@ -119,6 +126,22 @@ const streamingController: AppController = async (c) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
socket.onmessage = (e) => {
|
||||||
|
if (ip) {
|
||||||
|
const count = limiter.get(ip) ?? 0;
|
||||||
|
limiter.set(ip, count + 1, { ttl: LIMITER_WINDOW });
|
||||||
|
|
||||||
|
if (count > LIMITER_LIMIT) {
|
||||||
|
socket.close(1008, 'Rate limit exceeded');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof e.data !== 'string') {
|
||||||
|
socket.close(1003, 'Invalid message');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
socket.onclose = () => {
|
socket.onclose = () => {
|
||||||
controller.abort();
|
controller.abort();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue