diff --git a/src/util/entities/Config.ts b/src/util/entities/Config.ts
new file mode 100644
index 00000000..9aabc1a8
--- /dev/null
+++ b/src/util/entities/Config.ts
@@ -0,0 +1,416 @@
+import { Column, Entity } from "typeorm";
+import { BaseClassWithoutId, PrimaryIdColumn } from "./BaseClass";
+import crypto from "crypto";
+import { Snowflake } from "../util/Snowflake";
+import { SessionsReplace } from "..";
+import { hostname } from "os";
+import { Rights } from "../util/Rights";
+
+@Entity("config")
+export class ConfigEntity extends BaseClassWithoutId {
+ @PrimaryIdColumn()
+ key: string;
+
+ @Column({ type: "simple-json", nullable: true })
+ value: number | boolean | null | string | undefined;
+}
+
+export interface RateLimitOptions {
+ bot?: number;
+ count: number;
+ window: number;
+ onyIp?: boolean;
+}
+
+export interface Region {
+ id: string;
+ name: string;
+ endpoint: string;
+ location?: {
+ latitude: number;
+ longitude: number;
+ };
+ vip: boolean;
+ custom: boolean;
+ deprecated: boolean;
+}
+
+export interface KafkaBroker {
+ ip: string;
+ port: number;
+}
+
+export interface ConfigValue {
+ gateway: {
+ endpointClient: string | null;
+ endpointPrivate: string | null;
+ endpointPublic: string | null;
+ };
+ cdn: {
+ endpointClient: string | null;
+ endpointPublic: string | null;
+ endpointPrivate: string | null;
+ resizeHeightMax: number | null;
+ resizeWidthMax: number | null;
+ };
+ api: {
+ defaultVersion: string;
+ activeVersions: string[];
+ useFosscordEnhancements: boolean;
+ };
+ general: {
+ instanceName: string;
+ instanceDescription: string | null;
+ frontPage: string | null;
+ tosPage: string | null;
+ correspondenceEmail: string | null;
+ correspondenceUserID: string | null;
+ image: string | null;
+ instanceId: string;
+ };
+ limits: {
+ user: {
+ maxGuilds: number;
+ maxUsername: number;
+ maxFriends: number;
+ };
+ guild: {
+ maxRoles: number;
+ maxEmojis: number;
+ maxMembers: number;
+ maxChannels: number;
+ maxChannelsInCategory: number;
+ hideOfflineMember: number;
+ };
+ message: {
+ maxCharacters: number;
+ maxTTSCharacters: number;
+ maxReactions: number;
+ maxAttachmentSize: number;
+ maxBulkDelete: number;
+ maxEmbedDownloadSize: number;
+ };
+ channel: {
+ maxPins: number;
+ maxTopic: number;
+ maxWebhooks: number;
+ };
+ rate: {
+ disabled: boolean;
+ ip: Omit<RateLimitOptions, "bot_count">;
+ 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;
+ defaultRights: string;
+ };
+ login: {
+ requireCaptcha: boolean;
+ };
+ register: {
+ email: {
+ required: boolean;
+ allowlist: boolean;
+ blocklist: boolean;
+ domains: string[];
+ };
+ dateOfBirth: {
+ required: boolean;
+ minimum: number; // in years
+ };
+ disabled: boolean;
+ requireCaptcha: boolean;
+ requireInvite: boolean;
+ guestsRequireInvite: boolean;
+ allowNewRegistration: boolean;
+ allowMultipleAccounts: boolean;
+ blockProxies: boolean;
+ password: {
+ required: boolean;
+ minLength: number;
+ minNumbers: number;
+ minUpperCase: number;
+ minSymbols: number;
+ };
+ incrementingDiscriminators: boolean; // random otherwise
+ };
+ regions: {
+ default: string;
+ useDefaultAsOptimal: boolean;
+ available: Region[];
+ };
+ guild: {
+ discovery: {
+ showAllGuilds: boolean;
+ useRecommendation: boolean; // TODO: Recommendation, privacy concern?
+ offset: number;
+ limit: number;
+ };
+ autoJoin: {
+ enabled: boolean;
+ guilds: string[];
+ canLeave: boolean;
+ };
+ defaultFeatures: string[];
+ };
+ gif: {
+ enabled: boolean;
+ provider: "tenor"; // more coming soon
+ apiKey?: string;
+ };
+ rabbitmq: {
+ host: string | null;
+ };
+ kafka: {
+ brokers: KafkaBroker[] | null;
+ };
+ templates: {
+ enabled: Boolean;
+ allowTemplateCreation: Boolean;
+ allowDiscordTemplates: Boolean;
+ allowRaws: Boolean;
+ },
+ client: {
+ useTestClient: Boolean;
+ releases: {
+ useLocalRelease: Boolean; //TODO
+ upstreamVersion: string;
+ };
+ },
+ metrics: {
+ timeout: number;
+ },
+ sentry: {
+ enabled: boolean;
+ endpoint: string;
+ traceSampleRate: number;
+ environment: string;
+ };
+}
+
+export const DefaultConfigOptions: ConfigValue = {
+ gateway: {
+ endpointClient: null,
+ endpointPrivate: null,
+ endpointPublic: null,
+ },
+ cdn: {
+ endpointClient: null,
+ endpointPrivate: null,
+ endpointPublic: null,
+ resizeHeightMax: 1000,
+ resizeWidthMax: 1000,
+ },
+ api: {
+ defaultVersion: "9",
+ activeVersions: ["6", "7", "8", "9"],
+ useFosscordEnhancements: true,
+ },
+ general: {
+ instanceName: "Fosscord Instance",
+ instanceDescription: "This is a Fosscord instance made in pre-release days",
+ frontPage: null,
+ tosPage: null,
+ correspondenceEmail: "noreply@localhost.local",
+ correspondenceUserID: null,
+ image: null,
+ instanceId: Snowflake.generate(),
+ },
+ limits: {
+ user: {
+ maxGuilds: 1048576,
+ maxUsername: 127,
+ maxFriends: 5000,
+ },
+ guild: {
+ maxRoles: 1000,
+ maxEmojis: 2000,
+ maxMembers: 25000000,
+ maxChannels: 65535,
+ maxChannelsInCategory: 65535,
+ hideOfflineMember: 3,
+ },
+ message: {
+ maxCharacters: 1048576,
+ maxTTSCharacters: 160,
+ maxReactions: 2048,
+ maxAttachmentSize: 1024 * 1024 * 1024,
+ maxEmbedDownloadSize: 1024 * 1024 * 5,
+ maxBulkDelete: 1000,
+ },
+ channel: {
+ maxPins: 500,
+ maxTopic: 1024,
+ maxWebhooks: 100,
+ },
+ rate: {
+ disabled: true,
+ ip: {
+ count: 500,
+ window: 5,
+ },
+ global: {
+ count: 250,
+ window: 5,
+ },
+ error: {
+ count: 10,
+ window: 5,
+ },
+ routes: {
+ guild: {
+ count: 5,
+ window: 5,
+ },
+ webhook: {
+ count: 10,
+ window: 5,
+ },
+ channel: {
+ count: 10,
+ window: 5,
+ },
+ 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",
+ defaultRights: "30644591655936", // See util/scripts/rights.js
+ },
+ login: {
+ requireCaptcha: false,
+ },
+ register: {
+ email: {
+ required: false,
+ allowlist: false,
+ blocklist: true,
+ domains: [], // TODO: efficiently save domain blocklist in database
+ // domains: fs.readFileSync(__dirname + "/blockedEmailDomains.txt", { encoding: "utf8" }).split("\n"),
+ },
+ dateOfBirth: {
+ required: true,
+ minimum: 13,
+ },
+ disabled: false,
+ requireInvite: false,
+ guestsRequireInvite: true,
+ requireCaptcha: true,
+ allowNewRegistration: true,
+ allowMultipleAccounts: true,
+ blockProxies: true,
+ password: {
+ required: false,
+ minLength: 8,
+ minNumbers: 2,
+ minUpperCase: 2,
+ minSymbols: 0,
+ },
+ incrementingDiscriminators: false,
+ },
+ regions: {
+ default: "fosscord",
+ useDefaultAsOptimal: true,
+ available: [
+ {
+ id: "fosscord",
+ name: "Fosscord",
+ endpoint: "127.0.0.1:3004",
+ vip: false,
+ custom: false,
+ deprecated: false,
+ },
+ ],
+ },
+ guild: {
+ discovery: {
+ showAllGuilds: false,
+ useRecommendation: false,
+ offset: 0,
+ limit: 24,
+ },
+ autoJoin: {
+ enabled: true,
+ canLeave: true,
+ guilds: [],
+ },
+ defaultFeatures: [],
+ },
+ gif: {
+ enabled: true,
+ provider: "tenor",
+ apiKey: "LIVDSRZULELA",
+ },
+ rabbitmq: {
+ host: null,
+ },
+ kafka: {
+ brokers: null,
+ },
+ templates: {
+ enabled: true,
+ allowTemplateCreation: true,
+ allowDiscordTemplates: true,
+ allowRaws: false
+ },
+ client: {
+ useTestClient: true,
+ releases: {
+ useLocalRelease: true,
+ upstreamVersion: "0.0.264"
+ }
+ },
+ metrics: {
+ timeout: 30000
+ },
+ sentry: {
+ enabled: false,
+ endpoint: "https://05e8e3d005f34b7d97e920ae5870a5e5@sentry.thearcanebrony.net/6",
+ traceSampleRate: 1.0,
+ environment: hostname()
+ }
+};
\ No newline at end of file
|