mirror of
https://github.com/spacebarchat/server.git
synced 2026-03-30 22:35:40 +00:00
Prettier 1
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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" });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -23,8 +23,8 @@ import { ApplicationDetectableResponse } from "@spacebar/schemas";
|
||||
const router: Router = Router({ mergeParams: true });
|
||||
const cache = {
|
||||
data: {},
|
||||
expires: 0
|
||||
}
|
||||
expires: 0,
|
||||
};
|
||||
|
||||
router.get(
|
||||
"/",
|
||||
|
||||
@@ -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 });
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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"));
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
@@ -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 },
|
||||
|
||||
@@ -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 });
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user