Prettier 1

This commit is contained in:
Rory&
2025-12-17 07:32:21 +01:00
parent 41b700e12a
commit 23ad44a440
22 changed files with 102 additions and 322 deletions

View File

@@ -37,8 +37,7 @@ export function BodyParser(opts?: OptionsJson) {
const jsonParser = bodyParser.json(opts);
return (req: Request, res: Response, next: NextFunction) => {
if (!req.headers["content-type"])
req.headers["content-type"] = "application/json";
if (!req.headers["content-type"]) req.headers["content-type"] = "application/json";
jsonParser(req, res, (err) => {
if (err) {

View File

@@ -21,12 +21,7 @@ import { HTTPError } from "lambert-server";
import { ApiError, FieldError } from "@spacebar/util";
const EntityNotFoundErrorRegex = /"(\w+)"/;
export function ErrorHandler(
error: Error & { type?: string },
req: Request,
res: Response,
next: NextFunction,
) {
export function ErrorHandler(error: Error & { type?: string }, req: Request, res: Response, next: NextFunction) {
if (!error) return next();
try {
@@ -36,16 +31,13 @@ export function ErrorHandler(
let errors = undefined;
let _ajvErrors = undefined;
if (error instanceof HTTPError && error.code)
code = httpcode = error.code;
if (error instanceof HTTPError && error.code) code = httpcode = error.code;
else if (error instanceof ApiError) {
code = error.code;
message = error.message;
httpcode = error.httpStatus;
} else if (error.name === "EntityNotFoundError") {
message = `${
error.message.match(EntityNotFoundErrorRegex)?.[1] || "Item"
} could not be found`;
message = `${error.message.match(EntityNotFoundErrorRegex)?.[1] || "Item"} could not be found`;
code = httpcode = 404;
} else if (error instanceof FieldError) {
code = Number(error.code);
@@ -58,12 +50,7 @@ export function ErrorHandler(
code = 50109;
message = "The request body contains invalid JSON.";
} else {
console.error(
`[Error] ${code} ${req.url}\n`,
errors || error,
"\nbody:",
req.body,
);
console.error(`[Error] ${code} ${req.url}\n`, errors || error, "\nbody:", req.body);
if (req.server?.options?.production) {
// don't expose internal errors to the user, instead human errors should be thrown as HTTPError
@@ -77,8 +64,6 @@ export function ErrorHandler(
res.status(httpcode).json({ code: code, message, errors, _ajvErrors });
} catch (error) {
console.error(`[Internal Server Error] 500`, error);
return res
.status(500)
.json({ code: 500, message: "Internal Server Error" });
return res.status(500).json({ code: 500, message: "Internal Server Error" });
}
}

View File

@@ -32,23 +32,8 @@ try {
let sentImageProxyWarning = false;
const sharpSupported = new Set([
"image/jpeg",
"image/png",
"image/bmp",
"image/tiff",
"image/gif",
"image/webp",
"image/avif",
"image/svg+xml",
]);
const jimpSupported = new Set([
"image/jpeg",
"image/png",
"image/bmp",
"image/tiff",
"image/gif",
]);
const sharpSupported = new Set(["image/jpeg", "image/png", "image/bmp", "image/tiff", "image/gif", "image/webp", "image/avif", "image/svg+xml"]);
const jimpSupported = new Set(["image/jpeg", "image/png", "image/bmp", "image/tiff", "image/gif"]);
const resizeSupported = new Set([...sharpSupported, ...jimpSupported]);
export async function ImageProxy(req: Request, res: Response) {
@@ -63,15 +48,9 @@ export async function ImageProxy(req: Request, res: Response) {
.replace(/\//g, "_");
try {
if (!crypto.timingSafeEqual(Buffer.from(hash), Buffer.from(path[0])))
throw new Error("Invalid signature");
if (!crypto.timingSafeEqual(Buffer.from(hash), Buffer.from(path[0]))) throw new Error("Invalid signature");
} catch {
console.log(
"[ImageProxy] Invalid signature, expected " +
hash +
" but got " +
path[0],
);
console.log("[ImageProxy] Invalid signature, expected " + hash + " but got " + path[0]);
res.status(403).send("Invalid signature");
return;
}
@@ -91,30 +70,18 @@ export async function ImageProxy(req: Request, res: Response) {
if (!request) return;
if (request.status !== 200) {
res.status(request.status).send(
"Origin failed to respond: " +
request.status +
" " +
request.statusText,
);
res.status(request.status).send("Origin failed to respond: " + request.status + " " + request.statusText);
return;
}
if (
!request.headers.get("Content-Type") ||
!request.headers.get("Content-Length")
) {
res.status(500).send(
"Origin did not provide a Content-Type or Content-Length header",
);
if (!request.headers.get("Content-Type") || !request.headers.get("Content-Length")) {
res.status(500).send("Origin did not provide a Content-Type or Content-Length header");
return;
}
// @ts-expect-error TS doesn't believe that the header cannot be null (it's checked for falsiness above)
if (parseInt(request.headers.get("Content-Length")) > 1024 * 1024 * 10) {
res.status(500).send(
"Origin provided a Content-Length header that is too large",
);
res.status(500).send("Origin provided a Content-Length header that is too large");
return;
}
@@ -124,11 +91,7 @@ export async function ImageProxy(req: Request, res: Response) {
const arrayBuffer = await request.arrayBuffer();
let resultBuffer = Buffer.from(arrayBuffer);
if (
!sentImageProxyWarning &&
resizeSupported.has(contentType) &&
/^\d+x\d+$/.test(path[1])
) {
if (!sentImageProxyWarning && resizeSupported.has(contentType) && /^\d+x\d+$/.test(path[1])) {
if (sharp !== false) {
try {
sharp = await import("sharp");
@@ -144,11 +107,7 @@ export async function ImageProxy(req: Request, res: Response) {
Jimp = await import("jimp");
} catch {
sentImageProxyWarning = true;
console.log(
`[ImageProxy] ${yellow(
'Neither "sharp" or "jimp" NPM packages are installed, image resizing will be disabled',
)}`,
);
console.log(`[ImageProxy] ${yellow('Neither "sharp" or "jimp" NPM packages are installed, image resizing will be disabled')}`);
}
}
@@ -177,10 +136,7 @@ export async function ImageProxy(req: Request, res: Response) {
}
res.header("Content-Type", contentType);
res.setHeader(
"Cache-Control",
"public, max-age=" + Config.get().cdn.proxyCacheHeaderSeconds,
);
res.setHeader("Cache-Control", "public, max-age=" + Config.get().cdn.proxyCacheHeaderSeconds);
res.send(resultBuffer);
}

View File

@@ -27,12 +27,8 @@ const ASSET_FOLDER_PATH = path.join(__dirname, "..", "..", "..", "assets");
export async function initTranslation(router: Router) {
const languages = fs.readdirSync(path.join(ASSET_FOLDER_PATH, "locales"));
const namespaces = fs.readdirSync(
path.join(ASSET_FOLDER_PATH, "locales", "en"),
);
const ns = namespaces
.filter((x) => x.endsWith(".json"))
.map((x) => x.slice(0, x.length - 5));
const namespaces = fs.readdirSync(path.join(ASSET_FOLDER_PATH, "locales", "en"));
const ns = namespaces.filter((x) => x.endsWith(".json")).map((x) => x.slice(0, x.length - 5));
await i18next
.use(i18nextBackend)
@@ -43,9 +39,7 @@ export async function initTranslation(router: Router) {
fallbackLng: "en",
ns,
backend: {
loadPath:
path.join(ASSET_FOLDER_PATH, "locales") +
"/{{lng}}/{{ns}}.json",
loadPath: path.join(ASSET_FOLDER_PATH, "locales") + "/{{lng}}/{{ns}}.json",
},
load: "all",
});

View File

@@ -17,18 +17,11 @@
*/
import { route } from "@spacebar/api";
import {
Application,
DiscordApiErrors,
User,
createAppBotUser,
generateToken,
handleFile,
} from "@spacebar/util";
import { Application, DiscordApiErrors, User, createAppBotUser, generateToken, handleFile } from "@spacebar/util";
import { Request, Response, Router } from "express";
import { HTTPError } from "lambert-server";
import { verifyToken } from "node-2fa";
import { BotModifySchema } from "@spacebar/schemas"
import { BotModifySchema } from "@spacebar/schemas";
const router: Router = Router({ mergeParams: true });
@@ -50,8 +43,7 @@ router.post(
relations: ["owner"],
});
if (app.owner.id != req.user_id)
throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION;
if (app.owner.id != req.user_id) throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION;
const user = await createAppBotUser(app, req);
@@ -77,8 +69,7 @@ router.post(
const bot = await User.findOneOrFail({ where: { id: req.params.application_id } });
const owner = await User.findOneOrFail({ where: { id: req.user_id } });
if (owner.id != req.user_id)
throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION;
if (owner.id != req.user_id) throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION;
if (
owner.totp_secret &&
@@ -120,14 +111,9 @@ router.patch(
if (!app.bot) throw DiscordApiErrors.BOT_ONLY_ENDPOINT;
if (app.owner.id != req.user_id)
throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION;
if (app.owner.id != req.user_id) throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION;
if (body.avatar)
body.avatar = await handleFile(
`/avatars/${app.id}`,
body.avatar as string,
);
if (body.avatar) body.avatar = await handleFile(`/avatars/${app.id}`, body.avatar as string);
app.bot.assign(body);

View File

@@ -17,16 +17,11 @@
*/
import { route } from "@spacebar/api";
import {
Application,
DiscordApiErrors,
Guild,
handleFile,
} from "@spacebar/util";
import { Application, DiscordApiErrors, Guild, handleFile } from "@spacebar/util";
import { Request, Response, Router } from "express";
import { HTTPError } from "lambert-server";
import { verifyToken } from "node-2fa";
import { ApplicationModifySchema } from "@spacebar/schemas"
import { ApplicationModifySchema } from "@spacebar/schemas";
const router: Router = Router({ mergeParams: true });
@@ -75,16 +70,10 @@ router.patch(
});
if (body.icon) {
body.icon = await handleFile(
`/app-icons/${app.id}`,
body.icon as string,
);
body.icon = await handleFile(`/app-icons/${app.id}`, body.icon as string);
}
if (body.cover_image) {
body.cover_image = await handleFile(
`/app-icons/${app.id}`,
body.cover_image as string,
);
body.cover_image = await handleFile(`/app-icons/${app.id}`, body.cover_image as string);
}
if (body.guild_id) {
@@ -92,11 +81,7 @@ router.patch(
where: { id: body.guild_id },
select: ["owner_id"],
});
if (guild.owner_id != req.user_id)
throw new HTTPError(
"You must be the owner of the guild to link it to an application",
400,
);
if (guild.owner_id != req.user_id) throw new HTTPError("You must be the owner of the guild to link it to an application", 400);
}
if (app.bot) {

View File

@@ -23,8 +23,8 @@ import { ApplicationDetectableResponse } from "@spacebar/schemas";
const router: Router = Router({ mergeParams: true });
const cache = {
data: {},
expires: 0
}
expires: 0,
};
router.get(
"/",

View File

@@ -17,15 +17,9 @@
*/
import { route } from "@spacebar/api";
import {
Application,
Config,
User,
createAppBotUser,
trimSpecial,
} from "@spacebar/util";
import { Application, Config, User, createAppBotUser, trimSpecial } from "@spacebar/util";
import { Request, Response, Router } from "express";
import { ApplicationCreateSchema } from "@spacebar/schemas"
import { ApplicationCreateSchema } from "@spacebar/schemas";
const router: Router = Router({ mergeParams: true });

View File

@@ -17,12 +17,9 @@
*/
import { route } from "@spacebar/api";
import {
getUrlSignature,
NewUrlSignatureData,
} from "@spacebar/util";
import { getUrlSignature, NewUrlSignatureData } from "@spacebar/util";
import { Request, Response, Router } from "express";
import { RefreshUrlsRequestSchema } from "@spacebar/schemas"
import { RefreshUrlsRequestSchema } from "@spacebar/schemas";
const router = Router({ mergeParams: true });
router.post(

View File

@@ -29,13 +29,11 @@ router.get(
query: {
count: {
type: "number",
description:
"The number of registration tokens to generate. Defaults to 1.",
description: "The number of registration tokens to generate. Defaults to 1.",
},
length: {
type: "number",
description:
"The length of each registration token. Defaults to 255.",
description: "The length of each registration token. Defaults to 255.",
},
},
right: "CREATE_REGISTRATION_TOKENS",
@@ -43,20 +41,14 @@ router.get(
}),
async (req: Request, res: Response) => {
const count = req.query.count ? parseInt(req.query.count as string) : 1;
const length = req.query.length
? parseInt(req.query.length as string)
: 255;
const length = req.query.length ? parseInt(req.query.length as string) : 255;
const tokens: ValidRegistrationToken[] = [];
for (let i = 0; i < count; i++) {
const token = ValidRegistrationToken.create({
token: randomString(length),
expires_at: new Date(
Date.now() +
Config.get().security
.defaultRegistrationTokenExpiration,
),
expires_at: new Date(Date.now() + Config.get().security.defaultRegistrationTokenExpiration),
});
tokens.push(token);
}
@@ -68,14 +60,7 @@ router.get(
transaction: false,
});
const ret = req.query.include_url
? tokens.map(
(x) =>
`${Config.get().general.frontPage}/register?token=${
x.token
}`,
)
: tokens.map((x) => x.token);
const ret = req.query.include_url ? tokens.map((x) => `${Config.get().general.frontPage}/register?token=${x.token}`) : tokens.map((x) => x.token);
if (req.query.plain) return res.send(ret.join("\n"));

View File

@@ -21,7 +21,7 @@ import { BackupCode, User, generateToken } from "@spacebar/util";
import { Request, Response, Router } from "express";
import { HTTPError } from "lambert-server";
import { verifyToken } from "node-2fa";
import { TotpSchema } from "@spacebar/schemas"
import { TotpSchema } from "@spacebar/schemas";
const router = Router({ mergeParams: true });
router.post(
@@ -60,11 +60,7 @@ router.post(
if (!backup) {
const ret = verifyToken(user.totp_secret || "", code);
if (!ret || ret.delta != 0)
throw new HTTPError(
req.t("auth:login.INVALID_TOTP_CODE"),
60008,
);
if (!ret || ret.delta != 0) throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
} else {
backup.consumed = true;
await backup.save();

View File

@@ -17,17 +17,11 @@
*/
import { route } from "@spacebar/api";
import {
generateToken,
SecurityKey,
User,
verifyWebAuthnToken,
WebAuthn,
} from "@spacebar/util";
import { generateToken, SecurityKey, User, verifyWebAuthnToken, WebAuthn } from "@spacebar/util";
import { Request, Response, Router } from "express";
import { ExpectedAssertionResult } from "fido2-lib";
import { HTTPError } from "lambert-server";
import { WebAuthnTotpSchema } from "@spacebar/schemas"
import { WebAuthnTotpSchema } from "@spacebar/schemas";
const router = Router({ mergeParams: true });
function toArrayBuffer(buf: Buffer) {
@@ -65,46 +59,31 @@ router.post(
});
const ret = await verifyWebAuthnToken(ticket);
if (!ret)
throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
if (!ret) throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
await User.update({ id: user.id }, { totp_last_ticket: "" });
const clientAttestationResponse = JSON.parse(code);
if (!clientAttestationResponse.rawId)
throw new HTTPError("Missing rawId", 400);
if (!clientAttestationResponse.rawId) throw new HTTPError("Missing rawId", 400);
clientAttestationResponse.rawId = toArrayBuffer(
Buffer.from(clientAttestationResponse.rawId, "base64url"),
);
clientAttestationResponse.rawId = toArrayBuffer(Buffer.from(clientAttestationResponse.rawId, "base64url"));
const securityKey = await SecurityKey.findOneOrFail({
where: {
key_id: Buffer.from(
clientAttestationResponse.rawId,
"base64url",
).toString("base64"),
key_id: Buffer.from(clientAttestationResponse.rawId, "base64url").toString("base64"),
},
});
const assertionExpectations: ExpectedAssertionResult = JSON.parse(
Buffer.from(
clientAttestationResponse.response.clientDataJSON,
"base64",
).toString(),
);
const assertionExpectations: ExpectedAssertionResult = JSON.parse(Buffer.from(clientAttestationResponse.response.clientDataJSON, "base64").toString());
const authnResult = await WebAuthn.fido2.assertionResult(
clientAttestationResponse,
{
...assertionExpectations,
factor: "second",
publicKey: securityKey.public_key,
prevCounter: securityKey.counter,
userHandle: securityKey.key_id,
},
);
const authnResult = await WebAuthn.fido2.assertionResult(clientAttestationResponse, {
...assertionExpectations,
factor: "second",
publicKey: securityKey.public_key,
prevCounter: securityKey.counter,
userHandle: securityKey.key_id,
});
const counter = authnResult.authnrData.get("counter");

View File

@@ -17,16 +17,10 @@
*/
import { route } from "@spacebar/api";
import {
checkToken,
Email,
FieldErrors,
generateToken,
User,
} from "@spacebar/util";
import { checkToken, Email, FieldErrors, generateToken, User } from "@spacebar/util";
import bcrypt from "bcrypt";
import { Request, Response, Router } from "express";
import { PasswordResetSchema } from "@spacebar/schemas"
import { PasswordResetSchema } from "@spacebar/schemas";
const router = Router({ mergeParams: true });
@@ -52,7 +46,7 @@ router.post(
const userTokenData = await checkToken(token, {
select: ["email"],
fingerprint: req.fingerprint,
ipAddress: req.ip
ipAddress: req.ip,
});
user = userTokenData.user;
} catch {

View File

@@ -77,7 +77,7 @@ router.post(
try {
const userTokenData = await checkToken(token, {
fingerprint: req.fingerprint,
ipAddress: req.ip
ipAddress: req.ip,
});
user = userTokenData.user;
} catch {

View File

@@ -56,9 +56,7 @@ router.post(
return res.sendStatus(204);
})
.catch((e) => {
console.error(
`Failed to send verification email to ${user.username}#${user.discriminator}: ${e}`,
);
console.error(`Failed to send verification email to ${user.username}#${user.discriminator}: ${e}`);
throw new HTTPError("Failed to send verification email", 500);
});
},

View File

@@ -20,7 +20,7 @@ import { route } from "@spacebar/api";
import { FieldErrors, User } from "@spacebar/util";
import bcrypt from "bcrypt";
import { Request, Response, Router } from "express";
import { BackupCodesChallengeSchema } from "@spacebar/schemas"
import { BackupCodesChallengeSchema } from "@spacebar/schemas";
const router = Router({ mergeParams: true });
router.post(

View File

@@ -17,15 +17,10 @@
*/
import { randomString, route } from "@spacebar/api";
import {
Channel,
Config,
Permissions,
User,
} from "@spacebar/util";
import { Channel, Config, Permissions, User } from "@spacebar/util";
import { Request, Response, Router } from "express";
import { CloudAttachment } from "@spacebar/util";
import { UploadAttachmentRequestSchema, UploadAttachmentResponseSchema } from "@spacebar/schemas"
import { UploadAttachmentRequestSchema, UploadAttachmentResponseSchema } from "@spacebar/schemas";
const router: Router = Router({ mergeParams: true });
@@ -91,14 +86,16 @@ router.post(
}),
);
res.send({attachments: attachments.map(a => {
return {
id: a.userAttachmentId,
upload_filename: a.uploadFilename,
upload_url: `${cdnUrl}/attachments/${a.uploadFilename}`,
original_content_type: a.userOriginalContentType
}
})} as UploadAttachmentResponseSchema);
res.send({
attachments: attachments.map((a) => {
return {
id: a.userAttachmentId,
upload_filename: a.uploadFilename,
upload_url: `${cdnUrl}/attachments/${a.uploadFilename}`,
original_content_type: a.userOriginalContentType,
};
}),
} as UploadAttachmentResponseSchema);
},
);
@@ -122,18 +119,15 @@ router.delete("/:cloud_attachment_url", async (req: Request, res: Response) => {
});
}
const response = await fetch(
`${Config.get().cdn.endpointPrivate || "http://localhost:3001"}/attachments/${att.uploadFilename}`,
{
headers: {
signature: Config.get().security.requestSignature
},
method: "DELETE",
const response = await fetch(`${Config.get().cdn.endpointPrivate}/attachments/${att.uploadFilename}`, {
headers: {
signature: Config.get().security.requestSignature,
},
);
method: "DELETE",
});
await att.remove();
return res.status(response.status).send(response.body);
});
export default router;
export default router;

View File

@@ -17,16 +17,9 @@
*/
import { route } from "@spacebar/api";
import {
Channel,
ChannelDeleteEvent,
ChannelUpdateEvent,
Recipient,
emitEvent,
handleFile,
} from "@spacebar/util";
import { Channel, ChannelDeleteEvent, ChannelUpdateEvent, Recipient, emitEvent, handleFile } from "@spacebar/util";
import { Request, Response, Router } from "express";
import { ChannelModifySchema, ChannelType } from "@spacebar/schemas"
import { ChannelModifySchema, ChannelType } from "@spacebar/schemas";
const router: Router = Router({ mergeParams: true });
// TODO: delete channel
@@ -51,11 +44,7 @@ router.get(
});
if (!channel.guild_id) return res.send(channel);
channel.position = await Channel.calculatePosition(
channel_id,
channel.guild_id,
channel.guild,
);
channel.position = await Channel.calculatePosition(channel_id, channel.guild_id, channel.guild);
return res.send(channel);
},
);
@@ -145,11 +134,7 @@ router.patch(
async (req: Request, res: Response) => {
const payload = req.body as ChannelModifySchema;
const { channel_id } = req.params;
if (payload.icon)
payload.icon = await handleFile(
`/channel-icons/${channel_id}`,
payload.icon,
);
if (payload.icon) payload.icon = await handleFile(`/channel-icons/${channel_id}`, payload.icon);
const channel = await Channel.findOneOrFail({
where: { id: channel_id },

View File

@@ -20,7 +20,7 @@ import { randomString, route } from "@spacebar/api";
import { Channel, Guild, Invite, InviteCreateEvent, PublicInviteRelation, User, emitEvent } from "@spacebar/util";
import { Request, Response, Router } from "express";
import { HTTPError } from "lambert-server";
import { InviteCreateSchema, isTextChannel } from "@spacebar/schemas"
import { InviteCreateSchema, isTextChannel } from "@spacebar/schemas";
const router: Router = Router({ mergeParams: true });

View File

@@ -35,7 +35,7 @@ import { Request, Response, Router } from "express";
import { HTTPError } from "lambert-server";
import multer from "multer";
import { handleMessage, postHandleMessage, route } from "../../../../../util";
import { MessageCreateAttachment, MessageCreateCloudAttachment, MessageCreateSchema, MessageEditSchema } from "@spacebar/schemas"
import { MessageCreateAttachment, MessageCreateCloudAttachment, MessageCreateSchema, MessageEditSchema } from "@spacebar/schemas";
const router = Router({ mergeParams: true });
// TODO: message content/embed string length limit
@@ -75,11 +75,7 @@ router.patch(
relations: ["attachments"],
});
const permissions = await getPermission(
req.user_id,
undefined,
channel_id,
);
const permissions = await getPermission(req.user_id, undefined, channel_id);
const rights = await getRights(req.user_id);
@@ -196,13 +192,8 @@ router.put(
if (req.file) {
try {
const file = await uploadFile(
`/attachments/${req.params.channel_id}`,
req.file,
);
attachments.push(
Attachment.create({ ...file, proxy_url: file.url }),
);
const file = await uploadFile(`/attachments/${req.params.channel_id}`, req.file);
attachments.push(Attachment.create({ ...file, proxy_url: file.url }));
} catch (error) {
return res.status(400).json(error);
}
@@ -241,9 +232,7 @@ router.put(
]);
// no await as it shouldnt block the message send function and silently catch error
postHandleMessage(message).catch((e) =>
console.error("[Message] post-message handler failed", e),
);
postHandleMessage(message).catch((e) => console.error("[Message] post-message handler failed", e));
return res.json(
message.withSignedAttachments(
@@ -279,14 +268,9 @@ router.get(
relations: ["attachments"],
});
const permissions = await getPermission(
req.user_id,
undefined,
channel_id,
);
const permissions = await getPermission(req.user_id, undefined, channel_id);
if (message.author_id !== req.user_id)
permissions.hasThrow("READ_MESSAGE_HISTORY");
if (message.author_id !== req.user_id) permissions.hasThrow("READ_MESSAGE_HISTORY");
return res.json(message);
},
@@ -317,11 +301,7 @@ router.delete(
if (message.author_id !== req.user_id) {
if (!rights.has("MANAGE_MESSAGES")) {
const permission = await getPermission(
req.user_id,
channel.guild_id,
channel_id,
);
const permission = await getPermission(req.user_id, channel.guild_id, channel_id);
permission.hasThrow("MANAGE_MESSAGES");
}
} else rights.hasThrow("SELF_DELETE_MESSAGES");

View File

@@ -17,15 +17,7 @@
*/
import { route } from "@spacebar/api";
import {
Channel,
Config,
emitEvent,
getPermission,
getRights,
Message,
MessageDeleteBulkEvent,
} from "@spacebar/util";
import { Channel, Config, emitEvent, getPermission, getRights, Message, MessageDeleteBulkEvent } from "@spacebar/util";
import { Request, Response, Router } from "express";
import { HTTPError } from "lambert-server";
@@ -54,30 +46,21 @@ router.post(
const channel = await Channel.findOneOrFail({
where: { id: channel_id },
});
if (!channel.guild_id)
throw new HTTPError("Can't bulk delete dm channel messages", 400);
if (!channel.guild_id) throw new HTTPError("Can't bulk delete dm channel messages", 400);
const rights = await getRights(req.user_id);
rights.hasThrow("SELF_DELETE_MESSAGES");
const superuser = rights.has("MANAGE_MESSAGES");
const permission = await getPermission(
req.user_id,
channel?.guild_id,
channel_id,
);
const permission = await getPermission(req.user_id, channel?.guild_id, channel_id);
const { maxBulkDelete } = Config.get().limits.message;
const { messages } = req.body as { messages: string[] };
if (messages.length === 0)
throw new HTTPError("You must specify messages to bulk delete");
if (messages.length === 0) throw new HTTPError("You must specify messages to bulk delete");
if (!superuser) {
permission.hasThrow("MANAGE_MESSAGES");
if (messages.length > maxBulkDelete)
throw new HTTPError(
`You cannot delete more than ${maxBulkDelete} messages`,
);
if (messages.length > maxBulkDelete) throw new HTTPError(`You cannot delete more than ${maxBulkDelete} messages`);
}
await Message.delete(messages);

View File

@@ -17,16 +17,7 @@
*/
import { route } from "@spacebar/api";
import {
ChannelPinsUpdateEvent,
Config,
DiscordApiErrors,
emitEvent,
Message,
MessageCreateEvent,
MessageUpdateEvent,
User,
} from "@spacebar/util";
import { ChannelPinsUpdateEvent, Config, DiscordApiErrors, emitEvent, Message, MessageCreateEvent, MessageUpdateEvent, User } from "@spacebar/util";
import { Request, Response, Router } from "express";
import { IsNull, Not } from "typeorm";
@@ -61,8 +52,7 @@ router.put(
});
const { maxPins } = Config.get().limits.channel;
if (pinned_count >= maxPins)
throw DiscordApiErrors.MAXIMUM_PINS.withParams(maxPins);
if (pinned_count >= maxPins) throw DiscordApiErrors.MAXIMUM_PINS.withParams(maxPins);
message.pinned_at = new Date();