summary refs log tree commit diff
path: root/src/api
diff options
context:
space:
mode:
authorTomatoCake <60300461+DEVTomatoCake@users.noreply.github.com>2024-07-18 16:08:06 +0200
committerGitHub <noreply@github.com>2024-07-18 16:08:06 +0200
commitd79669f7712c467136e22761a4779a9ebd679b5e (patch)
treec42a8a211c5b88a5d0cb82510aade40b52f697e3 /src/api
parentFix build by using ts-ignore (diff)
parentMake channel ID optional when replying (diff)
downloadserver-ts-d79669f7712c467136e22761a4779a9ebd679b5e.tar.xz
Merge branch 'master' into feat/local-image-proxy
Diffstat (limited to 'src/api')
-rw-r--r--src/api/Server.ts14
-rw-r--r--src/api/routes/auth/verify/index.ts2
-rw-r--r--src/api/routes/channels/#channel_id/index.ts6
-rw-r--r--src/api/routes/channels/#channel_id/messages/#message_id/crosspost.ts7
-rw-r--r--src/api/routes/channels/#channel_id/messages/#message_id/index.ts9
-rw-r--r--src/api/routes/channels/#channel_id/messages/index.ts20
-rw-r--r--src/api/routes/channels/#channel_id/permissions.ts11
-rw-r--r--src/api/routes/connections/index.ts45
-rw-r--r--src/api/routes/guilds/#guild_id/channels.ts20
-rw-r--r--src/api/routes/guilds/#guild_id/emojis.ts12
-rw-r--r--src/api/routes/guilds/#guild_id/messages/search.ts7
-rw-r--r--src/api/routes/users/#id/profile.ts5
-rw-r--r--src/api/util/handlers/Message.ts56
13 files changed, 160 insertions, 54 deletions
diff --git a/src/api/Server.ts b/src/api/Server.ts

index 0f5df490c..bea75d7e2 100644 --- a/src/api/Server.ts +++ b/src/api/Server.ts
@@ -18,15 +18,15 @@ import { Config, + ConnectionConfig, + ConnectionLoader, Email, - initDatabase, - initEvent, JSONReplacer, - registerRoutes, Sentry, WebAuthn, - ConnectionConfig, - ConnectionLoader, + initDatabase, + initEvent, + registerRoutes, } from "@spacebar/util"; import { Request, Response, Router } from "express"; import { Server, ServerOptions } from "lambert-server"; @@ -143,6 +143,10 @@ export class SpacebarServer extends Server { res.sendFile(path.join(PUBLIC_ASSETS_FOLDER, "index.html")), ); + app.get("/verify", (req, res) => + res.sendFile(path.join(PUBLIC_ASSETS_FOLDER, "verify.html")), + ); + this.app.use(ErrorHandler); Sentry.errorHandler(this.app); diff --git a/src/api/routes/auth/verify/index.ts b/src/api/routes/auth/verify/index.ts
index 49f742778..32c3f3058 100644 --- a/src/api/routes/auth/verify/index.ts +++ b/src/api/routes/auth/verify/index.ts
@@ -85,7 +85,7 @@ router.post( user = userTokenData.user; } catch { throw FieldErrors({ - password: { + token: { message: req.t("auth:password_reset.INVALID_TOKEN"), code: "INVALID_TOKEN", }, diff --git a/src/api/routes/channels/#channel_id/index.ts b/src/api/routes/channels/#channel_id/index.ts
index 99f9a6471..291b64727 100644 --- a/src/api/routes/channels/#channel_id/index.ts +++ b/src/api/routes/channels/#channel_id/index.ts
@@ -50,7 +50,13 @@ router.get( const channel = await Channel.findOneOrFail({ where: { id: channel_id }, }); + if (!channel.guild_id) return res.send(channel); + channel.position = await Channel.calculatePosition( + channel_id, + channel.guild_id, + channel.guild, + ); return res.send(channel); }, ); diff --git a/src/api/routes/channels/#channel_id/messages/#message_id/crosspost.ts b/src/api/routes/channels/#channel_id/messages/#message_id/crosspost.ts
index 5ca645c00..6362941c6 100644 --- a/src/api/routes/channels/#channel_id/messages/#message_id/crosspost.ts +++ b/src/api/routes/channels/#channel_id/messages/#message_id/crosspost.ts
@@ -1,17 +1,17 @@ /* 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/>. */ @@ -56,6 +56,7 @@ router.post( edited_timestamp: null, flags: 1, components: [], + poll: {}, }).status(200); }, ); diff --git a/src/api/routes/channels/#channel_id/messages/#message_id/index.ts b/src/api/routes/channels/#channel_id/messages/#message_id/index.ts
index c4d2e1e82..211cf9972 100644 --- a/src/api/routes/channels/#channel_id/messages/#message_id/index.ts +++ b/src/api/routes/channels/#channel_id/messages/#message_id/index.ts
@@ -1,17 +1,17 @@ /* 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/>. */ @@ -91,11 +91,10 @@ router.patch( } } else rights.hasThrow("SELF_EDIT_MESSAGES"); + // @ts-expect-error Something is wrong with message_reference here, TS complains since "channel_id" is optional in MessageCreateSchema const new_message = await handleMessage({ ...message, // TODO: should message_reference be overridable? - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore message_reference: message.message_reference, ...body, author_id: message.author_id, diff --git a/src/api/routes/channels/#channel_id/messages/index.ts b/src/api/routes/channels/#channel_id/messages/index.ts
index a5bfcfd73..645c6db23 100644 --- a/src/api/routes/channels/#channel_id/messages/index.ts +++ b/src/api/routes/channels/#channel_id/messages/index.ts
@@ -1,17 +1,17 @@ /* 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/>. */ @@ -183,9 +183,17 @@ router.get( const uri = y.proxy_url.startsWith("http") ? y.proxy_url : `https://example.org${y.proxy_url}`; - y.proxy_url = `${endpoint == null ? "" : endpoint}${ - new URL(uri).pathname - }`; + + let pathname = new URL(uri).pathname; + while ( + pathname.split("/")[0] != "attachments" && + pathname.length > 30 + ) { + pathname = pathname.split("/").slice(1).join("/"); + } + if (!endpoint?.endsWith("/")) pathname = "/" + pathname; + + y.proxy_url = `${endpoint == null ? "" : endpoint}${pathname}`; }); /** diff --git a/src/api/routes/channels/#channel_id/permissions.ts b/src/api/routes/channels/#channel_id/permissions.ts
index d3edb0fa1..fe289f234 100644 --- a/src/api/routes/channels/#channel_id/permissions.ts +++ b/src/api/routes/channels/#channel_id/permissions.ts
@@ -1,17 +1,17 @@ /* 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/>. */ @@ -53,6 +53,11 @@ router.put( where: { id: channel_id }, }); if (!channel.guild_id) throw new HTTPError("Channel not found", 404); + channel.position = await Channel.calculatePosition( + channel_id, + channel.guild_id, + channel.guild, + ); if (body.type === 0) { if (!(await Role.count({ where: { id: overwrite_id } }))) diff --git a/src/api/routes/connections/index.ts b/src/api/routes/connections/index.ts new file mode 100644
index 000000000..37c20a379 --- /dev/null +++ b/src/api/routes/connections/index.ts
@@ -0,0 +1,45 @@ +/* + 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 { route } from "@spacebar/api"; +import { ConnectionConfig } from "@spacebar/util"; +import { Request, Response, Router } from "express"; +const router = Router(); + +router.get( + "/", + route({ + responses: { + 200: { + body: "APIConnectionsConfiguration", + }, + }, + }), + async (req: Request, res: Response) => { + const config = ConnectionConfig.get(); + + Object.keys(config).forEach((key) => { + delete config[key].clientId; + delete config[key].clientSecret; + }); + + res.json(config); + }, +); + +export default router; diff --git a/src/api/routes/guilds/#guild_id/channels.ts b/src/api/routes/guilds/#guild_id/channels.ts
index 68208fee2..3488b64dd 100644 --- a/src/api/routes/guilds/#guild_id/channels.ts +++ b/src/api/routes/guilds/#guild_id/channels.ts
@@ -1,17 +1,17 @@ /* 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/>. */ @@ -41,6 +41,15 @@ router.get( const { guild_id } = req.params; const channels = await Channel.find({ where: { guild_id } }); + for await (const channel of channels) { + channel.position = await Channel.calculatePosition( + channel.id, + guild_id, + channel.guild, + ); + } + channels.sort((a, b) => a.position - b.position); + res.json(channels); }, ); @@ -71,6 +80,11 @@ router.post( { ...body, guild_id }, req.user_id, ); + channel.position = await Channel.calculatePosition( + channel.id, + guild_id, + channel.guild, + ); res.status(201).json(channel); }, diff --git a/src/api/routes/guilds/#guild_id/emojis.ts b/src/api/routes/guilds/#guild_id/emojis.ts
index ef28f989a..f3f0fd8bf 100644 --- a/src/api/routes/guilds/#guild_id/emojis.ts +++ b/src/api/routes/guilds/#guild_id/emojis.ts
@@ -1,17 +1,17 @@ /* 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/>. */ @@ -125,6 +125,7 @@ router.post( const user = await User.findOneOrFail({ where: { id: req.user_id } }); body.image = (await handleFile(`/emojis/${id}`, body.image)) as string; + const mimeType = body.image.split(":")[1].split(";")[0]; const emoji = await Emoji.create({ id: id, guild_id: guild_id, @@ -132,7 +133,10 @@ router.post( require_colons: body.require_colons ?? undefined, // schema allows nulls, db does not user: user, managed: false, - animated: false, // TODO: Add support animated emojis + animated: + mimeType == "image/gif" || + mimeType == "image/apng" || + mimeType == "video/webm", available: true, roles: [], }).save(); diff --git a/src/api/routes/guilds/#guild_id/messages/search.ts b/src/api/routes/guilds/#guild_id/messages/search.ts
index 637d1e438..94adf9c6a 100644 --- a/src/api/routes/guilds/#guild_id/messages/search.ts +++ b/src/api/routes/guilds/#guild_id/messages/search.ts
@@ -1,17 +1,17 @@ /* 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/>. */ @@ -162,6 +162,7 @@ router.get( edited_timestamp: x.edited_timestamp, flags: x.flags, components: x.components, + poll: x.poll, hit: true, }, ]); diff --git a/src/api/routes/users/#id/profile.ts b/src/api/routes/users/#id/profile.ts
index eecec0f35..db0922d68 100644 --- a/src/api/routes/users/#id/profile.ts +++ b/src/api/routes/users/#id/profile.ts
@@ -18,6 +18,7 @@ import { route } from "@spacebar/api"; import { + Badge, Member, PrivateUserProjection, User, @@ -98,6 +99,9 @@ router.get( bio: guild_member?.bio || "", guild_id, }; + + const badges = await Badge.find(); + res.json({ connected_accounts: user.connected_accounts.filter( (x) => x.visibility != 0, @@ -111,6 +115,7 @@ router.get( user_profile: userProfile, guild_member: guild_member?.toPublicMember(), guild_member_profile: guild_id && guildMemberProfile, + badges: badges.filter((x) => user.badge_ids?.includes(x.id)), }); }, ); diff --git a/src/api/util/handlers/Message.ts b/src/api/util/handlers/Message.ts
index 6172a3d0c..c36586682 100644 --- a/src/api/util/handlers/Message.ts +++ b/src/api/util/handlers/Message.ts
@@ -1,57 +1,57 @@ /* 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 * as Sentry from "@sentry/node"; +import { EmbedHandlers } from "@spacebar/api"; import { + Application, + Attachment, Channel, + Config, Embed, + EmbedCache, emitEvent, + EVERYONE_MENTION, + getPermission, + getRights, Guild, + HERE_MENTION, Message, MessageCreateEvent, + MessageCreateSchema, + MessageType, MessageUpdateEvent, - getPermission, - getRights, - //CHANNEL_MENTION, - USER_MENTION, - ROLE_MENTION, Role, - EVERYONE_MENTION, - HERE_MENTION, - MessageType, + ROLE_MENTION, + Sticker, User, - Application, + //CHANNEL_MENTION, + USER_MENTION, Webhook, - Attachment, - Config, - Sticker, - MessageCreateSchema, - EmbedCache, } from "@spacebar/util"; import { HTTPError } from "lambert-server"; import { In } from "typeorm"; -import { EmbedHandlers } from "@spacebar/api"; -import * as Sentry from "@sentry/node"; const allow_empty = false; // TODO: check webhook, application, system author, stickers // TODO: embed gifs/videos/images const LINK_REGEX = - /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/g; + /<?https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)>?/g; export async function handleMessage(opts: MessageOptions): Promise<Message> { const channel = await Channel.findOneOrFail({ @@ -66,6 +66,7 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> { : undefined; const message = Message.create({ ...opts, + poll: opts.poll, sticker_items: stickers, guild_id: channel.guild_id, channel_id: opts.channel_id, @@ -116,6 +117,12 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> { const guild = await Guild.findOneOrFail({ where: { id: channel.guild_id }, }); + + if (!opts.message_reference.guild_id) + opts.message_reference.guild_id = channel.guild_id; + if (!opts.message_reference.channel_id) + opts.message_reference.channel_id = opts.channel_id; + if (!guild.features.includes("CROSS_CHANNEL_REPLIES")) { if (opts.message_reference.guild_id !== channel.guild_id) throw new HTTPError( @@ -126,6 +133,8 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> { "You can only reference messages from this channel", ); } + + message.message_reference = opts.message_reference; } /** Q: should be checked if the referenced message exists? ANSWER: NO otherwise backfilling won't work **/ @@ -138,7 +147,9 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> { !opts.content && !opts.embeds?.length && !opts.attachments?.length && - !opts.sticker_ids?.length + !opts.sticker_ids?.length && + !opts.poll && + !opts.components?.length ) { throw new HTTPError("Empty messages are not allowed", 50006); } @@ -213,6 +224,9 @@ export async function postHandleMessage(message: Message) { const cachePromises = []; for (const link of links) { + // Don't embed links in <> + if (link.startsWith("<") && link.endsWith(">")) continue; + const url = new URL(link); const cached = await EmbedCache.findOne({ where: { url: link } });