diff options
Diffstat (limited to 'src/util')
61 files changed, 691 insertions, 116 deletions
diff --git a/src/util/config/types/GeneralConfiguration.ts b/src/util/config/types/GeneralConfiguration.ts index c20fe9a7..cff8c527 100644 --- a/src/util/config/types/GeneralConfiguration.ts +++ b/src/util/config/types/GeneralConfiguration.ts @@ -28,4 +28,5 @@ export class GeneralConfiguration { correspondenceUserID: string | null = null; image: string | null = null; instanceId: string = Snowflake.generate(); + autoCreateBotUsers: boolean = false; } diff --git a/src/util/config/types/SecurityConfiguration.ts b/src/util/config/types/SecurityConfiguration.ts index 5e971cfe..35776642 100644 --- a/src/util/config/types/SecurityConfiguration.ts +++ b/src/util/config/types/SecurityConfiguration.ts @@ -28,7 +28,7 @@ export class SecurityConfiguration { // header to get the real user ip address // X-Forwarded-For for nginx/reverse proxies // CF-Connecting-IP for cloudflare - forwadedFor: string | null = null; + forwardedFor: string | null = null; ipdataApiKey: string | null = "eca677b284b3bac29eb72f5e496aa9047f26543605efe99ff2ce35c9"; mfaBackupCodeCount: number = 10; diff --git a/src/util/config/types/subconfigurations/limits/RateLimits.ts b/src/util/config/types/subconfigurations/limits/RateLimits.ts index caba740b..0ce0827c 100644 --- a/src/util/config/types/subconfigurations/limits/RateLimits.ts +++ b/src/util/config/types/subconfigurations/limits/RateLimits.ts @@ -16,11 +16,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -import { RouteRateLimit, RateLimitOptions } from "."; +import { RateLimitOptions, RouteRateLimit } from "."; export class RateLimits { enabled: boolean = false; - ip: Omit<RateLimitOptions, "bot_count"> = { + ip: RateLimitOptions = { count: 500, window: 5, }; diff --git a/src/util/entities/Channel.ts b/src/util/entities/Channel.ts index 72490028..19a7a41a 100644 --- a/src/util/entities/Channel.ts +++ b/src/util/entities/Channel.ts @@ -486,6 +486,29 @@ export enum ChannelPermissionOverwriteType { export interface DMChannel extends Omit<Channel, "type" | "recipients"> { type: ChannelType.DM | ChannelType.GROUP_DM; recipients: Recipient[]; +} - // TODO: probably more props +// TODO: probably more props +export function isTextChannel(type: ChannelType): boolean { + switch (type) { + case ChannelType.GUILD_STORE: + case ChannelType.GUILD_VOICE: + case ChannelType.GUILD_STAGE_VOICE: + case ChannelType.GUILD_CATEGORY: + case ChannelType.GUILD_FORUM: + case ChannelType.DIRECTORY: + throw new HTTPError("not a text channel", 400); + case ChannelType.DM: + case ChannelType.GROUP_DM: + case ChannelType.GUILD_NEWS: + case ChannelType.GUILD_NEWS_THREAD: + case ChannelType.GUILD_PUBLIC_THREAD: + case ChannelType.GUILD_PRIVATE_THREAD: + case ChannelType.GUILD_TEXT: + case ChannelType.ENCRYPTED: + case ChannelType.ENCRYPTED_THREAD: + return true; + default: + throw new HTTPError("unimplemented", 400); + } } diff --git a/src/util/entities/Guild.ts b/src/util/entities/Guild.ts index 64dc2420..4c2949a3 100644 --- a/src/util/entities/Guild.ts +++ b/src/util/entities/Guild.ts @@ -24,7 +24,7 @@ import { OneToMany, RelationId, } from "typeorm"; -import { Config, handleFile, Snowflake } from ".."; +import { Config, GuildWelcomeScreen, handleFile, Snowflake } from ".."; import { Ban } from "./Ban"; import { BaseClass } from "./BaseClass"; import { Channel } from "./Channel"; @@ -77,7 +77,7 @@ export class Guild extends BaseClass { afk_channel?: Channel; @Column({ nullable: true }) - afk_timeout?: number = Config.get().defaults.guild.afkTimeout; + afk_timeout?: number; // * commented out -> use owner instead // application id of the guild creator if it is bot-created @@ -95,8 +95,7 @@ export class Guild extends BaseClass { banner?: string; @Column({ nullable: true }) - default_message_notifications?: number = - Config.get().defaults.guild.defaultMessageNotifications; + default_message_notifications?: number; @Column({ nullable: true }) description?: string; @@ -105,11 +104,10 @@ export class Guild extends BaseClass { discovery_splash?: string; @Column({ nullable: true }) - explicit_content_filter?: number = - Config.get().defaults.guild.explicitContentFilter; + explicit_content_filter?: number; @Column({ type: "simple-array" }) - features: string[] = Config.get().guild.defaultFeatures || []; //TODO use enum + features: string[] = []; //TODO use enum //TODO: https://discord.com/developers/docs/resources/guild#guild-object-guild-features @Column({ nullable: true }) @@ -122,14 +120,13 @@ export class Guild extends BaseClass { large?: boolean = false; @Column({ nullable: true }) - max_members?: number = Config.get().limits.guild.maxMembers; + max_members?: number; @Column({ nullable: true }) - max_presences?: number = Config.get().defaults.guild.maxPresences; + max_presences?: number; @Column({ nullable: true }) - max_video_channel_users?: number = - Config.get().defaults.guild.maxVideoChannelUsers; + max_video_channel_users?: number; @Column({ nullable: true }) member_count?: number; @@ -247,7 +244,7 @@ export class Guild extends BaseClass { rules_channel?: string; @Column({ nullable: true }) - region?: string = Config.get().regions.default; + region?: string; @Column({ nullable: true }) splash?: string; @@ -270,16 +267,7 @@ export class Guild extends BaseClass { verification_level?: number; @Column({ type: "simple-json" }) - welcome_screen: { - enabled: boolean; - description: string; - welcome_channels: { - description: string; - emoji_id?: string; - emoji_name?: string; - channel_id: string; - }[]; - }; + welcome_screen: GuildWelcomeScreen; @Column({ nullable: true }) @RelationId((guild: Guild) => guild.widget_channel) @@ -336,6 +324,18 @@ export class Guild extends BaseClass { description: "Fill in your description", welcome_channels: [], }, + + afk_timeout: Config.get().defaults.guild.afkTimeout, + default_message_notifications: + Config.get().defaults.guild.defaultMessageNotifications, + explicit_content_filter: + Config.get().defaults.guild.explicitContentFilter, + features: Config.get().guild.defaultFeatures, + max_members: Config.get().limits.guild.maxMembers, + max_presences: Config.get().defaults.guild.maxPresences, + max_video_channel_users: + Config.get().defaults.guild.maxVideoChannelUsers, + region: Config.get().regions.default, }).save(); // we have to create the role _after_ the guild because else we would get a "SQLITE_CONSTRAINT: FOREIGN KEY constraint failed" error diff --git a/src/util/entities/Member.ts b/src/util/entities/Member.ts index 8c208202..8be6eae1 100644 --- a/src/util/entities/Member.ts +++ b/src/util/entities/Member.ts @@ -344,11 +344,7 @@ export class Member extends BaseClassWithoutId { relations: ["user", "roles"], take: 10, }) - ).map((member) => ({ - ...member.toPublicMember(), - user: member.user.toPublicUser(), - roles: member.roles.map((x) => x.id), - })); + ).map((member) => member.toPublicMember()); if ( await Member.count({ @@ -455,6 +451,10 @@ export class Member extends BaseClassWithoutId { PublicMemberProjection.forEach((x) => { member[x] = this[x]; }); + + if (member.roles) member.roles = member.roles.map((x: Role) => x.id); + if (member.user) member.user = member.user.toPublicUser(); + return member as PublicMember; } } diff --git a/src/util/entities/User.ts b/src/util/entities/User.ts index b30a7c58..68d7b5e8 100644 --- a/src/util/entities/User.ts +++ b/src/util/entities/User.ts @@ -26,11 +26,11 @@ import { OneToOne, } from "typeorm"; import { - adjustEmail, Config, Email, FieldErrors, Snowflake, + adjustEmail, trimSpecial, } from ".."; import { BitField } from "../util/BitField"; @@ -86,8 +86,7 @@ export const PrivateUserProjection = [ // Private user data that should never get sent to the client export type PublicUser = Pick<User, PublicUserKeys>; - -export type UserPublic = Pick<User, PublicUserKeys>; +export type PrivateUser = Pick<User, PrivateUserKeys>; export interface UserPrivate extends Pick<User, PrivateUserKeys> { locale: string; @@ -110,8 +109,10 @@ export class User extends BaseClass { @Column({ nullable: true }) banner?: string; // hash of the user banner + // TODO: Separate `User` and `UserProfile` models + // puyo: changed from [number, number] because it breaks openapi @Column({ nullable: true, type: "simple-array" }) - theme_colors?: [number, number]; // TODO: Separate `User` and `UserProfile` models + theme_colors?: number[]; @Column({ nullable: true }) pronouns?: string; @@ -126,10 +127,10 @@ export class User extends BaseClass { mobile: boolean = false; // if the user has mobile app installed @Column() - premium: boolean = Config.get().defaults.user.premium ?? false; // if user bought individual premium + premium: boolean; // if user bought individual premium @Column() - premium_type: number = Config.get().defaults.user.premiumType ?? 0; // individual premium level + premium_type: number; // individual premium level @Column() bot: boolean = false; // if user is bot @@ -156,13 +157,13 @@ export class User extends BaseClass { totp_last_ticket?: string = ""; @Column() - created_at: Date = new Date(); // registration date + created_at: Date; // registration date @Column({ nullable: true }) premium_since: Date; // premium date @Column({ select: false }) - verified: boolean = Config.get().defaults.user.verified ?? true; // email is verified + verified: boolean; // email is verified @Column() disabled: boolean = false; // if the account is disabled @@ -390,11 +391,16 @@ export class User extends BaseClass { valid_tokens_since: new Date(), }, extended_settings: "{}", + settings: settings, + premium_since: Config.get().defaults.user.premium ? new Date() : undefined, - settings: settings, rights: Config.get().register.defaultRights, + premium: Config.get().defaults.user.premium ?? false, + premium_type: Config.get().defaults.user.premiumType ?? 0, + verified: Config.get().defaults.user.verified ?? true, + created_at: new Date(), }); user.validate(); diff --git a/src/util/interfaces/Activity.ts b/src/util/interfaces/Activity.ts index 7654ba90..0227f242 100644 --- a/src/util/interfaces/Activity.ts +++ b/src/util/interfaces/Activity.ts @@ -36,7 +36,7 @@ export interface Activity { }; party?: { id?: string; - size?: [number]; // used to show the party's current and maximum size // TODO: array length 2 + size?: number[]; // used to show the party's current and maximum size // TODO: array length 2 }; assets?: { large_image?: string; // the id for a large asset of the activity, usually a snowflake diff --git a/src/util/interfaces/GuildWelcomeScreen.ts b/src/util/interfaces/GuildWelcomeScreen.ts new file mode 100644 index 00000000..38b6061b --- /dev/null +++ b/src/util/interfaces/GuildWelcomeScreen.ts @@ -0,0 +1,10 @@ +export interface GuildWelcomeScreen { + enabled: boolean; + description: string; + welcome_channels: { + description: string; + emoji_id?: string; + emoji_name?: string; + channel_id: string; + }[]; +} diff --git a/src/util/interfaces/index.ts b/src/util/interfaces/index.ts index c6a00458..6620ba32 100644 --- a/src/util/interfaces/index.ts +++ b/src/util/interfaces/index.ts @@ -19,6 +19,7 @@ export * from "./Activity"; export * from "./ConnectedAccount"; export * from "./Event"; +export * from "./GuildWelcomeScreen"; export * from "./Interaction"; export * from "./Presence"; export * from "./Status"; diff --git a/src/util/schemas/AckBulkSchema.ts b/src/util/schemas/AckBulkSchema.ts index cf6dc597..5604c2fc 100644 --- a/src/util/schemas/AckBulkSchema.ts +++ b/src/util/schemas/AckBulkSchema.ts @@ -17,11 +17,9 @@ */ export interface AckBulkSchema { - read_states: [ - { - channel_id: string; - message_id: string; - read_state_type: number; // WHat is this? - }, - ]; + read_states: { + channel_id: string; + message_id: string; + read_state_type: number; // WHat is this? + }[]; } diff --git a/src/util/schemas/IdentifySchema.ts b/src/util/schemas/IdentifySchema.ts index fb48c2a4..0619dacc 100644 --- a/src/util/schemas/IdentifySchema.ts +++ b/src/util/schemas/IdentifySchema.ts @@ -66,6 +66,7 @@ export const IdentifySchema = { $private_channels_version: Number, $guild_versions: Object, $api_code_version: Number, + $initial_guild_id: String, }, $clientState: { $guildHashes: Object, @@ -75,6 +76,7 @@ export const IdentifySchema = { $userGuildSettingsVersion: undefined, $guildVersions: Object, $apiCodeVersion: Number, + $initialGuildId: String, }, $v: Number, $version: Number, @@ -109,7 +111,11 @@ export interface IdentifySchema { compress?: boolean; large_threshold?: number; largeThreshold?: number; - shard?: [bigint, bigint]; + /** + * @minItems 2 + * @maxItems 2 + */ + shard?: bigint[]; // puyo: changed from [bigint, bigint] because it breaks openapi guild_subscriptions?: boolean; capabilities?: number; client_state?: { @@ -122,6 +128,7 @@ export interface IdentifySchema { private_channels_version?: number; guild_versions?: unknown; api_code_version?: number; + initial_guild_id?: string; }; clientState?: { guildHashes?: unknown; @@ -131,6 +138,7 @@ export interface IdentifySchema { useruserGuildSettingsVersion?: number; guildVersions?: unknown; apiCodeVersion?: number; + initialGuildId?: string; }; v?: number; } diff --git a/src/util/schemas/LazyRequestSchema.ts b/src/util/schemas/LazyRequestSchema.ts index 63e67416..ee52d66c 100644 --- a/src/util/schemas/LazyRequestSchema.ts +++ b/src/util/schemas/LazyRequestSchema.ts @@ -18,7 +18,14 @@ export interface LazyRequestSchema { guild_id: string; - channels?: Record<string, [number, number][]>; + channels?: { + /** + * @items.type integer + * @minItems 2 + * @maxItems 2 + */ + [key: string]: number[][]; // puyo: changed from [number, number] because it breaks openapi + }; activities?: boolean; threads?: boolean; typing?: true; diff --git a/src/util/schemas/LoginResponse.ts b/src/util/schemas/LoginResponse.ts new file mode 100644 index 00000000..faf3f769 --- /dev/null +++ b/src/util/schemas/LoginResponse.ts @@ -0,0 +1,14 @@ +import { TokenResponse } from "./responses"; + +export interface MFAResponse { + ticket: string; + mfa: true; + sms: false; // TODO + token: null; +} + +export interface WebAuthnResponse extends MFAResponse { + webauthn: string; +} + +export type LoginResponse = TokenResponse | MFAResponse | WebAuthnResponse; diff --git a/src/util/schemas/MemberChangeProfileSchema.ts b/src/util/schemas/MemberChangeProfileSchema.ts index e955a0f1..d2d1481d 100644 --- a/src/util/schemas/MemberChangeProfileSchema.ts +++ b/src/util/schemas/MemberChangeProfileSchema.ts @@ -21,8 +21,7 @@ export interface MemberChangeProfileSchema { nick?: string; bio?: string; pronouns?: string; - - /* + /** * @items.type integer */ theme_colors?: [number, number]; diff --git a/src/util/schemas/UserGuildSettingsSchema.ts b/src/util/schemas/UserGuildSettingsSchema.ts index c295f767..82edae9c 100644 --- a/src/util/schemas/UserGuildSettingsSchema.ts +++ b/src/util/schemas/UserGuildSettingsSchema.ts @@ -16,12 +16,12 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -import { UserGuildSettings, ChannelOverride } from "@spacebar/util"; +import { ChannelOverride, UserGuildSettings } from "@spacebar/util"; // This sucks. I would use a DeepPartial, my own or typeorms, but they both generate inncorect schema export interface UserGuildSettingsSchema extends Partial<Omit<UserGuildSettings, "channel_overrides">> { channel_overrides?: { - [channel_id: string]: Partial<ChannelOverride>; + [channel_id: string]: ChannelOverride; }; } diff --git a/src/util/schemas/UserNoteUpdateSchema.ts b/src/util/schemas/UserNoteUpdateSchema.ts new file mode 100644 index 00000000..0a731279 --- /dev/null +++ b/src/util/schemas/UserNoteUpdateSchema.ts @@ -0,0 +1,3 @@ +export interface UserNoteUpdateSchema { + note: string; +} diff --git a/src/util/schemas/UserProfileModifySchema.ts b/src/util/schemas/UserProfileModifySchema.ts index d49fe326..3dea257a 100644 --- a/src/util/schemas/UserProfileModifySchema.ts +++ b/src/util/schemas/UserProfileModifySchema.ts @@ -21,8 +21,7 @@ export interface UserProfileModifySchema { accent_color?: number | null; banner?: string | null; pronouns?: string; - - /* + /** * @items.type integer */ theme_colors?: [number, number]; diff --git a/src/util/schemas/UserProfileResponse.ts b/src/util/schemas/UserProfileResponse.ts deleted file mode 100644 index 699d6a29..00000000 --- a/src/util/schemas/UserProfileResponse.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - Spacebar: A FOSS re-implementation and extension of the Discord.com backend. - Copyright (C) 2023 Spacebar and Spacebar Contributors - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ - -import { PublicConnectedAccount, UserPublic } from ".."; - -export interface UserProfileResponse { - user: UserPublic; - connected_accounts: PublicConnectedAccount; - premium_guild_since?: Date; - premium_since?: Date; -} diff --git a/src/util/schemas/UserRelationsResponse.ts b/src/util/schemas/UserRelationsResponse.ts deleted file mode 100644 index 38507420..00000000 --- a/src/util/schemas/UserRelationsResponse.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - Spacebar: A FOSS re-implementation and extension of the Discord.com backend. - Copyright (C) 2023 Spacebar and Spacebar Contributors - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ - -export interface UserRelationsResponse { - object: { - id?: string; - username?: string; - avatar?: string; - discriminator?: string; - public_flags?: number; - }; -} diff --git a/src/util/schemas/VoiceStateUpdateSchema.ts b/src/util/schemas/VoiceStateUpdateSchema.ts index a7d9f9d7..fda073e9 100644 --- a/src/util/schemas/VoiceStateUpdateSchema.ts +++ b/src/util/schemas/VoiceStateUpdateSchema.ts @@ -26,6 +26,7 @@ export interface VoiceStateUpdateSchema { preferred_region?: string; request_to_speak_timestamp?: Date; suppress?: boolean; + flags?: number; } export const VoiceStateUpdateSchema = { @@ -37,4 +38,5 @@ export const VoiceStateUpdateSchema = { $preferred_region: String, $request_to_speak_timestamp: Date, $suppress: Boolean, + $flags: Number, }; diff --git a/src/util/schemas/WebAuthnSchema.ts b/src/util/schemas/WebAuthnSchema.ts index 652cda34..3f5e0da7 100644 --- a/src/util/schemas/WebAuthnSchema.ts +++ b/src/util/schemas/WebAuthnSchema.ts @@ -28,9 +28,9 @@ export interface CreateWebAuthnCredentialSchema { ticket: string; } -export type WebAuthnPostSchema = Partial< - GenerateWebAuthnCredentialsSchema | CreateWebAuthnCredentialSchema ->; +export type WebAuthnPostSchema = + | GenerateWebAuthnCredentialsSchema + | CreateWebAuthnCredentialSchema; export interface WebAuthnTotpSchema { code: string; diff --git a/src/util/schemas/index.ts b/src/util/schemas/index.ts index 2d254752..44a504cd 100644 --- a/src/util/schemas/index.ts +++ b/src/util/schemas/index.ts @@ -69,6 +69,7 @@ export * from "./TotpSchema"; export * from "./UserDeleteSchema"; export * from "./UserGuildSettingsSchema"; export * from "./UserModifySchema"; +export * from "./UserNoteUpdateSchema"; export * from "./UserProfileModifySchema"; export * from "./UserSettingsSchema"; export * from "./Validator"; @@ -79,7 +80,4 @@ export * from "./VoiceVideoSchema"; export * from "./WebAuthnSchema"; export * from "./WebhookCreateSchema"; export * from "./WidgetModifySchema"; -export * from "./UserRelationsResponse"; -export * from "./GatewayResponse"; -export * from "./GatewayBotResponse"; -export * from "./UserProfileResponse"; +export * from "./responses"; diff --git a/src/util/schemas/responses/APIErrorOrCaptchaResponse.ts b/src/util/schemas/responses/APIErrorOrCaptchaResponse.ts new file mode 100644 index 00000000..c9a0e5be --- /dev/null +++ b/src/util/schemas/responses/APIErrorOrCaptchaResponse.ts @@ -0,0 +1,6 @@ +import { APIErrorResponse } from "./APIErrorResponse"; +import { CaptchaRequiredResponse } from "./CaptchaRequiredResponse"; + +export type APIErrorOrCaptchaResponse = + | CaptchaRequiredResponse + | APIErrorResponse; diff --git a/src/util/schemas/responses/APIErrorResponse.ts b/src/util/schemas/responses/APIErrorResponse.ts new file mode 100644 index 00000000..25bb9504 --- /dev/null +++ b/src/util/schemas/responses/APIErrorResponse.ts @@ -0,0 +1,12 @@ +export interface APIErrorResponse { + code: number; + message: string; + errors: { + [key: string]: { + _errors: { + message: string; + code: string; + }[]; + }; + }; +} diff --git a/src/util/schemas/responses/BackupCodesChallengeResponse.ts b/src/util/schemas/responses/BackupCodesChallengeResponse.ts new file mode 100644 index 00000000..5473ad1f --- /dev/null +++ b/src/util/schemas/responses/BackupCodesChallengeResponse.ts @@ -0,0 +1,4 @@ +export interface BackupCodesChallengeResponse { + nonce: string; + regenerate_nonce: string; +} diff --git a/src/util/schemas/responses/CaptchaRequiredResponse.ts b/src/util/schemas/responses/CaptchaRequiredResponse.ts new file mode 100644 index 00000000..9f7f02ff --- /dev/null +++ b/src/util/schemas/responses/CaptchaRequiredResponse.ts @@ -0,0 +1,5 @@ +export interface CaptchaRequiredResponse { + captcha_key: string; + captcha_sitekey: string; + captcha_service: string; +} diff --git a/src/util/schemas/responses/DiscoverableGuildsResponse.ts b/src/util/schemas/responses/DiscoverableGuildsResponse.ts new file mode 100644 index 00000000..2a9fb1bd --- /dev/null +++ b/src/util/schemas/responses/DiscoverableGuildsResponse.ts @@ -0,0 +1,8 @@ +import { Guild } from "../../entities"; + +export interface DiscoverableGuildsResponse { + total: number; + guilds: Guild[]; + offset: number; + limit: number; +} diff --git a/src/util/schemas/responses/GatewayBotResponse.ts b/src/util/schemas/responses/GatewayBotResponse.ts new file mode 100644 index 00000000..30f1f57f --- /dev/null +++ b/src/util/schemas/responses/GatewayBotResponse.ts @@ -0,0 +1,10 @@ +export interface GatewayBotResponse { + url: string; + shards: number; + session_start_limit: { + total: number; + remaining: number; + reset_after: number; + max_concurrency: number; + }; +} diff --git a/src/util/schemas/responses/GatewayResponse.ts b/src/util/schemas/responses/GatewayResponse.ts new file mode 100644 index 00000000..e909f7bd --- /dev/null +++ b/src/util/schemas/responses/GatewayResponse.ts @@ -0,0 +1,3 @@ +export interface GatewayResponse { + url: string; +} diff --git a/src/util/schemas/responses/GenerateRegistrationTokensResponse.ts b/src/util/schemas/responses/GenerateRegistrationTokensResponse.ts new file mode 100644 index 00000000..8816eabf --- /dev/null +++ b/src/util/schemas/responses/GenerateRegistrationTokensResponse.ts @@ -0,0 +1,3 @@ +export interface GenerateRegistrationTokensResponse { + tokens: string[]; +} diff --git a/src/util/schemas/responses/GuildBansResponse.ts b/src/util/schemas/responses/GuildBansResponse.ts new file mode 100644 index 00000000..876a4bc4 --- /dev/null +++ b/src/util/schemas/responses/GuildBansResponse.ts @@ -0,0 +1,10 @@ +export interface GuildBansResponse { + reason: string; + user: { + username: string; + discriminator: string; + id: string; + avatar: string | null; + public_flags: number; + }; +} diff --git a/src/util/schemas/responses/GuildCreateResponse.ts b/src/util/schemas/responses/GuildCreateResponse.ts new file mode 100644 index 00000000..8185cb86 --- /dev/null +++ b/src/util/schemas/responses/GuildCreateResponse.ts @@ -0,0 +1,3 @@ +export interface GuildCreateResponse { + id: string; +} diff --git a/src/util/schemas/responses/GuildDiscoveryRequirements.ts b/src/util/schemas/responses/GuildDiscoveryRequirements.ts new file mode 100644 index 00000000..731976f7 --- /dev/null +++ b/src/util/schemas/responses/GuildDiscoveryRequirements.ts @@ -0,0 +1,23 @@ +export interface GuildDiscoveryRequirementsResponse { + uild_id: string; + safe_environment: boolean; + healthy: boolean; + health_score_pending: boolean; + size: boolean; + nsfw_properties: unknown; + protected: boolean; + sufficient: boolean; + sufficient_without_grace_period: boolean; + valid_rules_channel: boolean; + retention_healthy: boolean; + engagement_healthy: boolean; + age: boolean; + minimum_age: number; + health_score: { + avg_nonnew_participators: number; + avg_nonnew_communicators: number; + num_intentful_joiners: number; + perc_ret_w1_intentful: number; + }; + minimum_size: number; +} diff --git a/src/util/schemas/responses/GuildMessagesSearchResponse.ts b/src/util/schemas/responses/GuildMessagesSearchResponse.ts new file mode 100644 index 00000000..0b6248b7 --- /dev/null +++ b/src/util/schemas/responses/GuildMessagesSearchResponse.ts @@ -0,0 +1,32 @@ +import { + Attachment, + Embed, + MessageType, + PublicUser, + Role, +} from "../../entities"; + +export interface GuildMessagesSearchMessage { + id: string; + type: MessageType; + content?: string; + channel_id: string; + author: PublicUser; + attachments: Attachment[]; + embeds: Embed[]; + mentions: PublicUser[]; + mention_roles: Role[]; + pinned: boolean; + mention_everyone?: boolean; + tts: boolean; + timestamp: string; + edited_timestamp: string | null; + flags: number; + components: unknown[]; + hit: true; +} + +export interface GuildMessagesSearchResponse { + messages: GuildMessagesSearchMessage[]; + total_results: number; +} diff --git a/src/util/schemas/responses/GuildPruneResponse.ts b/src/util/schemas/responses/GuildPruneResponse.ts new file mode 100644 index 00000000..fb1abb89 --- /dev/null +++ b/src/util/schemas/responses/GuildPruneResponse.ts @@ -0,0 +1,7 @@ +export interface GuildPruneResponse { + pruned: number; +} + +export interface GuildPurgeResponse { + purged: number; +} diff --git a/src/util/schemas/responses/GuildRecommendationsResponse.ts b/src/util/schemas/responses/GuildRecommendationsResponse.ts new file mode 100644 index 00000000..211670a6 --- /dev/null +++ b/src/util/schemas/responses/GuildRecommendationsResponse.ts @@ -0,0 +1,6 @@ +import { Guild } from "../../entities"; + +export interface GuildRecommendationsResponse { + recommended_guilds: Guild[]; + load_id: string; +} diff --git a/src/util/schemas/responses/GuildVanityUrl.ts b/src/util/schemas/responses/GuildVanityUrl.ts new file mode 100644 index 00000000..ff37bf4e --- /dev/null +++ b/src/util/schemas/responses/GuildVanityUrl.ts @@ -0,0 +1,17 @@ +export interface GuildVanityUrl { + code: string; + uses: number; +} + +export interface GuildVanityUrlNoInvite { + code: null; +} + +export type GuildVanityUrlResponse = + | GuildVanityUrl + | GuildVanityUrl[] + | GuildVanityUrlNoInvite; + +export interface GuildVanityUrlCreateResponse { + code: string; +} diff --git a/src/util/schemas/responses/GuildVoiceRegionsResponse.ts b/src/util/schemas/responses/GuildVoiceRegionsResponse.ts new file mode 100644 index 00000000..8190d5fd --- /dev/null +++ b/src/util/schemas/responses/GuildVoiceRegionsResponse.ts @@ -0,0 +1,7 @@ +export interface GuildVoiceRegion { + id: string; + name: string; + custom: boolean; + deprecated: boolean; + optimal: boolean; +} diff --git a/src/util/schemas/responses/GuildWidgetJsonResponse.ts b/src/util/schemas/responses/GuildWidgetJsonResponse.ts new file mode 100644 index 00000000..ef85dd08 --- /dev/null +++ b/src/util/schemas/responses/GuildWidgetJsonResponse.ts @@ -0,0 +1,21 @@ +import { ClientStatus } from "../../interfaces"; + +export interface GuildWidgetJsonResponse { + id: string; + name: string; + instant_invite: string; + channels: { + id: string; + name: string; + position: number; + }[]; + members: { + id: string; + username: string; + discriminator: string; + avatar: string | null; + status: ClientStatus; + avatar_url: string; + }[]; + presence_count: number; +} diff --git a/src/util/schemas/responses/GuildWidgetSettingsResponse.ts b/src/util/schemas/responses/GuildWidgetSettingsResponse.ts new file mode 100644 index 00000000..3c6b45ce --- /dev/null +++ b/src/util/schemas/responses/GuildWidgetSettingsResponse.ts @@ -0,0 +1,6 @@ +import { Snowflake } from "../../util"; + +export interface GuildWidgetSettingsResponse { + enabled: boolean; + channel_id: Snowflake | null; +} diff --git a/src/util/schemas/responses/InstanceDomainsResponse.ts b/src/util/schemas/responses/InstanceDomainsResponse.ts new file mode 100644 index 00000000..60367492 --- /dev/null +++ b/src/util/schemas/responses/InstanceDomainsResponse.ts @@ -0,0 +1,6 @@ +export interface InstanceDomainsResponse { + cdn: string; + gateway: string; + defaultApiVersion: string; + apiEndpoint: string; +} diff --git a/src/util/schemas/responses/InstancePingResponse.ts b/src/util/schemas/responses/InstancePingResponse.ts new file mode 100644 index 00000000..5f1a9488 --- /dev/null +++ b/src/util/schemas/responses/InstancePingResponse.ts @@ -0,0 +1,13 @@ +export interface InstancePingResponse { + ping: "pong!"; + instance: { + id: string; + name: string; + description: string | null; + image: string | null; + correspondenceEmail: string | null; + correspondenceUserID: string | null; + frontPage: string | null; + tosPage: string | null; + }; +} diff --git a/src/util/schemas/responses/InstanceStatsResponse.ts b/src/util/schemas/responses/InstanceStatsResponse.ts new file mode 100644 index 00000000..d24fd434 --- /dev/null +++ b/src/util/schemas/responses/InstanceStatsResponse.ts @@ -0,0 +1,8 @@ +export interface InstanceStatsResponse { + counts: { + user: number; + guild: number; + message: number; + members: number; + }; +} diff --git a/src/util/schemas/responses/LocationMetadataResponse.ts b/src/util/schemas/responses/LocationMetadataResponse.ts new file mode 100644 index 00000000..55337557 --- /dev/null +++ b/src/util/schemas/responses/LocationMetadataResponse.ts @@ -0,0 +1,5 @@ +export interface LocationMetadataResponse { + consent_required: boolean; + country_code: string; + promotional_email_opt_in: { required: true; pre_checked: false }; +} diff --git a/src/util/schemas/responses/MemberJoinGuildResponse.ts b/src/util/schemas/responses/MemberJoinGuildResponse.ts new file mode 100644 index 00000000..d7b39d10 --- /dev/null +++ b/src/util/schemas/responses/MemberJoinGuildResponse.ts @@ -0,0 +1,8 @@ +import { Emoji, Guild, Role, Sticker } from "../../entities"; + +export interface MemberJoinGuildResponse { + guild: Guild; + emojis: Emoji[]; + roles: Role[]; + stickers: Sticker[]; +} diff --git a/src/util/schemas/responses/OAuthAuthorizeResponse.ts b/src/util/schemas/responses/OAuthAuthorizeResponse.ts new file mode 100644 index 00000000..60d6d2e2 --- /dev/null +++ b/src/util/schemas/responses/OAuthAuthorizeResponse.ts @@ -0,0 +1,3 @@ +export interface OAuthAuthorizeResponse { + location: string; +} diff --git a/src/util/schemas/responses/Tenor.ts b/src/util/schemas/responses/Tenor.ts new file mode 100644 index 00000000..9dddf9d0 --- /dev/null +++ b/src/util/schemas/responses/Tenor.ts @@ -0,0 +1,72 @@ +export enum TenorMediaTypes { + gif, + mediumgif, + tinygif, + nanogif, + mp4, + loopedmp4, + tinymp4, + nanomp4, + webm, + tinywebm, + nanowebm, +} + +export type TenorMedia = { + preview: string; + url: string; + dims: number[]; + size: number; +}; + +export type TenorGif = { + created: number; + hasaudio: boolean; + id: string; + media: { [type in keyof typeof TenorMediaTypes]: TenorMedia }[]; + tags: string[]; + title: string; + itemurl: string; + hascaption: boolean; + url: string; +}; + +export type TenorCategory = { + searchterm: string; + path: string; + image: string; + name: string; +}; + +export type TenorCategoriesResults = { + tags: TenorCategory[]; +}; + +export type TenorTrendingResults = { + next: string; + results: TenorGif[]; + locale: string; +}; + +export type TenorSearchResults = { + next: string; + results: TenorGif[]; +}; + +export interface TenorGifResponse { + id: string; + title: string; + url: string; + src: string; + gif_src: string; + width: number; + height: number; + preview: string; +} + +export interface TenorTrendingResponse { + categories: TenorCategoriesResults; + gifs: TenorGifResponse[]; +} + +export type TenorGifsResponse = TenorGifResponse[]; diff --git a/src/util/schemas/responses/TokenResponse.ts b/src/util/schemas/responses/TokenResponse.ts new file mode 100644 index 00000000..7e93055a --- /dev/null +++ b/src/util/schemas/responses/TokenResponse.ts @@ -0,0 +1,15 @@ +import { BackupCode, UserSettings } from "../../entities"; + +export interface TokenResponse { + token: string; + settings: UserSettings; +} + +export interface TokenOnlyResponse { + token: string; +} + +export interface TokenWithBackupCodesResponse { + token: string; + backup_codes: BackupCode[]; +} diff --git a/src/util/schemas/responses/TypedResponses.ts b/src/util/schemas/responses/TypedResponses.ts new file mode 100644 index 00000000..4349b93c --- /dev/null +++ b/src/util/schemas/responses/TypedResponses.ts @@ -0,0 +1,88 @@ +import { GeneralConfiguration, LimitsConfiguration } from "../../config"; +import { DmChannelDTO } from "../../dtos"; +import { + Application, + BackupCode, + Categories, + Channel, + Emoji, + Guild, + Invite, + Member, + Message, + PrivateUser, + PublicMember, + PublicUser, + Role, + Sticker, + StickerPack, + Template, + Webhook, +} from "../../entities"; +import { GuildVoiceRegion } from "./GuildVoiceRegionsResponse"; + +// removes internal properties from the guild class +export type APIGuild = Omit< + Guild, + | "afk_channel" + | "template" + | "owner" + | "public_updates_channel" + | "rules_channel" + | "system_channel" + | "widget_channel" +>; + +export type APIPublicUser = PublicUser; +export type APIPrivateUser = PrivateUser; + +export type APIGuildArray = APIGuild[]; + +export type APIDMChannelArray = DmChannelDTO[]; + +export type APIBackupCodeArray = BackupCode[]; + +export interface UserUpdateResponse extends APIPrivateUser { + newToken?: string; +} + +export type ApplicationDetectableResponse = unknown[]; + +export type ApplicationEntitlementsResponse = unknown[]; + +export type ApplicationSkusResponse = unknown[]; + +export type APIApplicationArray = Application[]; + +export type APIInviteArray = Invite[]; + +export type APIMessageArray = Message[]; + +export type APIWebhookArray = Webhook[]; + +export type APIDiscoveryCategoryArray = Categories[]; + +export type APIGeneralConfiguration = GeneralConfiguration; + +export type APIChannelArray = Channel[]; + +export type APIEmojiArray = Emoji[]; + +export type APIMemberArray = Member[]; +export type APIPublicMember = PublicMember; + +export interface APIGuildWithJoinedAt extends Guild { + joined_at: string; +} + +export type APIRoleArray = Role[]; + +export type APIStickerArray = Sticker[]; + +export type APITemplateArray = Template[]; + +export type APIGuildVoiceRegion = GuildVoiceRegion[]; + +export type APILimitsConfiguration = LimitsConfiguration; + +export type APIStickerPackArray = StickerPack[]; diff --git a/src/util/schemas/responses/UpdatesResponse.ts b/src/util/schemas/responses/UpdatesResponse.ts new file mode 100644 index 00000000..6b8566f4 --- /dev/null +++ b/src/util/schemas/responses/UpdatesResponse.ts @@ -0,0 +1,6 @@ +export interface UpdatesResponse { + name: string; + pub_date: string; + url: string; + notes: string | null; +} diff --git a/src/util/schemas/responses/UserNoteResponse.ts b/src/util/schemas/responses/UserNoteResponse.ts new file mode 100644 index 00000000..b142811e --- /dev/null +++ b/src/util/schemas/responses/UserNoteResponse.ts @@ -0,0 +1,5 @@ +export interface UserNoteResponse { + note: string; + note_user_id: string; + user_id: string; +} diff --git a/src/util/schemas/responses/UserProfileResponse.ts b/src/util/schemas/responses/UserProfileResponse.ts new file mode 100644 index 00000000..eba7cbcc --- /dev/null +++ b/src/util/schemas/responses/UserProfileResponse.ts @@ -0,0 +1,37 @@ +import { + Member, + PublicConnectedAccount, + PublicMember, + PublicUser, + User, +} from "@spacebar/util"; + +export type MutualGuild = { + id: string; + nick?: string; +}; + +export type PublicMemberProfile = Pick< + Member, + "banner" | "bio" | "guild_id" +> & { + accent_color: null; // TODO +}; + +export type UserProfile = Pick< + User, + "bio" | "accent_color" | "banner" | "pronouns" | "theme_colors" +>; + +export interface UserProfileResponse { + user: PublicUser; + connected_accounts: PublicConnectedAccount; + premium_guild_since?: Date; + premium_since?: Date; + mutual_guilds: MutualGuild[]; + premium_type: number; + profile_themes_experiment_bucket: number; + user_profile: UserProfile; + guild_member?: PublicMember; + guild_member_profile?: PublicMemberProfile; +} diff --git a/src/util/schemas/responses/UserRelationsResponse.ts b/src/util/schemas/responses/UserRelationsResponse.ts new file mode 100644 index 00000000..e784cafb --- /dev/null +++ b/src/util/schemas/responses/UserRelationsResponse.ts @@ -0,0 +1,7 @@ +import { User } from "@spacebar/util"; + +export type UserRelationsResponse = (Pick<User, "id"> & + Pick<User, "username"> & + Pick<User, "discriminator"> & + Pick<User, "avatar"> & + Pick<User, "public_flags">)[]; diff --git a/src/util/schemas/responses/UserRelationshipsResponse.ts b/src/util/schemas/responses/UserRelationshipsResponse.ts new file mode 100644 index 00000000..dff2f118 --- /dev/null +++ b/src/util/schemas/responses/UserRelationshipsResponse.ts @@ -0,0 +1,8 @@ +import { PublicUser, RelationshipType } from "../../entities"; + +export interface UserRelationshipsResponse { + id: string; + type: RelationshipType; + nickname: null; + user: PublicUser; +} diff --git a/src/util/schemas/responses/WebAuthnCreateResponse.ts b/src/util/schemas/responses/WebAuthnCreateResponse.ts new file mode 100644 index 00000000..9aa9e206 --- /dev/null +++ b/src/util/schemas/responses/WebAuthnCreateResponse.ts @@ -0,0 +1,4 @@ +export interface WebAuthnCreateResponse { + name: string; + id: string; +} diff --git a/src/util/schemas/responses/WebhookCreateResponse.ts b/src/util/schemas/responses/WebhookCreateResponse.ts new file mode 100644 index 00000000..ae142632 --- /dev/null +++ b/src/util/schemas/responses/WebhookCreateResponse.ts @@ -0,0 +1,6 @@ +import { User, Webhook } from "../../entities"; + +export interface WebhookCreateResponse { + user: User; + hook: Webhook; +} diff --git a/src/util/schemas/responses/index.ts b/src/util/schemas/responses/index.ts new file mode 100644 index 00000000..d8b7fd57 --- /dev/null +++ b/src/util/schemas/responses/index.ts @@ -0,0 +1,34 @@ +export * from "./APIErrorOrCaptchaResponse"; +export * from "./APIErrorResponse"; +export * from "./BackupCodesChallengeResponse"; +export * from "./CaptchaRequiredResponse"; +export * from "./DiscoverableGuildsResponse"; +export * from "./GatewayBotResponse"; +export * from "./GatewayResponse"; +export * from "./GenerateRegistrationTokensResponse"; +export * from "./GuildBansResponse"; +export * from "./GuildCreateResponse"; +export * from "./GuildDiscoveryRequirements"; +export * from "./GuildMessagesSearchResponse"; +export * from "./GuildPruneResponse"; +export * from "./GuildRecommendationsResponse"; +export * from "./GuildVanityUrl"; +export * from "./GuildVoiceRegionsResponse"; +export * from "./GuildWidgetJsonResponse"; +export * from "./GuildWidgetSettingsResponse"; +export * from "./InstanceDomainsResponse"; +export * from "./InstancePingResponse"; +export * from "./InstanceStatsResponse"; +export * from "./LocationMetadataResponse"; +export * from "./MemberJoinGuildResponse"; +export * from "./OAuthAuthorizeResponse"; +export * from "./Tenor"; +export * from "./TokenResponse"; +export * from "./TypedResponses"; +export * from "./UpdatesResponse"; +export * from "./UserNoteResponse"; +export * from "./UserProfileResponse"; +export * from "./UserRelationshipsResponse"; +export * from "./UserRelationsResponse"; +export * from "./WebAuthnCreateResponse"; +export * from "./WebhookCreateResponse"; diff --git a/src/util/util/Application.ts b/src/util/util/Application.ts new file mode 100644 index 00000000..23019a7f --- /dev/null +++ b/src/util/util/Application.ts @@ -0,0 +1,24 @@ +import { Request } from "express"; +import { Application, User } from "../entities"; + +export async function createAppBotUser(app: Application, req: Request) { + const user = await User.register({ + username: app.name, + password: undefined, + id: app.id, + req, + }); + + user.id = app.id; + user.premium_since = new Date(); + user.bot = true; + + await user.save(); + + // flags is NaN here? + app.assign({ bot: user, flags: app.flags || 0 }); + + await app.save(); + + return user; +} diff --git a/src/util/util/Gifs.ts b/src/util/util/Gifs.ts new file mode 100644 index 00000000..a5a5e64c --- /dev/null +++ b/src/util/util/Gifs.ts @@ -0,0 +1,25 @@ +import { HTTPError } from "lambert-server"; +import { Config } from "./Config"; +import { TenorGif } from ".."; + +export function parseGifResult(result: TenorGif) { + return { + id: result.id, + title: result.title, + url: result.itemurl, + src: result.media[0].mp4.url, + gif_src: result.media[0].gif.url, + width: result.media[0].mp4.dims[0], + height: result.media[0].mp4.dims[1], + preview: result.media[0].mp4.preview, + }; +} + +export function getGifApiKey() { + const { enabled, provider, apiKey } = Config.get().gif; + if (!enabled) throw new HTTPError(`Gifs are disabled`); + if (provider !== "tenor" || !apiKey) + throw new HTTPError(`${provider} gif provider not supported`); + + return apiKey; +} diff --git a/src/util/util/index.ts b/src/util/util/index.ts index 838239b7..10e09b5c 100644 --- a/src/util/util/index.ts +++ b/src/util/util/index.ts @@ -41,3 +41,5 @@ export * from "./String"; export * from "./Token"; export * from "./TraverseDirectory"; export * from "./WebAuthn"; +export * from "./Gifs"; +export * from "./Application"; |