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 } });
|