From b86032a001b45d3f345820b84ba4489981116919 Mon Sep 17 00:00:00 2001 From: Flam3rboy <34555296+Flam3rboy@users.noreply.github.com> Date: Tue, 24 Aug 2021 16:34:46 +0200 Subject: :sparkles: typeorm entities --- util/src/entities/RateLimit.ts | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 util/src/entities/RateLimit.ts (limited to 'util/src/entities/RateLimit.ts') diff --git a/util/src/entities/RateLimit.ts b/util/src/entities/RateLimit.ts new file mode 100644 index 00000000..374a0759 --- /dev/null +++ b/util/src/entities/RateLimit.ts @@ -0,0 +1,25 @@ +import { Column, Entity, JoinColumn, ManyToOne } from "typeorm"; +import { BaseClass } from "./BaseClass"; +import { User } from "./User"; + +@Entity("rate_limits") +export class RateLimit extends BaseClass { + @Column() + id: "global" | "error" | string; // channel_239842397 | guild_238927349823 | webhook_238923423498 + + @Column() + user_id: string; + + @JoinColumn({ name: "user_id" }) + @ManyToOne(() => User, (user) => user.id) + user: User; + + @Column() + hits: number; + + @Column() + blocked: boolean; + + @Column() + expires_at: Date; +} -- cgit 1.5.1 From db3f5c0d1b5556e16c37704467b3599a6230be02 Mon Sep 17 00:00:00 2001 From: Flam3rboy <34555296+Flam3rboy@users.noreply.github.com> Date: Thu, 26 Aug 2021 20:48:09 +0200 Subject: :sparkles: use RelationId --- util/src/entities/Application.ts | 6 +- util/src/entities/AuditLog.ts | 6 +- util/src/entities/Ban.ts | 8 +- util/src/entities/Channel.ts | 12 +- util/src/entities/Config.ts | 274 ++++++++++++++++++++++++++++++++++++++ util/src/entities/Emoji.ts | 4 +- util/src/entities/Guild.ts | 29 ++-- util/src/entities/Invite.ts | 12 +- util/src/entities/Member.ts | 6 +- util/src/entities/Message.ts | 29 ++-- util/src/entities/RateLimit.ts | 4 +- util/src/entities/ReadState.ts | 9 +- util/src/entities/Relationship.ts | 4 +- util/src/entities/Role.ts | 4 +- util/src/entities/Team.ts | 6 +- util/src/entities/TeamMember.ts | 6 +- util/src/entities/Template.ts | 8 +- util/src/entities/User.ts | 41 +++++- util/src/entities/VoiceState.ts | 11 +- util/src/entities/Webhook.ts | 46 +++++-- util/src/entities/index.ts | 1 + 21 files changed, 444 insertions(+), 82 deletions(-) create mode 100644 util/src/entities/Config.ts (limited to 'util/src/entities/RateLimit.ts') diff --git a/util/src/entities/Application.ts b/util/src/entities/Application.ts index 64b5d2e2..90d0f056 100644 --- a/util/src/entities/Application.ts +++ b/util/src/entities/Application.ts @@ -1,4 +1,4 @@ -import { Column, Entity, JoinColumn, ManyToOne } from "typeorm"; +import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; import { Team } from "./Team"; @@ -38,14 +38,14 @@ export class Application extends BaseClass { @Column() verify_key: string; - @Column() + @RelationId((application: Application) => application.team) team_id: string; @JoinColumn({ name: "team_id" }) @ManyToOne(() => Team, (team: Team) => team.id) team?: Team; - @Column() + @RelationId((application: Application) => application.guild) guild_id: string; @JoinColumn({ name: "guild_id" }) diff --git a/util/src/entities/AuditLog.ts b/util/src/entities/AuditLog.ts index 53e99261..2195771b 100644 --- a/util/src/entities/AuditLog.ts +++ b/util/src/entities/AuditLog.ts @@ -1,4 +1,4 @@ -import { Column, Entity, JoinColumn, ManyToOne } from "typeorm"; +import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { ChannelPermissionOverwrite } from "./Channel"; import { User } from "./User"; @@ -43,14 +43,14 @@ export enum AuditLogEvents { @Entity("audit_logs") export class AuditLogEntry extends BaseClass { - @Column() + @RelationId((auditlog: AuditLogEntry) => auditlog.target) target_id: string; @JoinColumn({ name: "user_id" }) @ManyToOne(() => User, (user: User) => user.id) target?: User; - @Column() + @RelationId((auditlog: AuditLogEntry) => auditlog.user) user_id: string; @JoinColumn({ name: "user_id" }) diff --git a/util/src/entities/Ban.ts b/util/src/entities/Ban.ts index ceea4a05..2553e886 100644 --- a/util/src/entities/Ban.ts +++ b/util/src/entities/Ban.ts @@ -1,25 +1,25 @@ -import { Column, Entity, JoinColumn, ManyToOne } from "typeorm"; +import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; import { User } from "./User"; @Entity("bans") export class Ban extends BaseClass { - @Column() + @RelationId((ban: Ban) => ban.user) user_id: string; @JoinColumn({ name: "user_id" }) @ManyToOne(() => User, (user: User) => user.id) user: User; - @Column() + @RelationId((ban: Ban) => ban.guild) guild_id: string; @JoinColumn({ name: "guild_id" }) @ManyToOne(() => Guild, (guild: Guild) => guild.id) guild: Guild; - @Column() + @RelationId((ban: Ban) => ban.executor) executor_id: string; @JoinColumn({ name: "executor_id" }) diff --git a/util/src/entities/Channel.ts b/util/src/entities/Channel.ts index 5845607a..d26f1054 100644 --- a/util/src/entities/Channel.ts +++ b/util/src/entities/Channel.ts @@ -1,4 +1,4 @@ -import { Column, Entity, JoinColumn, ManyToMany, ManyToOne } from "typeorm"; +import { Column, Entity, JoinColumn, ManyToMany, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; import { Message } from "./Message"; @@ -25,35 +25,35 @@ export class Channel extends BaseClass { @Column({ type: "simple-enum", enum: ChannelType }) type: ChannelType; - @Column("simple-array") + @RelationId((channel: Channel) => channel.recipients) recipient_ids: string[]; @JoinColumn({ name: "recipient_ids" }) @ManyToMany(() => User, (user: User) => user.id) recipients?: User[]; - @Column() + @RelationId((channel: Channel) => channel.last_message) last_message_id: string; @JoinColumn({ name: "last_message_id" }) @ManyToOne(() => Message, (message: Message) => message.id) last_message?: Message; - @Column() + @RelationId((channel: Channel) => channel.guild) guild_id?: string; @JoinColumn({ name: "guild_id" }) @ManyToOne(() => Guild, (guild: Guild) => guild.id) guild: Guild; - @Column() + @RelationId((channel: Channel) => channel.parent) parent_id: string; @JoinColumn({ name: "parent_id" }) @ManyToOne(() => Channel, (channel: Channel) => channel.id) parent?: Channel; - @Column() + @RelationId((channel: Channel) => channel.owner) owner_id: string; @JoinColumn({ name: "owner_id" }) diff --git a/util/src/entities/Config.ts b/util/src/entities/Config.ts new file mode 100644 index 00000000..60d84958 --- /dev/null +++ b/util/src/entities/Config.ts @@ -0,0 +1,274 @@ +import { Column, Entity, JoinColumn, ManyToOne } from "typeorm"; +import { Snowflake } from "../util"; +import { BaseClass } from "./BaseClass"; +import crypto from "crypto"; + +@Entity("config") +export class ConfigEntity extends BaseClass { + @Column("simple-json") + value: ConfigValue; +} + +export interface RateLimitOptions { + bot?: number; + count: number; + window: number; + onyIp?: boolean; +} + +export interface Region { + id: string; + name: string; + vip: boolean; + custom: boolean; + deprecated: boolean; + optimal: boolean; +} + +export interface KafkaBroker { + ip: string; + port: number; +} + +export interface ConfigValue { + gateway: { + endpointClient: string | null; + endpoint: string | null; + }; + cdn: { + endpointClient: string | null; + endpoint: string | null; + }; + general: { + instance_id: string; + }; + permissions: { + user: { + createGuilds: boolean; + }; + }; + limits: { + user: { + maxGuilds: number; + maxUsername: number; + maxFriends: number; + }; + guild: { + maxRoles: number; + maxMembers: number; + maxChannels: number; + maxChannelsInCategory: number; + hideOfflineMember: number; + }; + message: { + maxCharacters: number; + maxTTSCharacters: number; + maxReactions: number; + maxAttachmentSize: number; + maxBulkDelete: number; + }; + channel: { + maxPins: number; + maxTopic: number; + }; + rate: { + ip: Omit; + global: RateLimitOptions; + error: RateLimitOptions; + routes: { + guild: RateLimitOptions; + webhook: RateLimitOptions; + channel: RateLimitOptions; + auth: { + login: RateLimitOptions; + register: RateLimitOptions; + }; + // TODO: rate limit configuration for all routes + }; + }; + }; + security: { + autoUpdate: boolean | number; + requestSignature: string; + jwtSecret: string; + forwadedFor: string | null; // header to get the real user ip address + captcha: { + enabled: boolean; + service: "recaptcha" | "hcaptcha" | null; // TODO: hcaptcha, custom + sitekey: string | null; + secret: string | null; + }; + ipdataApiKey: string | null; + }; + login: { + requireCaptcha: boolean; + }; + register: { + email: { + necessary: boolean; // we have to use necessary instead of required as the cli tool uses json schema and can't use required + allowlist: boolean; + blocklist: boolean; + domains: string[]; + }; + dateOfBirth: { + necessary: boolean; + minimum: number; // in years + }; + requireCaptcha: boolean; + requireInvite: boolean; + allowNewRegistration: boolean; + allowMultipleAccounts: boolean; + blockProxies: boolean; + password: { + minLength: number; + minNumbers: number; + minUpperCase: number; + minSymbols: number; + }; + }; + regions: { + default: string; + available: Region[]; + }; + rabbitmq: { + host: string | null; + }; + kafka: { + brokers: KafkaBroker[] | null; + }; +} + +export const DefaultConfigOptions: ConfigValue = { + gateway: { + endpointClient: null, + endpoint: null, + }, + cdn: { + endpointClient: null, + endpoint: null, + }, + general: { + instance_id: Snowflake.generate(), + }, + permissions: { + user: { + createGuilds: true, + }, + }, + limits: { + user: { + maxGuilds: 100, + maxUsername: 32, + maxFriends: 1000, + }, + guild: { + maxRoles: 250, + maxMembers: 250000, + maxChannels: 500, + maxChannelsInCategory: 50, + hideOfflineMember: 1000, + }, + message: { + maxCharacters: 2000, + maxTTSCharacters: 200, + maxReactions: 20, + maxAttachmentSize: 8388608, + maxBulkDelete: 100, + }, + channel: { + maxPins: 50, + maxTopic: 1024, + }, + rate: { + ip: { + count: 500, + window: 5, + }, + global: { + count: 20, + window: 5, + bot: 250, + }, + error: { + count: 10, + window: 5, + }, + routes: { + guild: { + count: 5, + window: 5, + }, + webhook: { + count: 5, + window: 20, + }, + channel: { + count: 5, + window: 20, + }, + auth: { + login: { + count: 5, + window: 60, + }, + register: { + count: 2, + window: 60 * 60 * 12, + }, + }, + }, + }, + }, + security: { + autoUpdate: true, + requestSignature: crypto.randomBytes(32).toString("base64"), + jwtSecret: crypto.randomBytes(256).toString("base64"), + forwadedFor: null, + // forwadedFor: "X-Forwarded-For" // nginx/reverse proxy + // forwadedFor: "CF-Connecting-IP" // cloudflare: + captcha: { + enabled: false, + service: null, + sitekey: null, + secret: null, + }, + ipdataApiKey: "eca677b284b3bac29eb72f5e496aa9047f26543605efe99ff2ce35c9", + }, + login: { + requireCaptcha: false, + }, + register: { + email: { + necessary: true, + allowlist: false, + blocklist: true, + domains: [], // TODO: efficiently save domain blocklist in database + // domains: fs.readFileSync(__dirname + "/blockedEmailDomains.txt", { encoding: "utf8" }).split("\n"), + }, + dateOfBirth: { + necessary: true, + minimum: 13, + }, + requireInvite: false, + requireCaptcha: true, + allowNewRegistration: true, + allowMultipleAccounts: true, + blockProxies: true, + password: { + minLength: 8, + minNumbers: 2, + minUpperCase: 2, + minSymbols: 0, + }, + }, + regions: { + default: "fosscord", + available: [{ id: "fosscord", name: "Fosscord", vip: false, custom: false, deprecated: false, optimal: false }], + }, + rabbitmq: { + host: null, + }, + kafka: { + brokers: null, + }, +}; diff --git a/util/src/entities/Emoji.ts b/util/src/entities/Emoji.ts index 366549db..b31ddb3b 100644 --- a/util/src/entities/Emoji.ts +++ b/util/src/entities/Emoji.ts @@ -1,4 +1,4 @@ -import { Column, Entity, JoinColumn, ManyToMany, ManyToOne } from "typeorm"; +import { Column, Entity, JoinColumn, ManyToMany, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; import { Role } from "./Role"; @@ -30,7 +30,7 @@ export class Emoji extends BaseClass { @Column() url: string; - @Column("simple-array") + @RelationId((emoji: Emoji) => emoji.roles) role_ids: string[]; @JoinColumn({ name: "role_ids" }) diff --git a/util/src/entities/Guild.ts b/util/src/entities/Guild.ts index d46d31bc..d7b4dff4 100644 --- a/util/src/entities/Guild.ts +++ b/util/src/entities/Guild.ts @@ -1,4 +1,4 @@ -import { Column, Entity, JoinColumn, ManyToMany, ManyToOne, OneToOne } from "typeorm"; +import { Column, Entity, JoinColumn, ManyToMany, ManyToOne, OneToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { Channel } from "./Channel"; import { Emoji } from "./Emoji"; @@ -10,7 +10,7 @@ import { VoiceState } from "./VoiceState"; @Entity("guilds") export class Guild extends BaseClass { - @Column() + @RelationId((guild: Guild) => guild.afk_channel) afk_channel_id?: string; @JoinColumn({ name: "afk_channel_id" }) @@ -64,35 +64,35 @@ export class Guild extends BaseClass { @Column() presence_count?: number; // users online - @Column("simple-array") + @RelationId((guild: Guild) => guild.members) member_ids: string[]; @JoinColumn({ name: "member_ids" }) @ManyToMany(() => Member, (member: Member) => member.id) members: Member[]; - @Column("simple-array") + @RelationId((guild: Guild) => guild.roles) role_ids: string[]; @JoinColumn({ name: "role_ids" }) @ManyToMany(() => Role, (role: Role) => role.id) roles: Role[]; - @Column("simple-array") + @RelationId((guild: Guild) => guild.channels) channel_ids: string[]; @JoinColumn({ name: "channel_ids" }) @ManyToMany(() => Channel, (channel: Channel) => channel.id) channels: Channel[]; - @Column("simple-array") + @RelationId((guild: Guild) => guild.emojis) emoji_ids: string[]; @JoinColumn({ name: "emoji_ids" }) @ManyToMany(() => Emoji, (emoji: Emoji) => emoji.id) emojis: Emoji[]; - @Column("simple-array") + @RelationId((guild: Guild) => guild.voice_states) voice_state_ids: string[]; @JoinColumn({ name: "voice_state_ids" }) @@ -105,7 +105,7 @@ export class Guild extends BaseClass { @Column() name: string; - @Column() + @RelationId((guild: Guild) => guild.owner) owner_id: string; @JoinColumn({ name: "owner_id" }) @@ -121,11 +121,14 @@ export class Guild extends BaseClass { @Column() premium_tier?: number; // nitro boost level + @RelationId((guild: Guild) => guild.public_updates_channel) + public_updates_channel_id: string; + @JoinColumn({ name: "public_updates_channel_id" }) @ManyToOne(() => Channel, (channel: Channel) => channel.id) public_updates_channel?: Channel; - @Column() + @RelationId((guild: Guild) => guild.rules_channel) rules_channel_id?: string; @JoinColumn({ name: "rules_channel_id" }) @@ -138,7 +141,7 @@ export class Guild extends BaseClass { @Column() splash?: string; - @Column() + @RelationId((guild: Guild) => guild.system_channel) system_channel_id?: string; @JoinColumn({ name: "system_channel_id" }) @@ -151,6 +154,9 @@ export class Guild extends BaseClass { @Column() unavailable?: boolean; + @RelationId((guild: Guild) => guild.vanity_url) + vanity_url_code?: string; + @JoinColumn({ name: "vanity_url_code" }) @OneToOne(() => Invite, (invite: Invite) => invite.code) vanity_url?: Invite; @@ -170,6 +176,9 @@ export class Guild extends BaseClass { }[]; }; + @RelationId((guild: Guild) => guild.widget_channel) + widget_channel_id?: string; + @JoinColumn({ name: "widget_channel_id" }) @ManyToOne(() => Channel, (channel: Channel) => channel.id) widget_channel?: Channel; diff --git a/util/src/entities/Invite.ts b/util/src/entities/Invite.ts index 19f7206a..eac0cba0 100644 --- a/util/src/entities/Invite.ts +++ b/util/src/entities/Invite.ts @@ -1,4 +1,4 @@ -import { Column, Entity, JoinColumn, ManyToOne } from "typeorm"; +import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { Channel } from "./Channel"; import { Guild } from "./Guild"; @@ -27,29 +27,29 @@ export class Invite extends BaseClass { @Column() expires_at: Date; - @Column() + @RelationId((invite: Invite) => invite.guild) guild_id: string; @JoinColumn({ name: "guild_id" }) @ManyToOne(() => Guild, (guild: Guild) => guild.id) guild: Guild; - @Column() + @RelationId((invite: Invite) => invite.channel) channel_id: string; @JoinColumn({ name: "channel_id" }) @ManyToOne(() => Channel, (channel: Channel) => channel.id) channel: Channel; - @Column() + @RelationId((invite: Invite) => invite.inviter) inviter_id: string; @JoinColumn({ name: "inviter_id" }) @ManyToOne(() => User, (user: User) => user.id) inviter: User; - @Column() - target_usser_id: string; + @RelationId((invite: Invite) => invite.target_user) + target_user_id: string; @JoinColumn({ name: "target_user_id" }) @ManyToOne(() => User, (user: User) => user.id) diff --git a/util/src/entities/Member.ts b/util/src/entities/Member.ts index c367755e..01634d9e 100644 --- a/util/src/entities/Member.ts +++ b/util/src/entities/Member.ts @@ -1,18 +1,18 @@ import { PublicUser, User } from "./User"; import { BaseClass } from "./BaseClass"; -import { Column, Entity, JoinColumn, ManyToOne } from "typeorm"; +import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { Guild } from "./Guild"; @Entity("members") export class Member extends BaseClass { - @Column() + @RelationId((member: Member) => member.user) user_id: string; @JoinColumn({ name: "user_id" }) @ManyToOne(() => User, (user: User) => user.id) user: User; - @Column() + @RelationId((member: Member) => member.guild) guild_id: string; @JoinColumn({ name: "guild_id" }) diff --git a/util/src/entities/Message.ts b/util/src/entities/Message.ts index 2c0918c7..9daf042c 100644 --- a/util/src/entities/Message.ts +++ b/util/src/entities/Message.ts @@ -4,7 +4,16 @@ import { Role } from "./Role"; import { Channel } from "./Channel"; import { InteractionType } from "../interfaces/Interaction"; import { Application } from "./Application"; -import { Column, CreateDateColumn, Entity, JoinColumn, ManyToMany, ManyToOne, UpdateDateColumn } from "typeorm"; +import { + Column, + CreateDateColumn, + Entity, + JoinColumn, + ManyToMany, + ManyToOne, + RelationId, + UpdateDateColumn, +} from "typeorm"; import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; import { Webhook } from "./Webhook"; @@ -34,42 +43,42 @@ export class Message extends BaseClass { @Column() id: string; - @Column() + @RelationId((message: Message) => message.channel) channel_id: string; @JoinColumn({ name: "channel_id" }) @ManyToOne(() => Channel, (channel: Channel) => channel.id) channel: Channel; - @Column() + @RelationId((message: Message) => message.guild) guild_id: string; @JoinColumn({ name: "guild_id" }) @ManyToOne(() => Guild, (guild: Guild) => guild.id) guild?: Guild; - @Column() + @RelationId((message: Message) => message.author) author_id: string; @JoinColumn({ name: "author_id" }) @ManyToOne(() => User, (user: User) => user.id) author?: User; - @Column() + @RelationId((message: Message) => message.member) member_id: string; @JoinColumn({ name: "member_id" }) @ManyToOne(() => Member, (member: Member) => member.id) member?: Member; - @Column() + @RelationId((message: Message) => message.webhook) webhook_id: string; @JoinColumn({ name: "webhook_id" }) @ManyToOne(() => Webhook, (webhook: Webhook) => webhook.id) webhook?: Webhook; - @Column() + @RelationId((message: Message) => message.application) application_id: string; @JoinColumn({ name: "application_id" }) @@ -93,21 +102,21 @@ export class Message extends BaseClass { @Column() mention_everyone?: boolean; - @Column("simple-array") + @RelationId((message: Message) => message.mention_users) mention_user_ids: string[]; @JoinColumn({ name: "mention_user_ids" }) @ManyToMany(() => User, (user: User) => user.id) mention_users: User[]; - @Column("simple-array") + @RelationId((message: Message) => message.mention_roles) mention_role_ids: string[]; @JoinColumn({ name: "mention_role_ids" }) @ManyToMany(() => Role, (role: Role) => role.id) mention_roles: Role[]; - @Column("simple-array") + @RelationId((message: Message) => message.mention_channels) mention_channel_ids: string[]; @JoinColumn({ name: "mention_channel_ids" }) diff --git a/util/src/entities/RateLimit.ts b/util/src/entities/RateLimit.ts index 374a0759..3ac35df3 100644 --- a/util/src/entities/RateLimit.ts +++ b/util/src/entities/RateLimit.ts @@ -1,4 +1,4 @@ -import { Column, Entity, JoinColumn, ManyToOne } from "typeorm"; +import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { User } from "./User"; @@ -7,7 +7,7 @@ export class RateLimit extends BaseClass { @Column() id: "global" | "error" | string; // channel_239842397 | guild_238927349823 | webhook_238923423498 - @Column() + @RelationId((rate_limit: RateLimit) => rate_limit.user) user_id: string; @JoinColumn({ name: "user_id" }) diff --git a/util/src/entities/ReadState.ts b/util/src/entities/ReadState.ts index 7c56b6c6..0310cb5f 100644 --- a/util/src/entities/ReadState.ts +++ b/util/src/entities/ReadState.ts @@ -1,4 +1,4 @@ -import { Column, Entity, JoinColumn, ManyToOne } from "typeorm"; +import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { Channel } from "./Channel"; import { Message } from "./Message"; @@ -6,20 +6,23 @@ import { User } from "./User"; @Entity("read_states") export class ReadState extends BaseClass { - @Column() + @RelationId((read_state: ReadState) => read_state.channel) channel_id: string; @JoinColumn({ name: "channel_id" }) @ManyToOne(() => Channel, (channel: Channel) => channel.id) channel: Channel; - @Column() + @RelationId((read_state: ReadState) => read_state.user) user_id: string; @JoinColumn({ name: "user_id" }) @ManyToOne(() => User, (user: User) => user.id) user: User; + @RelationId((read_state: ReadState) => read_state.last_message) + last_message_id: string; + @JoinColumn({ name: "last_message_id" }) @ManyToOne(() => Message, (message: Message) => message.id) last_message?: Message; diff --git a/util/src/entities/Relationship.ts b/util/src/entities/Relationship.ts index bd5861f0..3e1280c7 100644 --- a/util/src/entities/Relationship.ts +++ b/util/src/entities/Relationship.ts @@ -1,4 +1,4 @@ -import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from "typeorm"; +import { Column, Entity, JoinColumn, ManyToOne, OneToMany, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { User } from "./User"; @@ -11,7 +11,7 @@ export enum RelationshipType { @Entity("relationships") export class Relationship extends BaseClass { - @Column() + @RelationId((relationship: Relationship) => relationship.user) user_id: string; @JoinColumn({ name: "user_id" }) diff --git a/util/src/entities/Role.ts b/util/src/entities/Role.ts index 7bb144cc..e48fd293 100644 --- a/util/src/entities/Role.ts +++ b/util/src/entities/Role.ts @@ -1,10 +1,10 @@ -import { Column, Entity, JoinColumn, ManyToOne } from "typeorm"; +import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; @Entity("roles") export class Role extends BaseClass { - @Column() + @RelationId((role: Role) => role.guild) guild_id: string; @JoinColumn({ name: "guild_id" }) diff --git a/util/src/entities/Team.ts b/util/src/entities/Team.ts index 5e645650..fa1b0ed2 100644 --- a/util/src/entities/Team.ts +++ b/util/src/entities/Team.ts @@ -1,4 +1,4 @@ -import { Column, Entity, JoinColumn, ManyToMany, ManyToOne } from "typeorm"; +import { Column, Entity, JoinColumn, ManyToMany, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { TeamMember } from "./TeamMember"; import { User } from "./User"; @@ -8,7 +8,7 @@ export class Team extends BaseClass { @Column() icon?: string; - @Column("simple-array") + @RelationId((team: Team) => team.members) member_ids: string[]; @JoinColumn({ name: "member_ids" }) @@ -18,7 +18,7 @@ export class Team extends BaseClass { @Column() name: string; - @Column() + @RelationId((team: Team) => team.owner_user) owner_user_id: string; @JoinColumn({ name: "owner_user_id" }) diff --git a/util/src/entities/TeamMember.ts b/util/src/entities/TeamMember.ts index 2b1c76f1..f0b54c6f 100644 --- a/util/src/entities/TeamMember.ts +++ b/util/src/entities/TeamMember.ts @@ -1,4 +1,4 @@ -import { Column, Entity, JoinColumn, ManyToOne } from "typeorm"; +import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { User } from "./User"; @@ -15,14 +15,14 @@ export class TeamMember extends BaseClass { @Column("simple-array") permissions: string[]; - @Column() + @RelationId((member: TeamMember) => member.team) team_id: string; @JoinColumn({ name: "team_id" }) @ManyToOne(() => require("./Team").Team, (team: import("./Team").Team) => team.id) team: import("./Team").Team; - @Column() + @RelationId((member: TeamMember) => member.user) user_id: string; @JoinColumn({ name: "user_id" }) diff --git a/util/src/entities/Template.ts b/util/src/entities/Template.ts index 5c9a5120..c8d2034c 100644 --- a/util/src/entities/Template.ts +++ b/util/src/entities/Template.ts @@ -1,4 +1,4 @@ -import { Column, Entity, JoinColumn, ManyToOne } from "typeorm"; +import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; import { User } from "./User"; @@ -17,6 +17,9 @@ export class Template extends BaseClass { @Column() usage_count?: number; + @RelationId((template: Template) => template.creator) + creator_id: string; + @JoinColumn({ name: "creator_id" }) @ManyToOne(() => User, (user: User) => user.id) creator: User; @@ -27,6 +30,9 @@ export class Template extends BaseClass { @Column() updated_at: Date; + @RelationId((template: Template) => template.source_guild) + source_guild_id: string; + @JoinColumn({ name: "source_guild_id" }) @ManyToOne(() => Guild, (guild: Guild) => guild.id) source_guild: Guild; diff --git a/util/src/entities/User.ts b/util/src/entities/User.ts index 39e59da4..bdf0d35f 100644 --- a/util/src/entities/User.ts +++ b/util/src/entities/User.ts @@ -1,8 +1,10 @@ -import { Column, Entity, JoinColumn, OneToMany } from "typeorm"; +import { Column, Entity, JoinColumn, OneToMany, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { BitField } from "../util/BitField"; import { Relationship } from "./Relationship"; import { ConnectedAccount } from "./ConnectedAccount"; +import { HTTPError } from "lambert-server"; +import { Guild } from "./Guild"; export const PublicUserProjection = { username: true, @@ -24,6 +26,13 @@ export class User extends BaseClass { @Column() discriminator: string; // #0001 4 digit long string from #0001 - #9999 + setDiscriminator(val: string) { + const number = Number(val); + if (isNaN(number)) throw new Error("invalid discriminator"); + if (number > 0 && number < 10000) throw new Error("discriminator must be between 1 and 9999"); + this.discriminator = val; + } + @Column() avatar?: string; // hash of the user avatar @@ -84,17 +93,21 @@ export class User extends BaseClass { @Column({ type: "bigint" }) public_flags: bigint; - @Column("simple-array") // string in simple-array must not contain commas - guilds: string[]; // array of guild ids the user is part of + @RelationId((user: User) => user.guilds) + guild_ids: string[]; // array of guild ids the user is part of + + @JoinColumn({ name: "guild_ids" }) + @OneToMany(() => Guild, (guild: Guild) => guild.id) + guilds: Guild[]; - @Column("simple-array") // string in simple-array must not contain commas + @RelationId((user: User) => user.relationships) relationship_ids: string[]; // array of guild ids the user is part of @JoinColumn({ name: "relationship_ids" }) @OneToMany(() => User, (user: User) => user.id) relationships: Relationship[]; - @Column("simple-array") // string in simple-array must not contain commas + @RelationId((user: User) => user.connected_accounts) connected_account_ids: string[]; // array of guild ids the user is part of @JoinColumn({ name: "connected_account_ids" }) @@ -102,14 +115,28 @@ export class User extends BaseClass { connected_accounts: ConnectedAccount[]; @Column({ type: "simple-json", select: false }) - user_data: { + data: { valid_tokens_since: Date; // all tokens with a previous issue date are invalid hash: string; // hash of the password, salt is saved in password (bcrypt) - fingerprints: string[]; // array of fingerprints -> used to prevent multiple accounts }; + @Column({ type: "simple-array" }) + fingerprints: string[]; // array of fingerprints -> used to prevent multiple accounts + @Column("simple-json") settings: UserSettings; + + static async getPublicUser(user_id: string, additional_fields?: any) { + const user = await User.findOne( + { id: user_id }, + { + ...PublicUserProjection, + ...additional_fields, + } + ); + if (!user) throw new HTTPError("User not found", 404); + return user; + } } export interface UserSettings { diff --git a/util/src/entities/VoiceState.ts b/util/src/entities/VoiceState.ts index 2416c6c0..6707a575 100644 --- a/util/src/entities/VoiceState.ts +++ b/util/src/entities/VoiceState.ts @@ -1,4 +1,4 @@ -import { Column, Entity, JoinColumn, ManyToOne, OneToOne } from "typeorm"; +import { Column, Entity, JoinColumn, ManyToOne, OneToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { Channel } from "./Channel"; import { Guild } from "./Guild"; @@ -6,14 +6,23 @@ import { User } from "./User"; @Entity("voice_states") export class VoiceState extends BaseClass { + @RelationId((voice_state: VoiceState) => voice_state.guild) + guild_id: string; + @JoinColumn({ name: "guild_id" }) @ManyToOne(() => Guild, (guild: Guild) => guild.id) guild?: Guild; + @RelationId((voice_state: VoiceState) => voice_state.channel) + channel_id: string; + @JoinColumn({ name: "channel_id" }) @ManyToOne(() => Channel, (channel: Channel) => channel.id) channel: Channel; + @RelationId((voice_state: VoiceState) => voice_state.user) + user_id: string; + @JoinColumn({ name: "user_id" }) @ManyToOne(() => User, (user: User) => user.id) user: User; diff --git a/util/src/entities/Webhook.ts b/util/src/entities/Webhook.ts index 54233638..dc929c18 100644 --- a/util/src/entities/Webhook.ts +++ b/util/src/entities/Webhook.ts @@ -1,5 +1,9 @@ -import { Column, Entity, JoinColumn } from "typeorm"; +import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; +import { Application } from "./Application"; import { BaseClass } from "./BaseClass"; +import { Channel } from "./Channel"; +import { Guild } from "./Guild"; +import { User } from "./User"; export enum WebhookType { Incoming = 1, @@ -23,18 +27,38 @@ export class Webhook extends BaseClass { @Column() token?: string; - @JoinColumn() - guild?: string; + @RelationId((webhook: Webhook) => webhook.guild) + guild_id: string; - @JoinColumn() - channel: string; + @JoinColumn({ name: "guild_id" }) + @ManyToOne(() => Guild, (guild: Guild) => guild.id) + guild: Guild; - @JoinColumn() - application?: string; + @RelationId((webhook: Webhook) => webhook.channel) + channel_id: string; - @JoinColumn() - user?: string; + @JoinColumn({ name: "channel_id" }) + @ManyToOne(() => Channel, (channel: Channel) => channel.id) + channel: Channel; - @JoinColumn() - source_guild: string; + @RelationId((webhook: Webhook) => webhook.application) + application_id: string; + + @JoinColumn({ name: "application_id" }) + @ManyToOne(() => Application, (application: Application) => application.id) + application: Application; + + @RelationId((webhook: Webhook) => webhook.user) + user_id: string; + + @JoinColumn({ name: "user_id" }) + @ManyToOne(() => User, (user: User) => user.id) + user: User; + + @RelationId((webhook: Webhook) => webhook.guild) + source_guild_id: string; + + @JoinColumn({ name: "source_guild_id" }) + @ManyToOne(() => Guild, (guild: Guild) => guild.id) + source_guild: Guild; } diff --git a/util/src/entities/index.ts b/util/src/entities/index.ts index 9cb10016..b9e361c1 100644 --- a/util/src/entities/index.ts +++ b/util/src/entities/index.ts @@ -3,6 +3,7 @@ export * from "./AuditLog"; export * from "./Ban"; export * from "./BaseClass"; export * from "./Channel"; +export * from "./Config"; export * from "./ConnectedAccount"; export * from "./Emoji"; export * from "./Guild"; -- cgit 1.5.1 From ac84431cc2d85d2510a19c2726a6eb3d7ae3fc9c Mon Sep 17 00:00:00 2001 From: Flam3rboy <34555296+Flam3rboy@users.noreply.github.com> Date: Sun, 29 Aug 2021 16:58:37 +0200 Subject: fix util --- util/src/entities/Guild.ts | 2 +- util/src/entities/Message.ts | 4 ++-- util/src/entities/RateLimit.ts | 8 ++------ util/src/entities/Role.ts | 1 + util/src/entities/User.ts | 38 +++++++++++++++++++------------------- util/src/entities/index.ts | 1 + util/src/interfaces/Event.ts | 2 +- util/src/util/Config.ts | 4 +++- util/src/util/Database.ts | 12 +++++++----- util/src/util/checkToken.ts | 3 ++- 10 files changed, 39 insertions(+), 36 deletions(-) (limited to 'util/src/entities/RateLimit.ts') diff --git a/util/src/entities/Guild.ts b/util/src/entities/Guild.ts index 9ca4b1e4..e6a93824 100644 --- a/util/src/entities/Guild.ts +++ b/util/src/entities/Guild.ts @@ -158,7 +158,7 @@ export class Guild extends BaseClass { vanity_url_code?: string; @JoinColumn({ name: "vanity_url_code" }) - @OneToOne(() => Invite, (invite: Invite) => invite.code) + @ManyToOne(() => Invite) vanity_url?: Invite; @Column({ nullable: true }) diff --git a/util/src/entities/Message.ts b/util/src/entities/Message.ts index 0c41a2eb..43d0f9d0 100644 --- a/util/src/entities/Message.ts +++ b/util/src/entities/Message.ts @@ -148,8 +148,8 @@ export class Message extends BaseClass { party_id: string; }; - @Column({ type: "bigint", nullable: true }) - flags?: bigint; + @Column({ nullable: true }) + flags?: string; @RelationId((message: Message) => message.stickers) sticker_ids: string[]; diff --git a/util/src/entities/RateLimit.ts b/util/src/entities/RateLimit.ts index 3ac35df3..49af0416 100644 --- a/util/src/entities/RateLimit.ts +++ b/util/src/entities/RateLimit.ts @@ -7,12 +7,8 @@ export class RateLimit extends BaseClass { @Column() id: "global" | "error" | string; // channel_239842397 | guild_238927349823 | webhook_238923423498 - @RelationId((rate_limit: RateLimit) => rate_limit.user) - user_id: string; - - @JoinColumn({ name: "user_id" }) - @ManyToOne(() => User, (user) => user.id) - user: User; + @Column() // no relation as it also + executor_id: string; @Column() hits: number; diff --git a/util/src/entities/Role.ts b/util/src/entities/Role.ts index 7c6ce64e..ddae7e40 100644 --- a/util/src/entities/Role.ts +++ b/util/src/entities/Role.ts @@ -1,4 +1,5 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; + import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; diff --git a/util/src/entities/User.ts b/util/src/entities/User.ts index c5f870fa..73afba67 100644 --- a/util/src/entities/User.ts +++ b/util/src/entities/User.ts @@ -49,7 +49,7 @@ export class User extends BaseClass { avatar?: string; // hash of the user avatar @Column({ nullable: true }) - accent_color?: number = 0; // banner color of user + accent_color?: number; // banner color of user @Column({ nullable: true }) banner?: string; // hash of the user banner @@ -58,52 +58,52 @@ export class User extends BaseClass { phone?: string; // phone number of the user @Column() - desktop: boolean = false; // if the user has desktop app installed + desktop: boolean; // if the user has desktop app installed @Column() - mobile: boolean = false; // if the user has mobile app installed + mobile: boolean; // if the user has mobile app installed @Column() - premium: boolean = false; // if user bought nitro + premium: boolean; // if user bought nitro @Column() - premium_type: number = 0; // nitro level + premium_type: number; // nitro level @Column() - bot: boolean = false; // if user is bot + bot: boolean; // if user is bot @Column() - bio: string = ""; // short description of the user (max 190 chars -> should be configurable) + bio: string; // short description of the user (max 190 chars -> should be configurable) @Column() - system: boolean = false; // shouldn't be used, the api sents this field type true, if the generated message comes from a system generated author + system: boolean; // shouldn't be used, the api sents this field type true, if the generated message comes from a system generated author @Column() - nsfw_allowed: boolean = false; // if the user is older than 18 (resp. Config) + nsfw_allowed: boolean; // if the user is older than 18 (resp. Config) @Column() - mfa_enabled: boolean = false; // if multi factor authentication is enabled + mfa_enabled: boolean; // if multi factor authentication is enabled @Column() created_at: Date = new Date(); // registration date @Column() - verified: boolean = false; // if the user is offically verified + verified: boolean; // if the user is offically verified @Column() - disabled: boolean = false; // if the account is disabled + disabled: boolean; // if the account is disabled @Column() - deleted: boolean = false; // if the user was deleted + deleted: boolean; // if the user was deleted @Column({ nullable: true }) email?: string; // email of the user - @Column({ type: "bigint" }) - flags: bigint = BigInt(0); // UserFlags + @Column() + flags: string; // UserFlags - @Column({ type: "bigint" }) - public_flags: bigint = BigInt(0); + @Column() + public_flags: string; @RelationId((user: User) => user.relationships) relationship_ids: string[]; // array of guild ids the user is part of @@ -123,13 +123,13 @@ export class User extends BaseClass { data: { valid_tokens_since: Date; // all tokens with a previous issue date are invalid hash?: string; // hash of the password, salt is saved in password (bcrypt) - } = { valid_tokens_since: new Date() }; + }; @Column({ type: "simple-array" }) fingerprints: string[] = []; // array of fingerprints -> used to prevent multiple accounts @Column({ type: "simple-json" }) - settings: UserSettings = defaultSettings; + settings: UserSettings; static async getPublicUser(user_id: string, opts?: FindOneOptions) { const user = await User.findOne(user_id, { diff --git a/util/src/entities/index.ts b/util/src/entities/index.ts index b9e361c1..e0246a10 100644 --- a/util/src/entities/index.ts +++ b/util/src/entities/index.ts @@ -14,6 +14,7 @@ export * from "./RateLimit"; export * from "./ReadState"; export * from "./Relationship"; export * from "./Role"; +export * from "./Sticker"; export * from "./Team"; export * from "./TeamMember"; export * from "./Template"; diff --git a/util/src/interfaces/Event.ts b/util/src/interfaces/Event.ts index bab6f4dc..e855095c 100644 --- a/util/src/interfaces/Event.ts +++ b/util/src/interfaces/Event.ts @@ -515,4 +515,4 @@ export type EVENT = | "RELATIONSHIP_REMOVE" | CUSTOMEVENTS; -export type CUSTOMEVENTS = "INVALIDATED"; +export type CUSTOMEVENTS = "INVALIDATED" | "RATELIMIT"; diff --git a/util/src/util/Config.ts b/util/src/util/Config.ts index f8574f38..f16921bd 100644 --- a/util/src/util/Config.ts +++ b/util/src/util/Config.ts @@ -6,6 +6,7 @@ var config: ConfigEntity; export const Config = { init: async function init() { + if (config) return config; config = new ConfigEntity({}, { id: "0" }); return this.set((config.value || {}).merge(DefaultConfigOptions)); }, @@ -13,7 +14,8 @@ export const Config = { return config.value as ConfigValue; }, set: function set(val: any) { - config.value = val.merge(config.value); + if (!config) return; + config.value = val.merge(config?.value || {}); return config.save(); }, }; diff --git a/util/src/util/Database.ts b/util/src/util/Database.ts index f49fb04c..c22d8abd 100644 --- a/util/src/util/Database.ts +++ b/util/src/util/Database.ts @@ -1,5 +1,5 @@ import "reflect-metadata"; -import { Connection, createConnection } from "typeorm"; +import { Connection, createConnection, ValueTransformer } from "typeorm"; import * as Models from "../entities"; // UUID extension option is only supported with postgres @@ -14,10 +14,10 @@ export function initDatabase() { console.log("[Database] connecting ..."); // @ts-ignore promise = createConnection({ - // type: "sqlite", - // database: "database.db", - type: "postgres", - url: "postgres://fosscord:wb94SmuURM2Syv&@localhost/fosscord", + type: "sqlite", + database: "database.db", + // type: "postgres", + // url: "postgres://fosscord:wb94SmuURM2Syv&@localhost/fosscord", // entities: Object.values(Models).filter((x) => x.constructor.name !== "Object"), synchronize: true, @@ -25,6 +25,8 @@ export function initDatabase() { cache: { duration: 1000 * 3, // cache all find queries for 3 seconds }, + bigNumberStrings: false, + supportBigNumbers: true, }); promise.then((connection) => { diff --git a/util/src/util/checkToken.ts b/util/src/util/checkToken.ts index 1e203006..8415e8c0 100644 --- a/util/src/util/checkToken.ts +++ b/util/src/util/checkToken.ts @@ -12,7 +12,8 @@ export function checkToken(token: string, jwtSecret: string): Promise { const user = await User.findOne({ id: decoded.id }, { select: ["data", "bot", "disabled", "deleted"] }); if (!user) return rej("Invalid Token"); // we need to round it to seconds as it saved as seconds in jwt iat and valid_tokens_since is stored in milliseconds - if (decoded.iat * 1000 < user.data.valid_tokens_since.setSeconds(0, 0)) return rej("Invalid Token"); + if (decoded.iat * 1000 < new Date(user.data.valid_tokens_since).setSeconds(0, 0)) + return rej("Invalid Token"); if (user.disabled) return rej("User disabled"); if (user.deleted) return rej("User not found"); -- cgit 1.5.1 From 954700b2d5c4090fdf9d7d25beef3d6529afa8d3 Mon Sep 17 00:00:00 2001 From: Flam3rboy <34555296+Flam3rboy@users.noreply.github.com> Date: Mon, 30 Aug 2021 12:14:32 +0200 Subject: :zap: only local rate limit to prevent to much pressure on the database --- api/src/middlewares/RateLimit.ts | 70 +++++++++++++++++++++++++++++----------- util/src/entities/RateLimit.ts | 3 +- 2 files changed, 52 insertions(+), 21 deletions(-) (limited to 'util/src/entities/RateLimit.ts') diff --git a/api/src/middlewares/RateLimit.ts b/api/src/middlewares/RateLimit.ts index ed6b951a..dffbc0d9 100644 --- a/api/src/middlewares/RateLimit.ts +++ b/api/src/middlewares/RateLimit.ts @@ -1,11 +1,12 @@ -import { Config, listenEvent, emitEvent, RateLimit } from "@fosscord/util"; +import { Config, listenEvent } from "@fosscord/util"; import { NextFunction, Request, Response, Router } from "express"; -import { LessThan, MoreThan } from "typeorm"; import { getIpAdress } from "../util/ipAddress"; import { API_PREFIX_TRAILING_SLASH } from "./Authentication"; // Docs: https://discord.com/developers/docs/topics/rate-limits +// TODO: use better caching (e.g. redis) as else it creates to much pressure on the database + /* ? bucket limit? Max actions/sec per bucket? @@ -18,6 +19,14 @@ TODO: different for methods (GET/POST) */ +type RateLimit = { + id: "global" | "error" | string; + executor_id: string; + hits: number; + blocked: boolean; + expires_at: Date; +}; + var Cache = new Map(); const EventRateLimit = "RATELIMIT"; @@ -46,13 +55,22 @@ export default function rateLimit(opts: { const offender = Cache.get(executor_id + bucket_id); - if (offender && offender.blocked) { + if (offender) { const reset = offender.expires_at.getTime(); const resetAfterMs = reset - Date.now(); const resetAfterSec = resetAfterMs / 1000; - const global = bucket_id === "global"; - if (resetAfterMs > 0) { + if (resetAfterMs <= 0) { + offender.hits = 0; + offender.expires_at = new Date(Date.now() + opts.window * 1000); + offender.blocked = false; + + Cache.delete(executor_id + bucket_id); + } + + if (offender.blocked) { + const global = bucket_id === "global"; + console.log("blocked bucket: " + bucket_id, { resetAfterMs }); return ( res @@ -67,15 +85,9 @@ export default function rateLimit(opts: { // TODO: error rate limit message translation .send({ message: "You are being rate limited.", retry_after: resetAfterSec, global }) ); - } else { - offender.hits = 0; - offender.expires_at = new Date(Date.now() + opts.window * 1000); - offender.blocked = false; - // mongodb ttl didn't update yet -> manually update/delete - RateLimit.delete({ id: bucket_id, executor_id }); - Cache.delete(executor_id + bucket_id); } } + next(); const hitRouteOpts = { bucket_id, executor_id, max_hits, window: opts.window }; @@ -100,20 +112,20 @@ export async function initRateLimits(app: Router) { Cache.set(event.channel_id as string, event.data); event.acknowledge?.(); }); - await RateLimit.delete({ expires_at: MoreThan(new Date()) }); // cleans up if not already deleted, morethan -> older date - const limits = await RateLimit.find({ blocked: true }); - limits.forEach((limit) => { - Cache.set(limit.executor_id, limit); - }); + // await RateLimit.delete({ expires_at: LessThan(new Date().toISOString()) }); // cleans up if not already deleted, morethan -> older date + // const limits = await RateLimit.find({ blocked: true }); + // limits.forEach((limit) => { + // Cache.set(limit.executor_id, limit); + // }); setInterval(() => { Cache.forEach((x, key) => { if (new Date() > x.expires_at) { Cache.delete(key); - RateLimit.delete({ executor_id: key }); + // RateLimit.delete({ executor_id: key }); } }); - }, 1000 * 60 * 10); + }, 1000 * 60); app.use( rateLimit({ @@ -139,6 +151,25 @@ export async function initRateLimits(app: Router) { } async function hitRoute(opts: { executor_id: string; bucket_id: string; max_hits: number; window: number }) { + const id = opts.executor_id + opts.bucket_id; + var limit = Cache.get(id); + if (!limit) { + limit = { + id: opts.bucket_id, + executor_id: opts.executor_id, + expires_at: new Date(Date.now() + opts.window * 1000), + hits: 0, + blocked: false + }; + Cache.set(id, limit); + } + + limit.hits++; + if (limit.hits >= opts.max_hits) { + limit.blocked = true; + } + + /* var ratelimit = await RateLimit.findOne({ id: opts.bucket_id, executor_id: opts.executor_id }); if (!ratelimit) { ratelimit = new RateLimit({ @@ -167,4 +198,5 @@ async function hitRoute(opts: { executor_id: string; bucket_id: string; max_hits } await ratelimit.save(); + */ } diff --git a/util/src/entities/RateLimit.ts b/util/src/entities/RateLimit.ts index 49af0416..fa9c32c1 100644 --- a/util/src/entities/RateLimit.ts +++ b/util/src/entities/RateLimit.ts @@ -1,6 +1,5 @@ -import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; +import { Column, Entity } from "typeorm"; import { BaseClass } from "./BaseClass"; -import { User } from "./User"; @Entity("rate_limits") export class RateLimit extends BaseClass { -- cgit 1.5.1