Add first half of cloud attachment uploads

This commit is contained in:
Rory&
2025-09-23 21:05:35 +02:00
parent 3720068b83
commit 1e6ed06da1
13 changed files with 381 additions and 116 deletions
@@ -16,7 +16,7 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { random, route } from "@spacebar/api";
import { randomString, route } from "@spacebar/api";
import { Config, ValidRegistrationToken } from "@spacebar/util";
import { Request, Response, Router } from "express";
@@ -51,7 +51,7 @@ router.get(
for (let i = 0; i < count; i++) {
const token = ValidRegistrationToken.create({
token: random(length),
token: randomString(length),
expires_at: new Date(
Date.now() +
Config.get().security
@@ -0,0 +1,100 @@
/*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2025 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 { generateCode, randomString, route } from "@spacebar/api";
import {
Attachment,
Channel,
Config,
emitEvent,
GreetRequestSchema,
Message,
MessageCreateEvent,
MessageType,
Permissions,
Sticker,
UploadAttachmentRequestSchema,
UploadAttachmentResponseSchema,
User,
} from "@spacebar/util";
import { Request, Response, Router } from "express";
import { In } from "typeorm";
import { CloudAttachment } from "../../../../util/entities/CloudAttachment";
const router: Router = Router();
router.post(
"/",
route({
requestBody: "UploadAttachmentRequestSchema",
responses: {
200: {
body: "UploadAttachmentResponseSchema",
},
404: {},
400: {
body: "APIErrorResponse",
},
},
}),
async (req: Request, res: Response) => {
const payload = req.body as UploadAttachmentRequestSchema;
const { channel_id } = req.params;
const user = await User.findOneOrFail({ where: { id: req.user_id } });
const channel = await Channel.findOneOrFail({ where: { id: channel_id } });
if (!(await channel.getUserPermissions({ user_id: req.user_id })).has(Permissions.FLAGS.ATTACH_FILES)) {
return res.status(403).json({
code: 403,
message: "Missing Permissions: ATTACH_FILES",
});
}
const cdnUrl = Config.get().cdn.endpointPublic;
const batchId = `CLOUD_${user.id}_${randomString(128)}`;
const attachments = await Promise.all(
payload.files.map(async (attachment) => {
attachment.filename = attachment.filename.replaceAll(" ", "_").replace(/[^a-zA-Z0-9._]+/g, "");
const uploadFilename = `${batchId}/${attachment.id}/${attachment.filename}`;
const newAttachment = CloudAttachment.create({
user: user,
channel: channel,
uploadFilename: uploadFilename,
userAttachmentId: attachment.id,
userFilename: attachment.filename,
userFileSize: attachment.file_size,
userIsClip: attachment.is_clip,
userOriginalContentType: attachment.original_content_type,
});
await newAttachment.save();
return newAttachment;
}),
);
res.send({attachments: attachments.map(a => {
return {
id: a.userAttachmentId,
upload_filename: a.uploadFilename,
upload_url: `${cdnUrl}/attachments/${a.uploadFilename}`,
}
})} as UploadAttachmentResponseSchema);
},
);
export default router;
@@ -16,7 +16,7 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { random, route } from "@spacebar/api";
import { randomString, route } from "@spacebar/api";
import {
Channel,
Guild,
@@ -70,7 +70,7 @@ router.post(
: new Date(body.max_age * 1000 + Date.now());
const invite = await Invite.create({
code: random(),
code: randomString(),
temporary: body.temporary || true,
uses: 0,
max_uses: body.max_uses ? Math.max(0, body.max_uses) : 0,
@@ -16,7 +16,7 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { random, route } from "@spacebar/api";
import { randomString, route } from "@spacebar/api";
import {
Channel,
DiscordApiErrors,
@@ -77,7 +77,7 @@ router.get(
const expires_at = new Date(max_age * 1000 + Date.now());
invite = await Invite.create({
code: random(),
code: randomString(),
temporary: false,
uses: 0,
max_uses: 0,
+1 -1
View File
@@ -22,7 +22,7 @@ import crypto from "crypto";
// TODO: 'random'? seriously? who named this?
// And why is this even here? Just use cryto.randomBytes?
export function random(length = 6) {
export function randomString(length = 6) {
// Declare all characters
const chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";