summary refs log tree commit diff
path: root/util/src
diff options
context:
space:
mode:
authorMadeline <46743919+MaddyUnderStars@users.noreply.github.com>2022-08-22 22:18:59 +1000
committerMadeline <46743919+MaddyUnderStars@users.noreply.github.com>2022-08-22 22:18:59 +1000
commit0cd9a46eea260c299db2e2983f7214ab8b119d29 (patch)
tree5fbb98e7adcfeab81594732089474afdde5893f9 /util/src
parentMerge branch 'master' into feat/captchaVerify (diff)
parentMerge remote-tracking branch 'Puyodead1/patch/prettier-config' into staging (diff)
downloadserver-0cd9a46eea260c299db2e2983f7214ab8b119d29.tar.xz
Merge remote-tracking branch 'upstream/staging' into feat/captchaVerify
Diffstat (limited to '')
-rw-r--r--src/util/dtos/DmChannelDTO.ts (renamed from util/src/dtos/DmChannelDTO.ts)0
-rw-r--r--src/util/dtos/UserDTO.ts (renamed from util/src/dtos/UserDTO.ts)0
-rw-r--r--src/util/dtos/index.ts (renamed from util/src/dtos/index.ts)0
-rw-r--r--src/util/entities/Application.ts (renamed from util/src/entities/Application.ts)115
-rw-r--r--src/util/entities/Attachment.ts (renamed from util/src/entities/Attachment.ts)0
-rw-r--r--src/util/entities/AuditLog.ts (renamed from util/src/entities/AuditLog.ts)0
-rw-r--r--src/util/entities/BackupCodes.ts (renamed from util/src/entities/BackupCodes.ts)16
-rw-r--r--src/util/entities/Ban.ts (renamed from util/src/entities/Ban.ts)0
-rw-r--r--src/util/entities/Categories.ts (renamed from util/src/entities/Categories.ts)0
-rw-r--r--src/util/entities/Channel.ts (renamed from util/src/entities/Channel.ts)71
-rw-r--r--src/util/entities/ClientRelease.ts (renamed from util/src/entities/ClientRelease.ts)0
-rw-r--r--src/util/entities/ConnectedAccount.ts (renamed from util/src/entities/ConnectedAccount.ts)0
-rw-r--r--src/util/entities/Emoji.ts (renamed from util/src/entities/Emoji.ts)0
-rw-r--r--src/util/entities/Encryption.ts (renamed from util/src/entities/Encryption.ts)2
-rw-r--r--src/util/entities/Group.ts (renamed from util/src/entities/Group.ts)0
-rw-r--r--src/util/entities/Guild.ts (renamed from util/src/entities/Guild.ts)39
-rw-r--r--src/util/entities/Invite.ts (renamed from util/src/entities/Invite.ts)15
-rw-r--r--src/util/entities/Member.ts (renamed from util/src/entities/Member.ts)44
-rw-r--r--src/util/entities/Message.ts (renamed from util/src/entities/Message.ts)1
-rw-r--r--src/util/entities/Migration.ts (renamed from util/src/entities/Migration.ts)0
-rw-r--r--src/util/entities/Note.ts (renamed from util/src/entities/Note.ts)0
-rw-r--r--src/util/entities/RateLimit.ts (renamed from util/src/entities/RateLimit.ts)0
-rw-r--r--src/util/entities/ReadState.ts (renamed from util/src/entities/ReadState.ts)0
-rw-r--r--src/util/entities/Recipient.ts (renamed from util/src/entities/Recipient.ts)0
-rw-r--r--src/util/entities/Relationship.ts (renamed from util/src/entities/Relationship.ts)0
-rw-r--r--src/util/entities/Role.ts (renamed from util/src/entities/Role.ts)0
-rw-r--r--src/util/entities/Session.ts (renamed from util/src/entities/Session.ts)0
-rw-r--r--src/util/entities/Sticker.ts (renamed from util/src/entities/Sticker.ts)0
-rw-r--r--src/util/entities/StickerPack.ts (renamed from util/src/entities/StickerPack.ts)0
-rw-r--r--src/util/entities/Team.ts (renamed from util/src/entities/Team.ts)0
-rw-r--r--src/util/entities/TeamMember.ts (renamed from util/src/entities/TeamMember.ts)0
-rw-r--r--src/util/entities/Template.ts (renamed from util/src/entities/Template.ts)0
-rw-r--r--src/util/entities/User.ts (renamed from util/src/entities/User.ts)193
-rw-r--r--src/util/entities/UserGroup.ts (renamed from util/src/entities/UserGroup.ts)0
-rw-r--r--src/util/entities/VoiceState.ts (renamed from util/src/entities/VoiceState.ts)0
-rw-r--r--src/util/entities/Webhook.ts (renamed from util/src/entities/Webhook.ts)0
-rw-r--r--src/util/entities/index.ts (renamed from util/src/entities/index.ts)1
-rw-r--r--src/util/index.ts (renamed from util/src/index.ts)3
-rw-r--r--src/util/interfaces/Activity.ts (renamed from util/src/interfaces/Activity.ts)0
-rw-r--r--src/util/interfaces/Event.ts (renamed from util/src/interfaces/Event.ts)6
-rw-r--r--src/util/interfaces/Interaction.ts (renamed from util/src/interfaces/Interaction.ts)0
-rw-r--r--src/util/interfaces/Presence.ts (renamed from util/src/interfaces/Presence.ts)0
-rw-r--r--src/util/interfaces/Status.ts (renamed from util/src/interfaces/Status.ts)0
-rw-r--r--src/util/interfaces/index.ts (renamed from util/src/interfaces/index.ts)0
-rw-r--r--src/util/util/ApiError.ts (renamed from util/src/util/ApiError.ts)0
-rw-r--r--src/util/util/Array.ts (renamed from util/src/util/Array.ts)0
-rw-r--r--src/util/util/AutoUpdate.ts (renamed from util/src/util/AutoUpdate.ts)5
-rw-r--r--src/util/util/BitField.ts (renamed from util/src/util/BitField.ts)3
-rw-r--r--src/util/util/Categories.ts (renamed from util/src/util/Categories.ts)0
-rw-r--r--src/util/util/Config.ts (renamed from util/src/util/Config.ts)45
-rw-r--r--src/util/util/Constants.ts (renamed from util/src/util/Constants.ts)0
-rw-r--r--src/util/util/Email.ts (renamed from util/src/util/Email.ts)0
-rw-r--r--src/util/util/Event.ts (renamed from util/src/util/Event.ts)4
-rw-r--r--src/util/util/FieldError.ts (renamed from util/src/util/FieldError.ts)2
-rw-r--r--src/util/util/Intents.ts (renamed from util/src/util/Intents.ts)0
-rw-r--r--src/util/util/InvisibleCharacters.ts (renamed from util/src/util/InvisibleCharacters.ts)0
-rw-r--r--src/util/util/MessageFlags.ts (renamed from util/src/util/MessageFlags.ts)0
-rw-r--r--src/util/util/Permissions.ts (renamed from util/src/util/Permissions.ts)22
-rw-r--r--src/util/util/RabbitMQ.ts (renamed from util/src/util/RabbitMQ.ts)0
-rw-r--r--src/util/util/Regex.ts (renamed from util/src/util/Regex.ts)0
-rw-r--r--src/util/util/Rights.ts (renamed from util/src/util/Rights.ts)13
-rw-r--r--src/util/util/Snowflake.ts (renamed from util/src/util/Snowflake.ts)8
-rw-r--r--src/util/util/String.ts (renamed from util/src/util/String.ts)0
-rw-r--r--src/util/util/Token.ts (renamed from util/src/util/Token.ts)8
-rw-r--r--src/util/util/TraverseDirectory.ts (renamed from util/src/util/TraverseDirectory.ts)0
-rw-r--r--src/util/util/cdn.ts (renamed from util/src/util/cdn.ts)5
-rw-r--r--src/util/util/index.ts (renamed from util/src/util/index.ts)6
-rw-r--r--util/src/entities/BaseClass.ts75
-rw-r--r--util/src/entities/Config.ts413
-rw-r--r--util/src/migrations/1633864260873-EmojiRoles.ts13
-rw-r--r--util/src/migrations/1633864669243-EmojiUser.ts23
-rw-r--r--util/src/migrations/1633881705509-VanityInvite.ts19
-rw-r--r--util/src/migrations/1634308884591-Stickers.ts66
-rw-r--r--util/src/migrations/1634424361103-Presence.ts11
-rw-r--r--util/src/migrations/1634426540271-MigrationTimestamp.ts15
-rw-r--r--util/src/migrations/1648643945733-ReleaseTypo.ts16
-rw-r--r--util/src/util/Database.ts72
77 files changed, 302 insertions, 1048 deletions
diff --git a/util/src/dtos/DmChannelDTO.ts b/src/util/dtos/DmChannelDTO.ts

index 226b2f9d..226b2f9d 100644 --- a/util/src/dtos/DmChannelDTO.ts +++ b/src/util/dtos/DmChannelDTO.ts
diff --git a/util/src/dtos/UserDTO.ts b/src/util/dtos/UserDTO.ts
index ee2752a4..ee2752a4 100644 --- a/util/src/dtos/UserDTO.ts +++ b/src/util/dtos/UserDTO.ts
diff --git a/util/src/dtos/index.ts b/src/util/dtos/index.ts
index 0e8f8459..0e8f8459 100644 --- a/util/src/dtos/index.ts +++ b/src/util/dtos/index.ts
diff --git a/util/src/entities/Application.ts b/src/util/entities/Application.ts
index fab3d93f..103f8e84 100644 --- a/util/src/entities/Application.ts +++ b/src/util/entities/Application.ts
@@ -1,4 +1,4 @@ -import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; +import { Column, Entity, JoinColumn, ManyToOne, OneToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; import { Team } from "./Team"; @@ -8,21 +8,77 @@ import { User } from "./User"; export class Application extends BaseClass { @Column() name: string; - + @Column({ nullable: true }) icon?: string; - - @Column() + + @Column({ nullable: true }) description: string; - - @Column({ type: "simple-array", nullable: true }) - rpc_origins?: string[]; - + + @Column({ nullable: true }) + summary: string = ""; + + @Column({ type: "simple-json", nullable: true }) + type?: any; + @Column() - bot_public: boolean; - + hook: boolean = true; + + @Column() + bot_public?: boolean = true; + + @Column() + bot_require_code_grant?: boolean = false; + @Column() - bot_require_code_grant: boolean; + verify_key: string; + + @JoinColumn({ name: "owner_id" }) + @ManyToOne(() => User) + owner: User; + + @Column() + flags: number = 0; + + @Column({ type: "simple-array", nullable: true }) + redirect_uris: string[] = []; + + @Column({ nullable: true }) + rpc_application_state: number = 0; + + @Column({ nullable: true }) + store_application_state: number = 1; + + @Column({ nullable: true }) + verification_state: number = 1; + + @Column({ nullable: true }) + interactions_endpoint_url?: string; + + @Column({ nullable: true }) + integration_public: boolean = true; + + @Column({ nullable: true }) + integration_require_code_grant: boolean = false; + + @Column({ nullable: true }) + discoverability_state: number = 1; + + @Column({ nullable: true }) + discovery_eligibility_flags: number = 2240; + + @JoinColumn({ name: "bot_user_id" }) + @OneToOne(() => User) + bot?: User; + + @Column({ type: "simple-array", nullable: true }) + tags?: string[]; + + @Column({ nullable: true }) + cover_image?: string; // the application's default rich presence invite cover image hash + + @Column({ type: "simple-json", nullable: true }) + install_params?: {scopes: string[], permissions: string}; @Column({ nullable: true }) terms_of_service_url?: string; @@ -30,38 +86,29 @@ export class Application extends BaseClass { @Column({ nullable: true }) privacy_policy_url?: string; - @JoinColumn({ name: "owner_id" }) - @ManyToOne(() => User) - owner?: User; + //just for us - @Column({ nullable: true }) - summary?: string; + //@Column({ type: "simple-array", nullable: true }) + //rpc_origins?: string[]; + + //@JoinColumn({ name: "guild_id" }) + //@ManyToOne(() => Guild) + //guild?: Guild; // if this application is a game sold, this field will be the guild to which it has been linked - @Column() - verify_key: string; + //@Column({ nullable: true }) + //primary_sku_id?: string; // if this application is a game sold, this field will be the id of the "Game SKU" that is created, + + //@Column({ nullable: true }) + //slug?: string; // if this application is a game sold, this field will be the URL slug that links to the store page @JoinColumn({ name: "team_id" }) @ManyToOne(() => Team, { onDelete: "CASCADE", + nullable: true }) team?: Team; - @JoinColumn({ name: "guild_id" }) - @ManyToOne(() => Guild) - guild: Guild; // if this application is a game sold, this field will be the guild to which it has been linked - - @Column({ nullable: true }) - primary_sku_id?: string; // if this application is a game sold, this field will be the id of the "Game SKU" that is created, - - @Column({ nullable: true }) - slug?: string; // if this application is a game sold, this field will be the URL slug that links to the store page - - @Column({ nullable: true }) - cover_image?: string; // the application's default rich presence invite cover image hash - - @Column() - flags: string; // the application's public flags -} + } export interface ApplicationCommand { id: string; diff --git a/util/src/entities/Attachment.ts b/src/util/entities/Attachment.ts
index 7b4b17eb..7b4b17eb 100644 --- a/util/src/entities/Attachment.ts +++ b/src/util/entities/Attachment.ts
diff --git a/util/src/entities/AuditLog.ts b/src/util/entities/AuditLog.ts
index b003e7ba..b003e7ba 100644 --- a/util/src/entities/AuditLog.ts +++ b/src/util/entities/AuditLog.ts
diff --git a/util/src/entities/BackupCodes.ts b/src/util/entities/BackupCodes.ts
index d532a39a..9092c14e 100644 --- a/util/src/entities/BackupCodes.ts +++ b/src/util/entities/BackupCodes.ts
@@ -1,7 +1,6 @@ import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { User } from "./User"; -import crypto from "crypto"; @Entity("backup_codes") export class BackupCode extends BaseClass { @@ -17,19 +16,4 @@ export class BackupCode extends BaseClass { @Column() expired: boolean; -} - -export function generateMfaBackupCodes(user_id: string) { - let backup_codes: BackupCode[] = []; - for (let i = 0; i < 10; i++) { - const code = BackupCode.create({ - user: { id: user_id }, - code: crypto.randomBytes(4).toString("hex"), // 8 characters - consumed: false, - expired: false, - }); - backup_codes.push(code); - } - - return backup_codes; } \ No newline at end of file diff --git a/util/src/entities/Ban.ts b/src/util/entities/Ban.ts
index 9504bd8e..9504bd8e 100644 --- a/util/src/entities/Ban.ts +++ b/src/util/entities/Ban.ts
diff --git a/util/src/entities/Categories.ts b/src/util/entities/Categories.ts
index 81fbc303..81fbc303 100644 --- a/util/src/entities/Categories.ts +++ b/src/util/entities/Categories.ts
diff --git a/util/src/entities/Channel.ts b/src/util/entities/Channel.ts
index 69c08be7..a576d7af 100644 --- a/util/src/entities/Channel.ts +++ b/src/util/entities/Channel.ts
@@ -1,8 +1,9 @@ import { Column, Entity, JoinColumn, ManyToOne, OneToMany, RelationId } from "typeorm"; +import { OrmUtils } from "../util/imports/OrmUtils"; import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; import { PublicUserProjection, User } from "./User"; -import { HTTPError } from "lambert-server"; +import { HTTPError } from "../util/imports/HTTPError"; import { containsAll, emitEvent, getPermission, Snowflake, trimSpecial, InvisibleCharacters } from "../util"; import { ChannelCreateEvent, ChannelRecipientRemoveEvent } from "../interfaces"; import { Recipient } from "./Recipient"; @@ -34,7 +35,7 @@ export enum ChannelType { KANBAN = 34, // confluence like kanban board VOICELESS_WHITEBOARD = 35, // whiteboard but without voice (whiteboard + voice is the same as stage) CUSTOM_START = 64, // start custom channel types from here - UNHANDLED = 255 // unhandled unowned pass-through channel type + UNHANDLED = 255, // unhandled unowned pass-through channel type } @Entity("channels") @@ -149,7 +150,14 @@ export class Channel extends BaseClass { orphanedRowAction: "delete", }) webhooks?: Webhook[]; + + @Column({ nullable: true }) + flags?: number = 0; + @Column({ nullable: true }) + default_thread_rate_limit_per_user?: number = 0; + + // TODO: DM channel static async createChannel( channel: Partial<Channel>, @@ -169,23 +177,21 @@ export class Channel extends BaseClass { } if (!opts?.skipNameChecks) { - const guild = await Guild.findOneOrFail({ id: channel.guild_id }); + const guild = await Guild.findOneOrFail({ where: { id: channel.guild_id } }); if (!guild.features.includes("ALLOW_INVALID_CHANNEL_NAMES") && channel.name) { - for (var character of InvisibleCharacters) + for (let character of InvisibleCharacters) if (channel.name.includes(character)) throw new HTTPError("Channel name cannot include invalid characters", 403); if (channel.name.match(/\-\-+/g)) - throw new HTTPError("Channel name cannot include multiple adjacent dashes.", 403) + throw new HTTPError("Channel name cannot include multiple adjacent dashes.", 403); - if (channel.name.charAt(0) === "-" || - channel.name.charAt(channel.name.length - 1) === "-") - throw new HTTPError("Channel name cannot start/end with dash.", 403) + if (channel.name.charAt(0) === "-" || channel.name.charAt(channel.name.length - 1) === "-") + throw new HTTPError("Channel name cannot start/end with dash.", 403); } if (!guild.features.includes("ALLOW_UNNAMED_CHANNELS")) { - if (!channel.name) - throw new HTTPError("Channel name cannot be empty.", 403); + if (!channel.name) throw new HTTPError("Channel name cannot be empty.", 403); } } @@ -194,7 +200,7 @@ export class Channel extends BaseClass { case ChannelType.GUILD_NEWS: case ChannelType.GUILD_VOICE: if (channel.parent_id && !opts?.skipExistsCheck) { - const exists = await Channel.findOneOrFail({ id: channel.parent_id }); + const exists = await Channel.findOneOrFail({ where: { id: channel.parent_id } }); if (!exists) throw new HTTPError("Parent id channel doesn't exist", 400); if (exists.guild_id !== channel.guild_id) throw new HTTPError("The category channel needs to be in the guild"); @@ -222,13 +228,13 @@ export class Channel extends BaseClass { }; await Promise.all([ - new Channel(channel).save(), + OrmUtils.mergeDeep(new Channel(), channel).save(), !opts?.skipEventEmit ? emitEvent({ - event: "CHANNEL_CREATE", - data: channel, - guild_id: channel.guild_id, - } as ChannelCreateEvent) + event: "CHANNEL_CREATE", + data: channel, + guild_id: channel.guild_id, + } as ChannelCreateEvent) : Promise.resolve(), ]); @@ -246,7 +252,7 @@ export class Channel extends BaseClass { } **/ - const type = recipients.length > 1 ? ChannelType.DM : ChannelType.GROUP_DM; + const type = recipients.length > 1 ? ChannelType.GROUP_DM : ChannelType.DM; let channel = null; @@ -263,7 +269,8 @@ export class Channel extends BaseClass { if (containsAll(re, channelRecipients)) { if (channel == null) { channel = ur.channel; - await ur.assign({ closed: false }).save(); + ur = OrmUtils.mergeDeep(ur, { closed: false }); + await ur.save(); } } } @@ -272,17 +279,21 @@ export class Channel extends BaseClass { if (channel == null) { name = trimSpecial(name); - channel = await new Channel({ - name, - type, - owner_id: type === ChannelType.DM ? undefined : null, // 1:1 DMs are ownerless in fosscord-server - created_at: new Date(), - last_message_id: null, - recipients: channelRecipients.map( - (x) => - new Recipient({ user_id: x, closed: !(type === ChannelType.GROUP_DM || x === creator_user_id) }) - ), - }).save(); + channel = await ( + OrmUtils.mergeDeep(new Channel(), { + name, + type, + owner_id: type === ChannelType.DM ? undefined : null, // 1:1 DMs are ownerless in fosscord-server + created_at: new Date(), + last_message_id: null, + recipients: channelRecipients.map((x) => + OrmUtils.mergeDeep(new Recipient(), { + user_id: x, + closed: !(type === ChannelType.GROUP_DM || x === creator_user_id), + }) + ), + }) as Channel + ).save(); } const channel_dto = await DmChannelDTO.from(channel); @@ -299,7 +310,7 @@ export class Channel extends BaseClass { await emitEvent({ event: "CHANNEL_CREATE", data: channel_dto, user_id: creator_user_id }); } - if (recipients.length === 1) return channel_dto; + if (recipients.length === 1) return channel_dto; else return channel_dto.excludedRecipients([creator_user_id]); } diff --git a/util/src/entities/ClientRelease.ts b/src/util/entities/ClientRelease.ts
index c5afd307..c5afd307 100644 --- a/util/src/entities/ClientRelease.ts +++ b/src/util/entities/ClientRelease.ts
diff --git a/util/src/entities/ConnectedAccount.ts b/src/util/entities/ConnectedAccount.ts
index 09ae30ab..09ae30ab 100644 --- a/util/src/entities/ConnectedAccount.ts +++ b/src/util/entities/ConnectedAccount.ts
diff --git a/util/src/entities/Emoji.ts b/src/util/entities/Emoji.ts
index a3615b7d..a3615b7d 100644 --- a/util/src/entities/Emoji.ts +++ b/src/util/entities/Emoji.ts
diff --git a/util/src/entities/Encryption.ts b/src/util/entities/Encryption.ts
index 3b82ff84..6b578d15 100644 --- a/util/src/entities/Encryption.ts +++ b/src/util/entities/Encryption.ts
@@ -2,7 +2,7 @@ import { Column, Entity, JoinColumn, ManyToOne, OneToMany, RelationId } from "ty import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; import { PublicUserProjection, User } from "./User"; -import { HTTPError } from "lambert-server"; +import { HTTPError } from ".."; import { containsAll, emitEvent, getPermission, Snowflake, trimSpecial, InvisibleCharacters } from "../util"; import { BitField, BitFieldResolvable, BitFlag } from "../util/BitField"; import { Recipient } from "./Recipient"; diff --git a/util/src/entities/Group.ts b/src/util/entities/Group.ts
index b24d38cf..b24d38cf 100644 --- a/util/src/entities/Group.ts +++ b/src/util/entities/Group.ts
diff --git a/util/src/entities/Guild.ts b/src/util/entities/Guild.ts
index 70bb41c5..d146e577 100644 --- a/util/src/entities/Guild.ts +++ b/src/util/entities/Guild.ts
@@ -1,4 +1,5 @@ import { Column, Entity, JoinColumn, ManyToMany, ManyToOne, OneToMany, OneToOne, RelationId } from "typeorm"; +import { OrmUtils } from "../util/imports/OrmUtils"; import { Config, handleFile, Snowflake } from ".."; import { Ban } from "./Ban"; import { BaseClass } from "./BaseClass"; @@ -52,7 +53,7 @@ export class Guild extends BaseClass { afk_channel?: Channel; @Column({ nullable: true }) - afk_timeout?: number; + afk_timeout?: number = Config.get().defaults.guild.afkTimeout; // * commented out -> use owner instead // application id of the guild creator if it is bot-created @@ -70,7 +71,7 @@ export class Guild extends BaseClass { banner?: string; @Column({ nullable: true }) - default_message_notifications?: number; + default_message_notifications?: number = Config.get().defaults.guild.defaultMessageNotifications; @Column({ nullable: true }) description?: string; @@ -79,7 +80,7 @@ export class Guild extends BaseClass { discovery_splash?: string; @Column({ nullable: true }) - explicit_content_filter?: number; + explicit_content_filter?: number = Config.get().defaults.guild.explicitContentFilter; @Column({ type: "simple-array" }) features: string[]; //TODO use enum @@ -95,19 +96,19 @@ export class Guild extends BaseClass { large?: boolean; @Column({ nullable: true }) - max_members?: number; // e.g. default 100.000 + max_members?: number = Config.get().limits.guild.maxMembers; // e.g. default 100.000 @Column({ nullable: true }) - max_presences?: number; + max_presences?: number = Config.get().defaults.guild.maxPresences; @Column({ nullable: true }) - max_video_channel_users?: number; // ? default: 25, is this max 25 streaming or watching + max_video_channel_users?: number = Config.get().defaults.guild.maxVideoChannelUsers; // ? default: 25, is this max 25 streaming or watching @Column({ nullable: true }) - member_count?: number; + member_count?: number = 0; @Column({ nullable: true }) - presence_count?: number; // users online + presence_count?: number = 0; // users online @OneToMany(() => Member, (member: Member) => member.guild, { cascade: true, @@ -269,7 +270,7 @@ export class Guild extends BaseClass { @Column({ nullable: true }) nsfw?: boolean; - + // TODO: nested guilds @Column({ nullable: true }) parent?: string; @@ -277,6 +278,10 @@ export class Guild extends BaseClass { // only for developer portal permissions?: number; + //new guild settings, 11/08/2022: + @Column({ nullable: true }) + premium_progress_bar_enabled: boolean = false; + static async createGuild(body: { name?: string; icon?: string | null; @@ -285,7 +290,7 @@ export class Guild extends BaseClass { }) { const guild_id = Snowflake.generate(); - const guild = await new Guild({ + const guild: Guild = OrmUtils.mergeDeep(new Guild(), { name: body.name || "Fosscord", icon: await handleFile(`/icons/${guild_id}`, body.icon as string), region: Config.get().regions.default, @@ -316,11 +321,12 @@ export class Guild extends BaseClass { welcome_channels: [], }, widget_enabled: true, // NB: don't set it as false to prevent artificial restrictions - }).save(); + }); + await guild.save(); // we have to create the role _after_ the guild because else we would get a "SQLITE_CONSTRAINT: FOREIGN KEY constraint failed" error // TODO: make the @everyone a pseudorole that is dynamically generated at runtime so we can save storage - await new Role({ + let role: Role = OrmUtils.mergeDeep(new Role(), { id: guild_id, guild_id: guild_id, color: 0, @@ -332,8 +338,9 @@ export class Guild extends BaseClass { permissions: String("2251804225"), position: 0, icon: null, - unicode_emoji: null - }).save(); + unicode_emoji: null, + }); + await role.save(); if (!body.channels || !body.channels.length) body.channels = [{ id: "01", type: 0, name: "general" }]; @@ -346,9 +353,9 @@ export class Guild extends BaseClass { }); for (const channel of body.channels?.sort((a, b) => (a.parent_id ? 1 : -1))) { - var id = ids.get(channel.id) || Snowflake.generate(); + let id = ids.get(channel.id) || Snowflake.generate(); - var parent_id = ids.get(channel.parent_id); + let parent_id = ids.get(channel.parent_id); await Channel.createChannel({ ...channel, guild_id, id, parent_id }, body.owner_id, { keepId: true, diff --git a/util/src/entities/Invite.ts b/src/util/entities/Invite.ts
index 6ac64ddc..1e0ebe52 100644 --- a/util/src/entities/Invite.ts +++ b/src/util/entities/Invite.ts
@@ -4,19 +4,20 @@ import { BaseClassWithoutId } from "./BaseClass"; import { Channel } from "./Channel"; import { Guild } from "./Guild"; import { User } from "./User"; +import { random } from "@fosscord/api"; export const PublicInviteRelation = ["inviter", "guild", "channel"]; @Entity("invites") export class Invite extends BaseClassWithoutId { @PrimaryColumn() - code: string; + code: string = random(); @Column() - temporary: boolean; + temporary: boolean = true; @Column() - uses: number; + uses: number = 0; @Column() max_uses: number; @@ -25,7 +26,7 @@ export class Invite extends BaseClassWithoutId { max_age: number; @Column() - created_at: Date; + created_at: Date = new Date(); @Column() expires_at: Date; @@ -55,7 +56,9 @@ export class Invite extends BaseClassWithoutId { inviter_id: string; @JoinColumn({ name: "inviter_id" }) - @ManyToOne(() => User) + @ManyToOne(() => User, { + onDelete: "CASCADE" + }) inviter: User; @Column({ nullable: true }) @@ -75,7 +78,7 @@ export class Invite extends BaseClassWithoutId { vanity_url?: boolean; static async joinGuild(user_id: string, code: string) { - const invite = await Invite.findOneOrFail({ code }); + const invite = await Invite.findOneOrFail({ where: { code } }); if (invite.uses++ >= invite.max_uses && invite.max_uses !== 0) await Invite.delete({ code }); else await invite.save(); diff --git a/util/src/entities/Member.ts b/src/util/entities/Member.ts
index fe2d5590..baac58ed 100644 --- a/util/src/entities/Member.ts +++ b/src/util/entities/Member.ts
@@ -20,11 +20,12 @@ import { GuildMemberRemoveEvent, GuildMemberUpdateEvent, } from "../interfaces"; -import { HTTPError } from "lambert-server"; +import { HTTPError } from "../util/imports/HTTPError"; import { Role } from "./Role"; import { BaseClassWithoutId } from "./BaseClass"; import { Ban, PublicGuildRelations } from "."; import { DiscordApiErrors } from "../util/Constants"; +import { OrmUtils } from "../util/imports/OrmUtils"; export const MemberPrivateProjection: (keyof Member)[] = [ "id", @@ -70,7 +71,7 @@ export class Member extends BaseClassWithoutId { @Column({ nullable: true }) nick?: string; - + @JoinTable({ name: "member_roles", joinColumn: { name: "index", referencedColumnName: "index" }, @@ -85,8 +86,8 @@ export class Member extends BaseClassWithoutId { @Column() joined_at: Date; - @Column({ type: "bigint", nullable: true }) - premium_since?: number; + @Column({ nullable: true }) + premium_since?: Date; @Column() deaf: boolean; @@ -102,14 +103,14 @@ export class Member extends BaseClassWithoutId { @Column({ nullable: true }) last_message_id?: string; - + /** @JoinColumn({ name: "id" }) @ManyToOne(() => User, { onDelete: "DO NOTHING", // do not auto-kick force-joined members just because their joiners left the server }) **/ - @Column({ nullable: true}) + @Column({ nullable: true }) joined_by?: string; // TODO: add this when we have proper read receipts @@ -117,22 +118,24 @@ export class Member extends BaseClassWithoutId { // read_state: ReadState; static async IsInGuildOrFail(user_id: string, guild_id: string) { - if (await Member.count({ id: user_id, guild: { id: guild_id } })) return true; + if (await Member.count({ where: { id: user_id, guild: { id: guild_id } } })) return true; throw new HTTPError("You are not member of this guild", 403); } static async removeFromGuild(user_id: string, guild_id: string) { - const guild = await Guild.findOneOrFail({ select: ["owner_id"], where: { id: guild_id } }); + const guild = await Guild.findOneOrFail({ select: ["owner_id", "member_count"], where: { id: guild_id } }); if (guild.owner_id === user_id) throw new Error("The owner cannot be removed of the guild"); const member = await Member.findOneOrFail({ where: { id: user_id, guild_id }, relations: ["user"] }); // use promise all to execute all promises at the same time -> save time + //TODO: check for bugs + if (guild.member_count) guild.member_count--; return Promise.all([ Member.delete({ id: user_id, guild_id, }), - Guild.decrement({ id: guild_id }, "member_count", -1), + //Guild.decrement({ id: guild_id }, "member_count", -1), emitEvent({ event: "GUILD_DELETE", @@ -155,11 +158,11 @@ export class Member extends BaseClassWithoutId { Member.findOneOrFail({ where: { id: user_id, guild_id }, relations: ["user", "roles"], // we don't want to load the role objects just the ids - select: ["index", "roles.id"], + select: ["index"], }), Role.findOneOrFail({ where: { id: role_id, guild_id }, select: ["id"] }), ]); - member.roles.push(new Role({ id: role_id })); + member.roles.push(OrmUtils.mergeDeep(new Role(), { id: role_id })); await Promise.all([ member.save(), @@ -181,9 +184,9 @@ export class Member extends BaseClassWithoutId { Member.findOneOrFail({ where: { id: user_id, guild_id }, relations: ["user", "roles"], // we don't want to load the role objects just the ids - select: ["roles.id", "index"], + select: ["index"], }), - await Role.findOneOrFail({ id: role_id, guild_id }), + await Role.findOneOrFail({ where: { id: role_id, guild_id } }), ]); member.roles = member.roles.filter((x) => x.id == role_id); @@ -233,7 +236,7 @@ export class Member extends BaseClassWithoutId { throw DiscordApiErrors.USER_BANNED; } const { maxGuilds } = Config.get().limits.user; - const guild_count = await Member.count({ id: user_id }); + const guild_count = await Member.count({ where: { id: user_id } }); if (guild_count >= maxGuilds) { throw new HTTPError(`You are at the ${maxGuilds} server limit.`, 403); } @@ -245,7 +248,7 @@ export class Member extends BaseClassWithoutId { relations: PublicGuildRelations, }); - if (await Member.count({ id: user.id, guild: { id: guild_id } })) + if (await Member.count({ where: { id: user.id, guild: { id: guild_id } } })) throw new HTTPError("You are already a member of this guild", 400); const member = { @@ -254,16 +257,17 @@ export class Member extends BaseClassWithoutId { nick: undefined, roles: [guild_id], // @everyone role joined_at: new Date(), - premium_since: (new Date()).getTime(), + premium_since: null, deaf: false, mute: false, pending: false, }; - + //TODO: check for bugs + if (guild.member_count) guild.member_count++; await Promise.all([ - new Member({ + OrmUtils.mergeDeep(new Member(), { ...member, - roles: [new Role({ id: guild_id })], + roles: [OrmUtils.mergeDeep(new Role(), { id: guild_id })], // read_state: {}, settings: { channel_overrides: [], @@ -276,7 +280,7 @@ export class Member extends BaseClassWithoutId { }, // Member.save is needed because else the roles relations wouldn't be updated }).save(), - Guild.increment({ id: guild_id }, "member_count", 1), + //Guild.increment({ id: guild_id }, "member_count", 1), emitEvent({ event: "GUILD_MEMBER_ADD", data: { diff --git a/util/src/entities/Message.ts b/src/util/entities/Message.ts
index e18cf691..ba3d4f2d 100644 --- a/util/src/entities/Message.ts +++ b/src/util/entities/Message.ts
@@ -8,7 +8,6 @@ import { Column, CreateDateColumn, Entity, - FindConditions, Index, JoinColumn, JoinTable, diff --git a/util/src/entities/Migration.ts b/src/util/entities/Migration.ts
index 3f39ae72..3f39ae72 100644 --- a/util/src/entities/Migration.ts +++ b/src/util/entities/Migration.ts
diff --git a/util/src/entities/Note.ts b/src/util/entities/Note.ts
index 36017c5e..36017c5e 100644 --- a/util/src/entities/Note.ts +++ b/src/util/entities/Note.ts
diff --git a/util/src/entities/RateLimit.ts b/src/util/entities/RateLimit.ts
index f5916f6b..f5916f6b 100644 --- a/util/src/entities/RateLimit.ts +++ b/src/util/entities/RateLimit.ts
diff --git a/util/src/entities/ReadState.ts b/src/util/entities/ReadState.ts
index b915573b..b915573b 100644 --- a/util/src/entities/ReadState.ts +++ b/src/util/entities/ReadState.ts
diff --git a/util/src/entities/Recipient.ts b/src/util/entities/Recipient.ts
index a945f938..a945f938 100644 --- a/util/src/entities/Recipient.ts +++ b/src/util/entities/Recipient.ts
diff --git a/util/src/entities/Relationship.ts b/src/util/entities/Relationship.ts
index c3592c76..c3592c76 100644 --- a/util/src/entities/Relationship.ts +++ b/src/util/entities/Relationship.ts
diff --git a/util/src/entities/Role.ts b/src/util/entities/Role.ts
index 4b721b5b..4b721b5b 100644 --- a/util/src/entities/Role.ts +++ b/src/util/entities/Role.ts
diff --git a/util/src/entities/Session.ts b/src/util/entities/Session.ts
index 969efa89..969efa89 100644 --- a/util/src/entities/Session.ts +++ b/src/util/entities/Session.ts
diff --git a/util/src/entities/Sticker.ts b/src/util/entities/Sticker.ts
index 37bc6fbe..37bc6fbe 100644 --- a/util/src/entities/Sticker.ts +++ b/src/util/entities/Sticker.ts
diff --git a/util/src/entities/StickerPack.ts b/src/util/entities/StickerPack.ts
index ec8c69a2..ec8c69a2 100644 --- a/util/src/entities/StickerPack.ts +++ b/src/util/entities/StickerPack.ts
diff --git a/util/src/entities/Team.ts b/src/util/entities/Team.ts
index 22140b7f..22140b7f 100644 --- a/util/src/entities/Team.ts +++ b/src/util/entities/Team.ts
diff --git a/util/src/entities/TeamMember.ts b/src/util/entities/TeamMember.ts
index b726e1e8..b726e1e8 100644 --- a/util/src/entities/TeamMember.ts +++ b/src/util/entities/TeamMember.ts
diff --git a/util/src/entities/Template.ts b/src/util/entities/Template.ts
index 1d952283..1d952283 100644 --- a/util/src/entities/Template.ts +++ b/src/util/entities/Template.ts
diff --git a/util/src/entities/User.ts b/src/util/entities/User.ts
index 470398a5..5432f298 100644 --- a/util/src/entities/User.ts +++ b/src/util/entities/User.ts
@@ -1,11 +1,11 @@ -import { Column, Entity, FindOneOptions, JoinColumn, OneToMany } from "typeorm"; +import { Column, Entity, FindOneOptions, FindOptionsSelectByString, JoinColumn, OneToMany, OneToOne } from "typeorm"; +import { OrmUtils } from "../util/imports/OrmUtils"; import { BaseClass } from "./BaseClass"; import { BitField } from "../util/BitField"; import { Relationship } from "./Relationship"; import { ConnectedAccount } from "./ConnectedAccount"; import { Config, FieldErrors, Snowflake, trimSpecial } from ".."; -import { Member, Session } from "."; -import { Note } from "./Note"; +import { Member, Session, UserSettings } from "."; export enum PublicUserEnum { username, @@ -83,30 +83,30 @@ export class User extends BaseClass { phone?: string; // phone number of the user @Column({ select: false }) - desktop: boolean; // if the user has desktop app installed + desktop: boolean = false; // if the user has desktop app installed @Column({ select: false }) - mobile: boolean; // if the user has mobile app installed + mobile: boolean = false; // if the user has mobile app installed @Column() - premium: boolean; // if user bought individual premium - - @Column() - premium_type: number; // individual premium level + premium: boolean = Config.get().defaults.user.premium; // if user bought individual premium @Column() - bot: boolean; // if user is bot + premium_type: number = Config.get().defaults.user.premium_type; // individual premium level @Column() + bot: boolean = false; // if user is bot + + @Column({ nullable: true }) bio: string; // short description of the user (max 190 chars -> should be configurable) @Column() - system: boolean; // shouldn't be used, the api sends this field type true, if the generated message comes from a system generated author + system: boolean = false; // shouldn't be used, the api sends this field type true, if the generated message comes from a system generated author @Column({ select: false }) - nsfw_allowed: boolean; // if the user can do age-restricted actions (NSFW channels/guilds/commands) - - @Column({ select: false }) + nsfw_allowed: boolean = true; // if the user can do age-restricted actions (NSFW channels/guilds/commands) // TODO: depending on age + + @Column({ select: false, nullable: true }) mfa_enabled: boolean; // if multi factor authentication is enabled @Column({ select: false, nullable: true }) @@ -116,31 +116,31 @@ export class User extends BaseClass { totp_last_ticket?: string; @Column() - created_at: Date; // registration date + created_at: Date = new Date(); // registration date @Column({ nullable: true }) - premium_since: Date; // premium date + premium_since: Date = new Date(); // premium date @Column({ select: false }) - verified: boolean; // if the user is offically verified + verified: boolean = Config.get().defaults.user.verified; // if the user is offically verified @Column() - disabled: boolean; // if the account is disabled + disabled: boolean = false; // if the account is disabled @Column() - deleted: boolean; // if the user was deleted + deleted: boolean = false; // if the user was deleted @Column({ nullable: true, select: false }) email?: string; // email of the user @Column() - flags: string; // UserFlags + flags: string = "0"; // UserFlags // TODO: generate @Column() - public_flags: number; + public_flags: number = 0; @Column({ type: "bigint" }) - rights: string; // Rights + rights: string = Config.get().register.defaultRights; // Rights @OneToMany(() => Session, (session: Session) => session.user) sessions: Session[]; @@ -166,14 +166,30 @@ export class User extends BaseClass { }; @Column({ type: "simple-array", select: false }) - fingerprints: string[]; // array of fingerprints -> used to prevent multiple accounts + fingerprints: string[] = []; // array of fingerprints -> used to prevent multiple accounts - @Column({ type: "simple-json", select: false }) + + @OneToOne(()=> UserSettings, { + cascade: true, + orphanedRowAction: "delete", + eager: false + }) + @JoinColumn() settings: UserSettings; - + // workaround to prevent fossord-unaware clients from deleting settings not used by them @Column({ type: "simple-json", select: false }) - extended_settings: string; + extended_settings: string = "{}"; + + @Column({ type: "simple-json" }) + notes: { [key: string]: string } = {}; //key is ID of user + + async save(): Promise<any> { + if(!this.settings) this.settings = new UserSettings(); + this.settings.id = this.id; + //await this.settings.save(); + return super.save(); + } toPublicUser() { const user: any = {}; @@ -184,19 +200,17 @@ export class User extends BaseClass { } static async getPublicUser(user_id: string, opts?: FindOneOptions<User>) { - return await User.findOneOrFail( - { id: user_id }, - { - ...opts, - select: [...PublicUserProjection, ...(opts?.select || [])], - } - ); + return await User.findOneOrFail({ + where: { id: user_id }, + select: [...PublicUserProjection, ...((opts?.select as FindOptionsSelectByString<User>) || [])], + ...opts, + }); } - private static async generateDiscriminator(username: string): Promise<string | undefined> { + public static async generateDiscriminator(username: string): Promise<string | undefined> { if (Config.get().register.incrementingDiscriminators) { // discriminator will be incrementally generated - + // First we need to figure out the currently highest discrimnator for the given username and then increment it const users = await User.find({ where: { username }, select: ["discriminator"] }); const highestDiscriminator = Math.max(0, ...users.map((u) => Number(u.discriminator))); @@ -244,7 +258,7 @@ export class User extends BaseClass { throw FieldErrors({ username: { code: "USERNAME_TOO_MANY_USERS", - message: req.t("auth:register.USERNAME_TOO_MANY_USERS"), + message: req?.t("auth:register.USERNAME_TOO_MANY_USERS"), }, }); } @@ -252,40 +266,22 @@ export class User extends BaseClass { // TODO: save date_of_birth // appearently discord doesn't save the date of birth and just calculate if nsfw is allowed // if nsfw_allowed is null/undefined it'll require date_of_birth to set it to true/false - const language = req.language === "en" ? "en-US" : req.language || "en-US"; + const language = req?.language === "en" ? "en-US" : req?.language || "en-US"; - const user = new User({ - created_at: new Date(), + const user = OrmUtils.mergeDeep(new User(), { + //required: username: username, discriminator, id: Snowflake.generate(), - bot: false, - system: false, - premium_since: new Date(), - desktop: false, - mobile: false, - premium: true, - premium_type: 2, - bio: "", - mfa_enabled: false, - verified: true, - disabled: false, - deleted: false, email: email, - rights: "0", // TODO: grant rights correctly, as 0 actually stands for no rights at all - nsfw_allowed: true, // TODO: depending on age - public_flags: "0", - flags: "0", // TODO: generate data: { hash: password, valid_tokens_since: new Date(), }, - settings: { ...defaultSettings, locale: language }, - extended_settings: {}, - fingerprints: [], - notes: {}, + settings: { ...new UserSettings(), locale: language } }); + //await (user.settings as UserSettings).save(); await user.save(); setImmediate(async () => { @@ -300,85 +296,6 @@ export class User extends BaseClass { } } -export const defaultSettings: UserSettings = { - afk_timeout: 3600, - allow_accessibility_detection: true, - animate_emoji: true, - animate_stickers: 0, - contact_sync_enabled: false, - convert_emoticons: false, - custom_status: null, - default_guilds_restricted: false, - detect_platform_accounts: false, - developer_mode: true, - disable_games_tab: true, - enable_tts_command: false, - explicit_content_filter: 0, - friend_source_flags: { all: true }, - gateway_connected: false, - gif_auto_play: true, - guild_folders: [], - guild_positions: [], - inline_attachment_media: true, - inline_embed_media: true, - locale: "en-US", - message_display_compact: true, - native_phone_integration_enabled: true, - render_embeds: true, - render_reactions: true, - restricted_guilds: [], - show_current_game: true, - status: "online", - stream_notifications_enabled: false, - theme: "dark", - timezone_offset: 0, // TODO: timezone from request -}; - -export interface UserSettings { - afk_timeout: number; - allow_accessibility_detection: boolean; - animate_emoji: boolean; - animate_stickers: number; - contact_sync_enabled: boolean; - convert_emoticons: boolean; - custom_status: { - emoji_id?: string; - emoji_name?: string; - expires_at?: number; - text?: string; - } | null; - default_guilds_restricted: boolean; - detect_platform_accounts: boolean; - developer_mode: boolean; - disable_games_tab: boolean; - enable_tts_command: boolean; - explicit_content_filter: number; - friend_source_flags: { all: boolean }; - gateway_connected: boolean; - gif_auto_play: boolean; - // every top guild is displayed as a "folder" - guild_folders: { - color: number; - guild_ids: string[]; - id: number; - name: string; - }[]; - guild_positions: string[]; // guild ids ordered by position - inline_attachment_media: boolean; - inline_embed_media: boolean; - locale: string; // en_US - message_display_compact: boolean; - native_phone_integration_enabled: boolean; - render_embeds: boolean; - render_reactions: boolean; - restricted_guilds: string[]; - show_current_game: boolean; - status: "online" | "offline" | "dnd" | "idle" | "invisible"; - stream_notifications_enabled: boolean; - theme: "dark" | "white"; // dark - timezone_offset: number; // e.g -60 -} - export const CUSTOM_USER_FLAG_OFFSET = BigInt(1) << BigInt(32); export class UserFlags extends BitField { diff --git a/util/src/entities/UserGroup.ts b/src/util/entities/UserGroup.ts
index 709b9d0b..709b9d0b 100644 --- a/util/src/entities/UserGroup.ts +++ b/src/util/entities/UserGroup.ts
diff --git a/util/src/entities/VoiceState.ts b/src/util/entities/VoiceState.ts
index 75748a01..75748a01 100644 --- a/util/src/entities/VoiceState.ts +++ b/src/util/entities/VoiceState.ts
diff --git a/util/src/entities/Webhook.ts b/src/util/entities/Webhook.ts
index 89538417..89538417 100644 --- a/util/src/entities/Webhook.ts +++ b/src/util/entities/Webhook.ts
diff --git a/util/src/entities/index.ts b/src/util/entities/index.ts
index c439a4b7..c6f12022 100644 --- a/util/src/entities/index.ts +++ b/src/util/entities/index.ts
@@ -30,3 +30,4 @@ export * from "./Webhook"; export * from "./ClientRelease"; export * from "./BackupCodes"; export * from "./Note"; +export * from "./UserSettings"; diff --git a/util/src/index.ts b/src/util/index.ts
index ae0f7e54..d944dc49 100644 --- a/util/src/index.ts +++ b/src/util/index.ts
@@ -1,6 +1,9 @@ import "reflect-metadata"; export * from "./util/index"; +export * from "./config/index"; export * from "./interfaces/index"; export * from "./entities/index"; export * from "./dtos/index"; +export * from "./util/MFA"; +export * from "./schemas"; \ No newline at end of file diff --git a/util/src/interfaces/Activity.ts b/src/util/interfaces/Activity.ts
index 43984afd..43984afd 100644 --- a/util/src/interfaces/Activity.ts +++ b/src/util/interfaces/Activity.ts
diff --git a/util/src/interfaces/Event.ts b/src/util/interfaces/Event.ts
index 416082ed..be66c62f 100644 --- a/util/src/interfaces/Event.ts +++ b/src/util/interfaces/Event.ts
@@ -1,4 +1,4 @@ -import { PublicUser, User, UserSettings } from "../entities/User"; +import { PublicUser, User } from "../entities/User"; import { Channel } from "../entities/Channel"; import { Guild } from "../entities/Guild"; import { Member, PublicMember, UserGuildSettings } from "../entities/Member"; @@ -12,7 +12,7 @@ import { Interaction } from "./Interaction"; import { ConnectedAccount } from "../entities/ConnectedAccount"; import { Relationship, RelationshipType } from "../entities/Relationship"; import { Presence } from "./Presence"; -import { Sticker } from ".."; +import { Sticker, UserSettings } from ".."; import { Activity, Status } from "."; export interface Event { @@ -93,7 +93,7 @@ export interface ReadyEventData { }; application?: { id: string; - flags: string; + flags: number; }; merged_members?: PublicMember[][]; // probably all users who the user is in contact with diff --git a/util/src/interfaces/Interaction.ts b/src/util/interfaces/Interaction.ts
index 5d3aae24..5d3aae24 100644 --- a/util/src/interfaces/Interaction.ts +++ b/src/util/interfaces/Interaction.ts
diff --git a/util/src/interfaces/Presence.ts b/src/util/interfaces/Presence.ts
index 7663891a..7663891a 100644 --- a/util/src/interfaces/Presence.ts +++ b/src/util/interfaces/Presence.ts
diff --git a/util/src/interfaces/Status.ts b/src/util/interfaces/Status.ts
index 5d2e1bba..5d2e1bba 100644 --- a/util/src/interfaces/Status.ts +++ b/src/util/interfaces/Status.ts
diff --git a/util/src/interfaces/index.ts b/src/util/interfaces/index.ts
index ab7fa429..ab7fa429 100644 --- a/util/src/interfaces/index.ts +++ b/src/util/interfaces/index.ts
diff --git a/util/src/util/ApiError.ts b/src/util/util/ApiError.ts
index f1a9b4f6..f1a9b4f6 100644 --- a/util/src/util/ApiError.ts +++ b/src/util/util/ApiError.ts
diff --git a/util/src/util/Array.ts b/src/util/util/Array.ts
index 5a45d1b5..5a45d1b5 100644 --- a/util/src/util/Array.ts +++ b/src/util/util/Array.ts
diff --git a/util/src/util/AutoUpdate.ts b/src/util/util/AutoUpdate.ts
index 531bd8b7..7d020106 100644 --- a/util/src/util/AutoUpdate.ts +++ b/src/util/util/AutoUpdate.ts
@@ -1,4 +1,3 @@ -import "missing-native-js-functions"; import fetch from "node-fetch"; import ProxyAgent from 'proxy-agent'; import readline from "readline"; @@ -18,7 +17,7 @@ export function enableAutoUpdate(opts: { downloadType?: "zip"; }) { if (!opts.checkInterval) return; - var interval = 1000 * 60 * 60 * 24; + let interval = 1000 * 60 * 60 * 24; if (typeof opts.checkInterval === "number") opts.checkInterval = 1000 * interval; const i = setInterval(async () => { @@ -76,7 +75,7 @@ async function getLatestVersion(url: string) { try { const agent = new ProxyAgent(); const response = await fetch(url, { agent }); - const content = await response.json(); + const content: any = await response.json(); return content.version; } catch (error) { throw new Error("[Auto update] check failed for " + url); diff --git a/util/src/util/BitField.ts b/src/util/util/BitField.ts
index fb887e05..9bdbf6d7 100644 --- a/util/src/util/BitField.ts +++ b/src/util/util/BitField.ts
@@ -138,6 +138,9 @@ export class BitField { return bit.map((p) => resolve.call(this, p)).reduce((prev, p) => BigInt(prev) | BigInt(p), BigInt(0)); } if (typeof bit === "string" && typeof FLAGS[bit] !== "undefined") return FLAGS[bit]; + if (bit === "0") return BigInt(0); //special case: 0 + if (typeof bit === "string") return BigInt(bit); //last ditch effort... + if(/--debug|--inspect/.test(process.execArgv.join(' '))) debugger; //if you're here, we have an invalid bitfield... if bit is 0, thats fine, I guess... throw new RangeError("BITFIELD_INVALID: " + bit); } } diff --git a/util/src/util/Categories.ts b/src/util/util/Categories.ts
index a3c69da7..a3c69da7 100644 --- a/util/src/util/Categories.ts +++ b/src/util/util/Categories.ts
diff --git a/util/src/util/Config.ts b/src/util/util/Config.ts
index 31b8d97c..e0fb2a81 100644 --- a/util/src/util/Config.ts +++ b/src/util/util/Config.ts
@@ -1,13 +1,13 @@ -import "missing-native-js-functions"; -import { ConfigValue, ConfigEntity, DefaultConfigOptions } from "../entities/Config"; -import path from "path"; +import { ConfigEntity } from "../entities/Config"; import fs from "fs"; +import { ConfigValue } from "../config"; +import { OrmUtils } from "."; // TODO: yaml instead of json -// const overridePath = path.join(process.cwd(), "config.json"); +const overridePath = process.env.CONFIG_PATH ?? ""; -var config: ConfigValue; -var pairs: ConfigEntity[]; +let config: ConfigValue; +let pairs: ConfigEntity[]; // TODO: use events to inform about config updates // Config keys are separated with _ @@ -15,20 +15,29 @@ var pairs: ConfigEntity[]; export const Config = { init: async function init() { if (config) return config; + console.log('[Config] Loading configuration...') pairs = await ConfigEntity.find(); config = pairsToConfig(pairs); - config = (config || {}).merge(DefaultConfigOptions); - - // try { - // const overrideConfig = JSON.parse(fs.readFileSync(overridePath, { encoding: "utf8" })); - // config = overrideConfig.merge(config); - // } catch (error) { - // fs.writeFileSync(overridePath, JSON.stringify(config, null, 4)); - // } + //config = (config || {}).merge(new ConfigValue()); + config = OrmUtils.mergeDeep(new ConfigValue(), config) + + if(process.env.CONFIG_PATH) + try { + const overrideConfig = JSON.parse(fs.readFileSync(overridePath, { encoding: "utf8" })); + config = overrideConfig.merge(config); + } catch (error) { + fs.writeFileSync(overridePath, JSON.stringify(config, null, 4)); + } + return this.set(config); }, get: function get() { + if(!config) { + if(/--debug|--inspect/.test(process.execArgv.join(' '))) + console.log("Oops.. trying to get config without config existing... Returning defaults... (Is the database still initialising?)"); + return new ConfigValue(); + } return config; }, set: function set(val: Partial<ConfigValue>) { @@ -51,13 +60,17 @@ function applyConfig(val: ConfigValue) { pair.value = obj; return pair.save(); } - // fs.writeFileSync(overridePath, JSON.stringify(val, null, 4)); + if(process.env.CONFIG_PATH) { + if(/--debug|--inspect/.test(process.execArgv.join(' '))) + console.log(`Writing config: ${process.env.CONFIG_PATH}`) + fs.writeFileSync(overridePath, JSON.stringify(val, null, 4)); + } return apply(val); } function pairsToConfig(pairs: ConfigEntity[]) { - var value: any = {}; + let value: any = {}; pairs.forEach((p) => { const keys = p.key.split("_"); diff --git a/util/src/util/Constants.ts b/src/util/util/Constants.ts
index a5d3fcd2..a5d3fcd2 100644 --- a/util/src/util/Constants.ts +++ b/src/util/util/Constants.ts
diff --git a/util/src/util/Email.ts b/src/util/util/Email.ts
index 6885da33..6885da33 100644 --- a/util/src/util/Email.ts +++ b/src/util/util/Email.ts
diff --git a/util/src/util/Event.ts b/src/util/util/Event.ts
index bb624051..90c24347 100644 --- a/util/src/util/Event.ts +++ b/src/util/util/Event.ts
@@ -58,8 +58,8 @@ export async function listenEvent(event: string, callback: (event: EventOpts) => process.setMaxListeners(process.getMaxListeners() - 1); }; - const listener = (msg: ProcessEvent) => { - msg.type === "event" && msg.id === event && callback({ ...msg.event, cancel }); + const listener = (message: any) => { + message.type === "event" && message.id === event && callback({ ...message.event, cancel }); }; process.addListener("message", listener); diff --git a/util/src/util/FieldError.ts b/src/util/util/FieldError.ts
index 406b33e8..49968e1a 100644 --- a/util/src/util/FieldError.ts +++ b/src/util/util/FieldError.ts
@@ -1,5 +1,3 @@ -import "missing-native-js-functions"; - export function FieldErrors(fields: Record<string, { code?: string; message: string }>) { return new FieldError( 50035, diff --git a/util/src/util/Intents.ts b/src/util/util/Intents.ts
index 1e840b76..1e840b76 100644 --- a/util/src/util/Intents.ts +++ b/src/util/util/Intents.ts
diff --git a/util/src/util/InvisibleCharacters.ts b/src/util/util/InvisibleCharacters.ts
index 2b014e14..2b014e14 100644 --- a/util/src/util/InvisibleCharacters.ts +++ b/src/util/util/InvisibleCharacters.ts
diff --git a/util/src/util/MessageFlags.ts b/src/util/util/MessageFlags.ts
index b59295c4..b59295c4 100644 --- a/util/src/util/MessageFlags.ts +++ b/src/util/util/MessageFlags.ts
diff --git a/util/src/util/Permissions.ts b/src/util/util/Permissions.ts
index e5459ab5..c7400303 100644 --- a/util/src/util/Permissions.ts +++ b/src/util/util/Permissions.ts
@@ -1,17 +1,8 @@ // https://github.com/discordjs/discord.js/blob/master/src/util/Permissions.js // Apache License Version 2.0 Copyright 2015 - 2021 Amish Shah import { Channel, ChannelPermissionOverwrite, Guild, Member, Role } from "../entities"; -import { BitField } from "./BitField"; -import "missing-native-js-functions"; -import { BitFieldResolvable, BitFlag } from "./BitField"; - -var HTTPError: any; - -try { - HTTPError = require("lambert-server").HTTPError; -} catch (e) { - HTTPError = Error; -} +import { BitField, BitFieldResolvable, BitFlag } from "./BitField"; +import { HTTPError } from ".."; export type PermissionResolvable = bigint | number | Permissions | PermissionResolvable[] | PermissionString; @@ -207,9 +198,9 @@ export async function getPermission( } = {} ) { if (!user_id) throw new HTTPError("User not found"); - var channel: Channel | undefined; - var member: Member | undefined; - var guild: Guild | undefined; + let channel: Channel | undefined; + let member: Member | undefined; + let guild: Guild | undefined; if (channel_id) { channel = await Channel.findOneOrFail({ @@ -247,6 +238,7 @@ export async function getPermission( select: [ "id", "roles", + "index", // @ts-ignore ...(opts.member_select || []), ], @@ -257,7 +249,7 @@ export async function getPermission( if (!recipient_ids?.length) recipient_ids = null; // TODO: remove guild.roles and convert recipient_ids to recipients - var permission = Permissions.finalPermission({ + let permission = Permissions.finalPermission({ user: { id: user_id, roles: member?.roles.map((x) => x.id) || [], diff --git a/util/src/util/RabbitMQ.ts b/src/util/util/RabbitMQ.ts
index 0f5eb6aa..0f5eb6aa 100644 --- a/util/src/util/RabbitMQ.ts +++ b/src/util/util/RabbitMQ.ts
diff --git a/util/src/util/Regex.ts b/src/util/util/Regex.ts
index 83fc9fe8..83fc9fe8 100644 --- a/util/src/util/Regex.ts +++ b/src/util/util/Regex.ts
diff --git a/util/src/util/Rights.ts b/src/util/util/Rights.ts
index b28c75b7..1c3906fb 100644 --- a/util/src/util/Rights.ts +++ b/src/util/util/Rights.ts
@@ -1,15 +1,6 @@ -import { BitField } from "./BitField"; -import "missing-native-js-functions"; -import { BitFieldResolvable, BitFlag } from "./BitField"; +import { BitField, BitFieldResolvable, BitFlag } from "./BitField"; import { User } from "../entities"; - -var HTTPError: any; - -try { - HTTPError = require("lambert-server").HTTPError; -} catch (e) { - HTTPError = Error; -} +import { HTTPError } from ".."; export type RightResolvable = bigint | number | Rights | RightResolvable[] | RightString; diff --git a/util/src/util/Snowflake.ts b/src/util/util/Snowflake.ts
index 134d526e..0ef178fe 100644 --- a/util/src/util/Snowflake.ts +++ b/src/util/util/Snowflake.ts
@@ -84,10 +84,10 @@ export class Snowflake { } static generateWorkerProcess() { // worker process - returns a number - var time = BigInt(Date.now() - Snowflake.EPOCH) << BigInt(22); - var worker = Snowflake.workerId << 17n; - var process = Snowflake.processId << 12n; - var increment = Snowflake.INCREMENT++; + let time = BigInt(Date.now() - Snowflake.EPOCH) << BigInt(22); + let worker = Snowflake.workerId << 17n; + let process = Snowflake.processId << 12n; + let increment = Snowflake.INCREMENT++; return BigInt(time | worker | process | increment); } diff --git a/util/src/util/String.ts b/src/util/util/String.ts
index 55f11e8d..55f11e8d 100644 --- a/util/src/util/String.ts +++ b/src/util/util/String.ts
diff --git a/util/src/util/Token.ts b/src/util/util/Token.ts
index 500ace45..5a3922d1 100644 --- a/util/src/util/Token.ts +++ b/src/util/util/Token.ts
@@ -15,10 +15,10 @@ export function checkToken(token: string, jwtSecret: string): Promise<any> { jwt.verify(token, jwtSecret, JWTOptions, async (err, decoded: any) => { if (err || !decoded) return rej("Invalid Token"); - const user = await User.findOne( - { id: decoded.id }, - { select: ["data", "bot", "disabled", "deleted", "rights"] } - ); + const user = await User.findOne({ + where: { id: decoded.id }, + select: ["data", "bot", "disabled", "deleted", "rights"] + }); 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 < new Date(user.data.valid_tokens_since).setSeconds(0, 0)) diff --git a/util/src/util/TraverseDirectory.ts b/src/util/util/TraverseDirectory.ts
index 3d0d6279..3d0d6279 100644 --- a/util/src/util/TraverseDirectory.ts +++ b/src/util/util/TraverseDirectory.ts
diff --git a/util/src/util/cdn.ts b/src/util/util/cdn.ts
index ea950cd1..9cfe4896 100644 --- a/util/src/util/cdn.ts +++ b/src/util/util/cdn.ts
@@ -1,8 +1,9 @@ import FormData from "form-data"; -import { HTTPError } from "lambert-server"; -import fetch from "node-fetch"; +import { HTTPError } from ".."; import { Config } from "./Config"; import multer from "multer"; +import fetch from "node-fetch" +import { nodeModuleNameResolver } from "typescript"; export async function uploadFile(path: string, file?: Express.Multer.File) { if (!file?.buffer) throw new HTTPError("Missing file in body"); diff --git a/util/src/util/index.ts b/src/util/util/index.ts
index f7a273cb..9e6059fa 100644 --- a/util/src/util/index.ts +++ b/src/util/util/index.ts
@@ -1,6 +1,8 @@ export * from "./ApiError"; export * from "./BitField"; export * from "./Token"; +export * from "./imports/HTTPError"; +export * from "./imports/OrmUtils"; //export * from "./Categories"; export * from "./cdn"; export * from "./Config"; @@ -19,4 +21,6 @@ export * from "./Snowflake"; export * from "./String"; export * from "./Array"; export * from "./TraverseDirectory"; -export * from "./InvisibleCharacters"; \ No newline at end of file +export * from "./InvisibleCharacters"; + +export * from "./imports/index"; diff --git a/util/src/entities/BaseClass.ts b/util/src/entities/BaseClass.ts deleted file mode 100644
index aabca016..00000000 --- a/util/src/entities/BaseClass.ts +++ /dev/null
@@ -1,75 +0,0 @@ -import "reflect-metadata"; -import { BaseEntity, EntityMetadata, FindConditions, ObjectIdColumn, PrimaryColumn } from "typeorm"; -import { Snowflake } from "../util/Snowflake"; -import "missing-native-js-functions"; - -export class BaseClassWithoutId extends BaseEntity { - constructor(props?: any) { - super(); - this.assign(props); - } - - private get construct(): any { - return this.constructor; - } - - private get metadata() { - return this.construct.getRepository().metadata as EntityMetadata; - } - - assign(props: any = {}) { - delete props.opts; - delete props.props; - - const properties = new Set( - this.metadata.columns - .map((x: any) => x.propertyName) - .concat(this.metadata.relations.map((x) => x.propertyName)) - ); - // will not include relational properties - - for (const key in props) { - if (!properties.has(key)) continue; - // @ts-ignore - const setter = this[`set${key.capitalize()}`]; // use setter function if it exists - - if (setter) { - setter.call(this, props[key]); - } else { - // @ts-ignore - this[key] = props[key]; - } - } - } - - toJSON(): any { - return Object.fromEntries( - this.metadata.columns // @ts-ignore - .map((x) => [x.propertyName, this[x.propertyName]]) // @ts-ignore - .concat(this.metadata.relations.map((x) => [x.propertyName, this[x.propertyName]])) - ); - } - - static increment<T extends BaseClass>(conditions: FindConditions<T>, propertyPath: string, value: number | string) { - const repository = this.getRepository(); - return repository.increment(conditions as T, propertyPath, value); - } - - static decrement<T extends BaseClass>(conditions: FindConditions<T>, propertyPath: string, value: number | string) { - const repository = this.getRepository(); - return repository.decrement(conditions as T, propertyPath, value); - } -} - -export const PrimaryIdColumn = process.env.DATABASE?.startsWith("mongodb") ? ObjectIdColumn : PrimaryColumn; - -export class BaseClass extends BaseClassWithoutId { - @PrimaryIdColumn() - id: string; - - assign(props: any = {}) { - super.assign(props); - if (!this.id) this.id = Snowflake.generate(); - return this; - } -} diff --git a/util/src/entities/Config.ts b/util/src/entities/Config.ts deleted file mode 100644
index c84ea4aa..00000000 --- a/util/src/entities/Config.ts +++ /dev/null
@@ -1,413 +0,0 @@ -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"; - -@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; - }; - 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; - twoFactor: { - generateBackupCodes: boolean; - }; - }; - 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; - }; - }; - 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, - }, - 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", - twoFactor: { - generateBackupCodes: true, - }, - }, - 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: [], - }, - }, - 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() - } -}; diff --git a/util/src/migrations/1633864260873-EmojiRoles.ts b/util/src/migrations/1633864260873-EmojiRoles.ts deleted file mode 100644
index f0d709f2..00000000 --- a/util/src/migrations/1633864260873-EmojiRoles.ts +++ /dev/null
@@ -1,13 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class EmojiRoles1633864260873 implements MigrationInterface { - name = "EmojiRoles1633864260873"; - - public async up(queryRunner: QueryRunner): Promise<void> { - await queryRunner.query(`ALTER TABLE "emojis" ADD "roles" text NOT NULL DEFAULT ''`); - } - - public async down(queryRunner: QueryRunner): Promise<void> { - await queryRunner.query(`ALTER TABLE "emojis" DROP COLUMN column_name "roles"`); - } -} diff --git a/util/src/migrations/1633864669243-EmojiUser.ts b/util/src/migrations/1633864669243-EmojiUser.ts deleted file mode 100644
index 982405d7..00000000 --- a/util/src/migrations/1633864669243-EmojiUser.ts +++ /dev/null
@@ -1,23 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class EmojiUser1633864669243 implements MigrationInterface { - name = "EmojiUser1633864669243"; - - public async up(queryRunner: QueryRunner): Promise<void> { - await queryRunner.query(`ALTER TABLE "emojis" ADD "user_id" varchar`); - try { - await queryRunner.query( - `ALTER TABLE "emojis" ADD CONSTRAINT FK_fa7ddd5f9a214e28ce596548421 FOREIGN KEY (user_id) REFERENCES users(id)` - ); - } catch (error) { - console.error( - "sqlite doesn't support altering foreign keys: https://stackoverflow.com/questions/1884818/how-do-i-add-a-foreign-key-to-an-existing-sqlite-table" - ); - } - } - - public async down(queryRunner: QueryRunner): Promise<void> { - await queryRunner.query(`ALTER TABLE "emojis" DROP COLUMN column_name "user_id"`); - await queryRunner.query(`ALTER TABLE "emojis" DROP CONSTRAINT FK_fa7ddd5f9a214e28ce596548421`); - } -} diff --git a/util/src/migrations/1633881705509-VanityInvite.ts b/util/src/migrations/1633881705509-VanityInvite.ts deleted file mode 100644
index 45485310..00000000 --- a/util/src/migrations/1633881705509-VanityInvite.ts +++ /dev/null
@@ -1,19 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class VanityInvite1633881705509 implements MigrationInterface { - name = "VanityInvite1633881705509"; - - public async up(queryRunner: QueryRunner): Promise<void> { - try { - await queryRunner.query(`ALTER TABLE "emojis" DROP COLUMN vanity_url_code`); - await queryRunner.query(`ALTER TABLE "emojis" DROP CONSTRAINT FK_c2c1809d79eb120ea0cb8d342ad`); - } catch (error) {} - } - - public async down(queryRunner: QueryRunner): Promise<void> { - await queryRunner.query(`ALTER TABLE "emojis" ADD vanity_url_code varchar`); - await queryRunner.query( - `ALTER TABLE "emojis" ADD CONSTRAINT FK_c2c1809d79eb120ea0cb8d342ad FOREIGN KEY ("vanity_url_code") REFERENCES "invites"("code") ON DELETE NO ACTION ON UPDATE NO ACTION` - ); - } -} diff --git a/util/src/migrations/1634308884591-Stickers.ts b/util/src/migrations/1634308884591-Stickers.ts deleted file mode 100644
index fbc4649f..00000000 --- a/util/src/migrations/1634308884591-Stickers.ts +++ /dev/null
@@ -1,66 +0,0 @@ -import { MigrationInterface, QueryRunner, Table, TableColumn, TableForeignKey } from "typeorm"; - -export class Stickers1634308884591 implements MigrationInterface { - name = "Stickers1634308884591"; - - public async up(queryRunner: QueryRunner): Promise<void> { - await queryRunner.dropForeignKey("read_states", "FK_6f255d873cfbfd7a93849b7ff74"); - await queryRunner.changeColumn( - "stickers", - "tags", - new TableColumn({ name: "tags", type: "varchar", isNullable: true }) - ); - await queryRunner.changeColumn( - "stickers", - "pack_id", - new TableColumn({ name: "pack_id", type: "varchar", isNullable: true }) - ); - await queryRunner.changeColumn("stickers", "type", new TableColumn({ name: "type", type: "integer" })); - await queryRunner.changeColumn( - "stickers", - "format_type", - new TableColumn({ name: "format_type", type: "integer" }) - ); - await queryRunner.changeColumn( - "stickers", - "available", - new TableColumn({ name: "available", type: "boolean", isNullable: true }) - ); - await queryRunner.changeColumn( - "stickers", - "user_id", - new TableColumn({ name: "user_id", type: "boolean", isNullable: true }) - ); - await queryRunner.createForeignKey( - "stickers", - new TableForeignKey({ - name: "FK_8f4ee73f2bb2325ff980502e158", - columnNames: ["user_id"], - referencedColumnNames: ["id"], - referencedTableName: "users", - onDelete: "CASCADE", - }) - ); - await queryRunner.createTable( - new Table({ - name: "sticker_packs", - columns: [ - new TableColumn({ name: "id", type: "varchar", isPrimary: true }), - new TableColumn({ name: "name", type: "varchar" }), - new TableColumn({ name: "description", type: "varchar", isNullable: true }), - new TableColumn({ name: "banner_asset_id", type: "varchar", isNullable: true }), - new TableColumn({ name: "cover_sticker_id", type: "varchar", isNullable: true }), - ], - foreignKeys: [ - new TableForeignKey({ - columnNames: ["cover_sticker_id"], - referencedColumnNames: ["id"], - referencedTableName: "stickers", - }), - ], - }) - ); - } - - public async down(queryRunner: QueryRunner): Promise<void> {} -} diff --git a/util/src/migrations/1634424361103-Presence.ts b/util/src/migrations/1634424361103-Presence.ts deleted file mode 100644
index 729955b8..00000000 --- a/util/src/migrations/1634424361103-Presence.ts +++ /dev/null
@@ -1,11 +0,0 @@ -import { MigrationInterface, QueryRunner, TableColumn } from "typeorm"; - -export class Presence1634424361103 implements MigrationInterface { - name = "Presence1634424361103"; - - public async up(queryRunner: QueryRunner): Promise<void> { - queryRunner.addColumn("sessions", new TableColumn({ name: "activites", type: "text" })); - } - - public async down(queryRunner: QueryRunner): Promise<void> {} -} diff --git a/util/src/migrations/1634426540271-MigrationTimestamp.ts b/util/src/migrations/1634426540271-MigrationTimestamp.ts deleted file mode 100644
index 3208b25b..00000000 --- a/util/src/migrations/1634426540271-MigrationTimestamp.ts +++ /dev/null
@@ -1,15 +0,0 @@ -import { MigrationInterface, QueryRunner, TableColumn } from "typeorm"; - -export class MigrationTimestamp1634426540271 implements MigrationInterface { - name = "MigrationTimestamp1634426540271"; - - public async up(queryRunner: QueryRunner): Promise<void> { - await queryRunner.changeColumn( - "migrations", - "timestamp", - new TableColumn({ name: "timestampe", type: "bigint", isNullable: false }) - ); - } - - public async down(queryRunner: QueryRunner): Promise<void> {} -} diff --git a/util/src/migrations/1648643945733-ReleaseTypo.ts b/util/src/migrations/1648643945733-ReleaseTypo.ts deleted file mode 100644
index 944b9dd9..00000000 --- a/util/src/migrations/1648643945733-ReleaseTypo.ts +++ /dev/null
@@ -1,16 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class ReleaseTypo1648643945733 implements MigrationInterface { - name = "ReleaseTypo1648643945733"; - - public async up(queryRunner: QueryRunner): Promise<void> { - //drop table first because typeorm creates it before migrations run - await queryRunner.dropTable("client_release", true); - await queryRunner.renameTable("client_relase", "client_release"); - } - - public async down(queryRunner: QueryRunner): Promise<void> { - await queryRunner.dropTable("client_relase", true); - await queryRunner.renameTable("client_release", "client_relase"); - } -} diff --git a/util/src/util/Database.ts b/util/src/util/Database.ts deleted file mode 100644
index 9ab5d14c..00000000 --- a/util/src/util/Database.ts +++ /dev/null
@@ -1,72 +0,0 @@ -import path from "path"; -import "reflect-metadata"; -import { Connection, createConnection } from "typeorm"; -import * as Models from "../entities"; -import { Migration } from "../entities/Migration"; -import { yellow, green, red } from "picocolors"; - -// UUID extension option is only supported with postgres -// We want to generate all id's with Snowflakes that's why we have our own BaseEntity class - -var promise: Promise<any>; -var dbConnection: Connection | undefined; -let dbConnectionString = process.env.DATABASE || path.join(process.cwd(), "database.db"); - -export function initDatabase(): Promise<Connection> { - if (promise) return promise; // prevent initalizing multiple times - - const type = dbConnectionString.includes("://") ? dbConnectionString.split(":")[0]?.replace("+srv", "") : "sqlite"; - const isSqlite = type.includes("sqlite"); - - console.log(`[Database] ${yellow(`connecting to ${type} db`)}`); - if(isSqlite) { - console.log(`[Database] ${red(`You are running sqlite! Please keep in mind that we recommend setting up a dedicated database!`)}`); - } - // @ts-ignore - promise = createConnection({ - type, - charset: 'utf8mb4', - url: isSqlite ? undefined : dbConnectionString, - database: isSqlite ? dbConnectionString : undefined, - // @ts-ignore - entities: Object.values(Models).filter((x) => x.constructor.name !== "Object" && x.name), - synchronize: type !== "mongodb", - logging: false, - cache: { - duration: 1000 * 3, // cache all find queries for 3 seconds - }, - bigNumberStrings: false, - supportBigNumbers: true, - name: "default", - migrations: [path.join(__dirname, "..", "migrations", "*.js")], - }); - - promise.then(async (connection: Connection) => { - dbConnection = connection; - - // run migrations, and if it is a new fresh database, set it to the last migration - if (connection.migrations.length) { - if (!(await Migration.findOne({}))) { - let i = 0; - - await Migration.insert( - connection.migrations.map((x) => ({ - id: i++, - name: x.name, - timestamp: Date.now(), - })) - ); - } - } - await connection.runMigrations(); - console.log(`[Database] ${green("connected")}`); - }); - - return promise; -} - -export { dbConnection }; - -export function closeDatabase() { - dbConnection?.close(); -}