diff --git a/src/api/routes/users/@me/channels.ts b/src/api/routes/users/@me/channels.ts
index ad483529..237be102 100644
--- a/src/api/routes/users/@me/channels.ts
+++ b/src/api/routes/users/@me/channels.ts
@@ -1,5 +1,10 @@
import { Request, Response, Router } from "express";
-import { Recipient, DmChannelDTO, Channel, DmChannelCreateSchema } from "@fosscord/util";
+import {
+ Recipient,
+ DmChannelDTO,
+ Channel,
+ DmChannelCreateSchema,
+} from "@fosscord/util";
import { route } from "@fosscord/api";
const router: Router = Router();
@@ -7,14 +12,28 @@ const router: Router = Router();
router.get("/", route({}), async (req: Request, res: Response) => {
const recipients = await Recipient.find({
where: { user_id: req.user_id, closed: false },
- relations: ["channel", "channel.recipients"]
+ relations: ["channel", "channel.recipients"],
});
- res.json(await Promise.all(recipients.map((r) => DmChannelDTO.from(r.channel, [req.user_id]))));
+ res.json(
+ await Promise.all(
+ recipients.map((r) => DmChannelDTO.from(r.channel, [req.user_id])),
+ ),
+ );
});
-router.post("/", route({ body: "DmChannelCreateSchema" }), async (req: Request, res: Response) => {
- const body = req.body as DmChannelCreateSchema;
- res.json(await Channel.createDMChannel(body.recipients, req.user_id, body.name));
-});
+router.post(
+ "/",
+ route({ body: "DmChannelCreateSchema" }),
+ async (req: Request, res: Response) => {
+ const body = req.body as DmChannelCreateSchema;
+ res.json(
+ await Channel.createDMChannel(
+ body.recipients,
+ req.user_id,
+ body.name,
+ ),
+ );
+ },
+);
export default router;
diff --git a/src/api/routes/users/@me/delete.ts b/src/api/routes/users/@me/delete.ts
index c24c3f1e..a9f8167c 100644
--- a/src/api/routes/users/@me/delete.ts
+++ b/src/api/routes/users/@me/delete.ts
@@ -7,7 +7,10 @@ import { HTTPError } from "lambert-server";
const router = Router();
router.post("/", route({}), async (req: Request, res: Response) => {
- const user = await User.findOneOrFail({ where: { id: req.user_id }, select: ["data"] }); //User object
+ const user = await User.findOneOrFail({
+ where: { id: req.user_id },
+ select: ["data"],
+ }); //User object
let correctpass = true;
if (user.data.hash) {
@@ -21,7 +24,10 @@ router.post("/", route({}), async (req: Request, res: Response) => {
// TODO: decrement guild member count
if (correctpass) {
- await Promise.all([User.delete({ id: req.user_id }), Member.delete({ id: req.user_id })]);
+ await Promise.all([
+ User.delete({ id: req.user_id }),
+ Member.delete({ id: req.user_id }),
+ ]);
res.sendStatus(204);
} else {
diff --git a/src/api/routes/users/@me/disable.ts b/src/api/routes/users/@me/disable.ts
index 4aff3774..313a888f 100644
--- a/src/api/routes/users/@me/disable.ts
+++ b/src/api/routes/users/@me/disable.ts
@@ -6,7 +6,10 @@ import bcrypt from "bcrypt";
const router = Router();
router.post("/", route({}), async (req: Request, res: Response) => {
- const user = await User.findOneOrFail({ where: { id: req.user_id }, select: ["data"] }); //User object
+ const user = await User.findOneOrFail({
+ where: { id: req.user_id },
+ select: ["data"],
+ }); //User object
let correctpass = true;
if (user.data.hash) {
@@ -19,7 +22,10 @@ router.post("/", route({}), async (req: Request, res: Response) => {
res.sendStatus(204);
} else {
- res.status(400).json({ message: "Password does not match", code: 50018 });
+ res.status(400).json({
+ message: "Password does not match",
+ code: 50018,
+ });
}
});
diff --git a/src/api/routes/users/@me/email-settings.ts b/src/api/routes/users/@me/email-settings.ts
index 3114984e..a2834b89 100644
--- a/src/api/routes/users/@me/email-settings.ts
+++ b/src/api/routes/users/@me/email-settings.ts
@@ -11,9 +11,9 @@ router.get("/", route({}), (req: Request, res: Response) => {
communication: true,
tips: false,
updates_and_announcements: false,
- recommendations_and_events: false
+ recommendations_and_events: false,
},
- initialized: false
+ initialized: false,
}).status(200);
});
diff --git a/src/api/routes/users/@me/guilds.ts b/src/api/routes/users/@me/guilds.ts
index 754a240e..e12bf258 100644
--- a/src/api/routes/users/@me/guilds.ts
+++ b/src/api/routes/users/@me/guilds.ts
@@ -1,12 +1,23 @@
import { Router, Request, Response } from "express";
-import { Guild, Member, User, GuildDeleteEvent, GuildMemberRemoveEvent, emitEvent, Config } from "@fosscord/util";
+import {
+ Guild,
+ Member,
+ User,
+ GuildDeleteEvent,
+ GuildMemberRemoveEvent,
+ emitEvent,
+ Config,
+} from "@fosscord/util";
import { HTTPError } from "lambert-server";
import { route } from "@fosscord/api";
const router: Router = Router();
router.get("/", route({}), async (req: Request, res: Response) => {
- const members = await Member.find({ relations: ["guild"], where: { id: req.user_id } });
+ const members = await Member.find({
+ relations: ["guild"],
+ where: { id: req.user_id },
+ });
let guild = members.map((x) => x.guild);
@@ -21,11 +32,19 @@ router.get("/", route({}), async (req: Request, res: Response) => {
router.delete("/:guild_id", route({}), async (req: Request, res: Response) => {
const { autoJoin } = Config.get().guild;
const { guild_id } = req.params;
- const guild = await Guild.findOneOrFail({ where: { id: guild_id }, select: ["owner_id"] });
+ const guild = await Guild.findOneOrFail({
+ where: { id: guild_id },
+ select: ["owner_id"],
+ });
if (!guild) throw new HTTPError("Guild doesn't exist", 404);
- if (guild.owner_id === req.user_id) throw new HTTPError("You can't leave your own guild", 400);
- if (autoJoin.enabled && autoJoin.guilds.includes(guild_id) && !autoJoin.canLeave) {
+ if (guild.owner_id === req.user_id)
+ throw new HTTPError("You can't leave your own guild", 400);
+ if (
+ autoJoin.enabled &&
+ autoJoin.guilds.includes(guild_id) &&
+ !autoJoin.canLeave
+ ) {
throw new HTTPError("You can't leave instance auto join guilds", 400);
}
@@ -34,10 +53,10 @@ router.delete("/:guild_id", route({}), async (req: Request, res: Response) => {
emitEvent({
event: "GUILD_DELETE",
data: {
- id: guild_id
+ id: guild_id,
},
- user_id: req.user_id
- } as GuildDeleteEvent)
+ user_id: req.user_id,
+ } as GuildDeleteEvent),
]);
const user = await User.getPublicUser(req.user_id);
@@ -46,9 +65,9 @@ router.delete("/:guild_id", route({}), async (req: Request, res: Response) => {
event: "GUILD_MEMBER_REMOVE",
data: {
guild_id: guild_id,
- user: user
+ user: user,
},
- guild_id: guild_id
+ guild_id: guild_id,
} as GuildMemberRemoveEvent);
return res.sendStatus(204);
diff --git a/src/api/routes/users/@me/guilds/#guild_id/settings.ts b/src/api/routes/users/@me/guilds/#guild_id/settings.ts
index f09be25b..4b806cfb 100644
--- a/src/api/routes/users/@me/guilds/#guild_id/settings.ts
+++ b/src/api/routes/users/@me/guilds/#guild_id/settings.ts
@@ -1,39 +1,51 @@
import { Router, Response, Request } from "express";
-import { Channel, ChannelOverride, Member, UserGuildSettings } from "@fosscord/util";
+import {
+ Channel,
+ ChannelOverride,
+ Member,
+ UserGuildSettings,
+} from "@fosscord/util";
import { route } from "@fosscord/api";
const router = Router();
// This sucks. I would use a DeepPartial, my own or typeorms, but they both generate inncorect schema
-export interface UserGuildSettingsSchema extends Partial<Omit<UserGuildSettings, 'channel_overrides'>> {
+export interface UserGuildSettingsSchema
+ extends Partial<Omit<UserGuildSettings, "channel_overrides">> {
channel_overrides: {
[channel_id: string]: Partial<ChannelOverride>;
- },
+ };
}
// GET doesn't exist on discord.com
router.get("/", route({}), async (req: Request, res: Response) => {
const user = await Member.findOneOrFail({
where: { id: req.user_id, guild_id: req.params.guild_id },
- select: ["settings"]
+ select: ["settings"],
});
return res.json(user.settings);
});
-router.patch("/", route({ body: "UserGuildSettingsSchema" }), async (req: Request, res: Response) => {
- const body = req.body as UserGuildSettings;
+router.patch(
+ "/",
+ route({ body: "UserGuildSettingsSchema" }),
+ async (req: Request, res: Response) => {
+ const body = req.body as UserGuildSettings;
- if (body.channel_overrides) {
- for (var channel in body.channel_overrides) {
- Channel.findOneOrFail({ where: { id: channel } });
+ if (body.channel_overrides) {
+ for (var channel in body.channel_overrides) {
+ Channel.findOneOrFail({ where: { id: channel } });
+ }
}
- }
- const user = await Member.findOneOrFail({ where: { id: req.user_id, guild_id: req.params.guild_id } });
- user.settings = { ...user.settings, ...body };
- await user.save();
+ const user = await Member.findOneOrFail({
+ where: { id: req.user_id, guild_id: req.params.guild_id },
+ });
+ user.settings = { ...user.settings, ...body };
+ await user.save();
- res.json(user.settings);
-});
+ res.json(user.settings);
+ },
+);
export default router;
diff --git a/src/api/routes/users/@me/index.ts b/src/api/routes/users/@me/index.ts
index e849b72a..5eba4665 100644
--- a/src/api/routes/users/@me/index.ts
+++ b/src/api/routes/users/@me/index.ts
@@ -1,5 +1,15 @@
import { Router, Request, Response } from "express";
-import { User, PrivateUserProjection, emitEvent, UserUpdateEvent, handleFile, FieldErrors, adjustEmail, Config, UserModifySchema } from "@fosscord/util";
+import {
+ User,
+ PrivateUserProjection,
+ emitEvent,
+ UserUpdateEvent,
+ handleFile,
+ FieldErrors,
+ adjustEmail,
+ Config,
+ UserModifySchema,
+} from "@fosscord/util";
import { route } from "@fosscord/api";
import bcrypt from "bcrypt";
import { HTTPError } from "lambert-server";
@@ -7,79 +17,134 @@ import { HTTPError } from "lambert-server";
const router: Router = Router();
router.get("/", route({}), async (req: Request, res: Response) => {
- res.json(await User.findOne({ select: PrivateUserProjection, where: { id: req.user_id } }));
+ res.json(
+ await User.findOne({
+ select: PrivateUserProjection,
+ where: { id: req.user_id },
+ }),
+ );
});
-router.patch("/", route({ body: "UserModifySchema" }), async (req: Request, res: Response) => {
- const body = req.body as UserModifySchema;
-
- const user = await User.findOneOrFail({ where: { id: req.user_id }, select: [...PrivateUserProjection, "data"] });
-
- if (user.email == "demo@maddy.k.vu") throw new HTTPError("Demo user, sorry", 400);
+router.patch(
+ "/",
+ route({ body: "UserModifySchema" }),
+ async (req: Request, res: Response) => {
+ const body = req.body as UserModifySchema;
+
+ const user = await User.findOneOrFail({
+ where: { id: req.user_id },
+ select: [...PrivateUserProjection, "data"],
+ });
+
+ if (user.email == "demo@maddy.k.vu")
+ throw new HTTPError("Demo user, sorry", 400);
+
+ if (body.avatar)
+ body.avatar = await handleFile(
+ `/avatars/${req.user_id}`,
+ body.avatar as string,
+ );
+ if (body.banner)
+ body.banner = await handleFile(
+ `/banners/${req.user_id}`,
+ body.banner as string,
+ );
+
+ if (body.password) {
+ if (user.data?.hash) {
+ const same_password = await bcrypt.compare(
+ body.password,
+ user.data.hash || "",
+ );
+ if (!same_password) {
+ throw FieldErrors({
+ password: {
+ message: req.t("auth:login.INVALID_PASSWORD"),
+ code: "INVALID_PASSWORD",
+ },
+ });
+ }
+ } else {
+ user.data.hash = await bcrypt.hash(body.password, 12);
+ }
+ }
- if (body.avatar) body.avatar = await handleFile(`/avatars/${req.user_id}`, body.avatar as string);
- if (body.banner) body.banner = await handleFile(`/banners/${req.user_id}`, body.banner as string);
+ if (body.email) {
+ body.email = adjustEmail(body.email);
+ if (!body.email && Config.get().register.email.required)
+ throw FieldErrors({
+ email: {
+ message: req.t("auth:register.EMAIL_INVALID"),
+ code: "EMAIL_INVALID",
+ },
+ });
+ if (!body.password)
+ throw FieldErrors({
+ password: {
+ message: req.t("auth:register.INVALID_PASSWORD"),
+ code: "INVALID_PASSWORD",
+ },
+ });
+ }
- if (body.password) {
- if (user.data?.hash) {
- const same_password = await bcrypt.compare(body.password, user.data.hash || "");
- if (!same_password) {
- throw FieldErrors({ password: { message: req.t("auth:login.INVALID_PASSWORD"), code: "INVALID_PASSWORD" } });
+ if (body.new_password) {
+ if (!body.password && !user.email) {
+ throw FieldErrors({
+ password: {
+ code: "BASE_TYPE_REQUIRED",
+ message: req.t("common:field.BASE_TYPE_REQUIRED"),
+ },
+ });
}
- } else {
- user.data.hash = await bcrypt.hash(body.password, 12);
+ user.data.hash = await bcrypt.hash(body.new_password, 12);
}
- }
-
- if (body.email) {
- body.email = adjustEmail(body.email);
- if (!body.email && Config.get().register.email.required)
- throw FieldErrors({ email: { message: req.t("auth:register.EMAIL_INVALID"), code: "EMAIL_INVALID" } });
- if (!body.password)
- throw FieldErrors({ password: { message: req.t("auth:register.INVALID_PASSWORD"), code: "INVALID_PASSWORD" } });
- }
-
- if (body.new_password) {
- if (!body.password && !user.email) {
- throw FieldErrors({
- password: { code: "BASE_TYPE_REQUIRED", message: req.t("common:field.BASE_TYPE_REQUIRED") }
- });
- }
- user.data.hash = await bcrypt.hash(body.new_password, 12);
- }
-
- if (body.username) {
- var check_username = body?.username?.replace(/\s/g, '');
- if (!check_username) {
- throw FieldErrors({
- username: { code: "BASE_TYPE_REQUIRED", message: req.t("common:field.BASE_TYPE_REQUIRED") }
- });
+
+ if (body.username) {
+ var check_username = body?.username?.replace(/\s/g, "");
+ if (!check_username) {
+ throw FieldErrors({
+ username: {
+ code: "BASE_TYPE_REQUIRED",
+ message: req.t("common:field.BASE_TYPE_REQUIRED"),
+ },
+ });
+ }
}
- }
- if (body.discriminator) {
- if (await User.findOne({ where: { discriminator: body.discriminator, username: body.username || user.username } })) {
- throw FieldErrors({
- discriminator: { code: "INVALID_DISCRIMINATOR", message: "This discriminator is already in use." }
- });
+ if (body.discriminator) {
+ if (
+ await User.findOne({
+ where: {
+ discriminator: body.discriminator,
+ username: body.username || user.username,
+ },
+ })
+ ) {
+ throw FieldErrors({
+ discriminator: {
+ code: "INVALID_DISCRIMINATOR",
+ message: "This discriminator is already in use.",
+ },
+ });
+ }
}
- }
- user.assign(body);
- await user.save();
+ user.assign(body);
+ await user.save();
- // @ts-ignore
- delete user.data;
+ // @ts-ignore
+ delete user.data;
- // TODO: send update member list event in gateway
- await emitEvent({
- event: "USER_UPDATE",
- user_id: req.user_id,
- data: user
- } as UserUpdateEvent);
+ // TODO: send update member list event in gateway
+ await emitEvent({
+ event: "USER_UPDATE",
+ user_id: req.user_id,
+ data: user,
+ } as UserUpdateEvent);
- res.json(user);
-});
+ res.json(user);
+ },
+);
export default router;
// {"message": "Invalid two-factor code", "code": 60008}
diff --git a/src/api/routes/users/@me/mfa/codes-verification.ts b/src/api/routes/users/@me/mfa/codes-verification.ts
index 071c71fa..3411605b 100644
--- a/src/api/routes/users/@me/mfa/codes-verification.ts
+++ b/src/api/routes/users/@me/mfa/codes-verification.ts
@@ -1,41 +1,49 @@
import { Router, Request, Response } from "express";
import { route } from "@fosscord/api";
-import { BackupCode, generateMfaBackupCodes, User, CodesVerificationSchema } from "@fosscord/util";
+import {
+ BackupCode,
+ generateMfaBackupCodes,
+ User,
+ CodesVerificationSchema,
+} from "@fosscord/util";
const router = Router();
-router.post("/", route({ body: "CodesVerificationSchema" }), async (req: Request, res: Response) => {
- const { key, nonce, regenerate } = req.body as CodesVerificationSchema;
-
- // TODO: We don't have email/etc etc, so can't send a verification code.
- // Once that's done, this route can verify `key`
-
- const user = await User.findOneOrFail({ where: { id: req.user_id } });
-
- var codes: BackupCode[];
- if (regenerate) {
- await BackupCode.update(
- { user: { id: req.user_id } },
- { expired: true }
- );
-
- codes = generateMfaBackupCodes(req.user_id);
- await Promise.all(codes.map(x => x.save()));
- }
- else {
- codes = await BackupCode.find({
- where: {
- user: {
- id: req.user_id,
+router.post(
+ "/",
+ route({ body: "CodesVerificationSchema" }),
+ async (req: Request, res: Response) => {
+ const { key, nonce, regenerate } = req.body as CodesVerificationSchema;
+
+ // TODO: We don't have email/etc etc, so can't send a verification code.
+ // Once that's done, this route can verify `key`
+
+ const user = await User.findOneOrFail({ where: { id: req.user_id } });
+
+ var codes: BackupCode[];
+ if (regenerate) {
+ await BackupCode.update(
+ { user: { id: req.user_id } },
+ { expired: true },
+ );
+
+ codes = generateMfaBackupCodes(req.user_id);
+ await Promise.all(codes.map((x) => x.save()));
+ } else {
+ codes = await BackupCode.find({
+ where: {
+ user: {
+ id: req.user_id,
+ },
+ expired: false,
},
- expired: false,
- }
- });
- }
+ });
+ }
- return res.json({
- backup_codes: codes.map(x => ({ ...x, expired: undefined })),
- });
-});
+ return res.json({
+ backup_codes: codes.map((x) => ({ ...x, expired: undefined })),
+ });
+ },
+);
export default router;
diff --git a/src/api/routes/users/@me/mfa/codes.ts b/src/api/routes/users/@me/mfa/codes.ts
index 58466b9c..33053028 100644
--- a/src/api/routes/users/@me/mfa/codes.ts
+++ b/src/api/routes/users/@me/mfa/codes.ts
@@ -1,45 +1,62 @@
import { Router, Request, Response } from "express";
import { route } from "@fosscord/api";
-import { BackupCode, FieldErrors, generateMfaBackupCodes, User, MfaCodesSchema } from "@fosscord/util";
+import {
+ BackupCode,
+ FieldErrors,
+ generateMfaBackupCodes,
+ User,
+ MfaCodesSchema,
+} from "@fosscord/util";
import bcrypt from "bcrypt";
const router = Router();
// TODO: This route is replaced with users/@me/mfa/codes-verification in newer clients
-router.post("/", route({ body: "MfaCodesSchema" }), async (req: Request, res: Response) => {
- const { password, regenerate } = req.body as MfaCodesSchema;
-
- const user = await User.findOneOrFail({ where: { id: req.user_id }, select: ["data"] });
-
- if (!await bcrypt.compare(password, user.data.hash || "")) {
- throw FieldErrors({ password: { message: req.t("auth:login.INVALID_PASSWORD"), code: "INVALID_PASSWORD" } });
- }
-
- var codes: BackupCode[];
- if (regenerate) {
- await BackupCode.update(
- { user: { id: req.user_id } },
- { expired: true }
- );
-
- codes = generateMfaBackupCodes(req.user_id);
- await Promise.all(codes.map(x => x.save()));
- }
- else {
- codes = await BackupCode.find({
- where: {
- user: {
- id: req.user_id,
- },
- expired: false,
- }
+router.post(
+ "/",
+ route({ body: "MfaCodesSchema" }),
+ async (req: Request, res: Response) => {
+ const { password, regenerate } = req.body as MfaCodesSchema;
+
+ const user = await User.findOneOrFail({
+ where: { id: req.user_id },
+ select: ["data"],
});
- }
- return res.json({
- backup_codes: codes.map(x => ({ ...x, expired: undefined })),
- });
-});
+ if (!(await bcrypt.compare(password, user.data.hash || ""))) {
+ throw FieldErrors({
+ password: {
+ message: req.t("auth:login.INVALID_PASSWORD"),
+ code: "INVALID_PASSWORD",
+ },
+ });
+ }
+
+ var codes: BackupCode[];
+ if (regenerate) {
+ await BackupCode.update(
+ { user: { id: req.user_id } },
+ { expired: true },
+ );
+
+ codes = generateMfaBackupCodes(req.user_id);
+ await Promise.all(codes.map((x) => x.save()));
+ } else {
+ codes = await BackupCode.find({
+ where: {
+ user: {
+ id: req.user_id,
+ },
+ expired: false,
+ },
+ });
+ }
+
+ return res.json({
+ backup_codes: codes.map((x) => ({ ...x, expired: undefined })),
+ });
+ },
+);
export default router;
diff --git a/src/api/routes/users/@me/mfa/totp/disable.ts b/src/api/routes/users/@me/mfa/totp/disable.ts
index 2fe9355c..7916e598 100644
--- a/src/api/routes/users/@me/mfa/totp/disable.ts
+++ b/src/api/routes/users/@me/mfa/totp/disable.ts
@@ -1,41 +1,56 @@
import { Router, Request, Response } from "express";
import { route } from "@fosscord/api";
-import { verifyToken } from 'node-2fa';
+import { verifyToken } from "node-2fa";
import { HTTPError } from "lambert-server";
-import { User, generateToken, BackupCode, TotpDisableSchema } from "@fosscord/util";
+import {
+ User,
+ generateToken,
+ BackupCode,
+ TotpDisableSchema,
+} from "@fosscord/util";
const router = Router();
-router.post("/", route({ body: "TotpDisableSchema" }), async (req: Request, res: Response) => {
- const body = req.body as TotpDisableSchema;
-
- const user = await User.findOneOrFail({ where: { id: req.user_id }, select: ["totp_secret"] });
-
- const backup = await BackupCode.findOne({ where: { code: body.code } });
- if (!backup) {
- const ret = verifyToken(user.totp_secret!, body.code);
- if (!ret || ret.delta != 0)
- throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
- }
-
- await User.update(
- { id: req.user_id },
- {
- mfa_enabled: false,
- totp_secret: "",
- },
- );
-
- await BackupCode.update(
- { user: { id: req.user_id } },
- {
- expired: true,
+router.post(
+ "/",
+ route({ body: "TotpDisableSchema" }),
+ async (req: Request, res: Response) => {
+ const body = req.body as TotpDisableSchema;
+
+ const user = await User.findOneOrFail({
+ where: { id: req.user_id },
+ select: ["totp_secret"],
+ });
+
+ const backup = await BackupCode.findOne({ where: { code: body.code } });
+ if (!backup) {
+ const ret = verifyToken(user.totp_secret!, body.code);
+ if (!ret || ret.delta != 0)
+ throw new HTTPError(
+ req.t("auth:login.INVALID_TOTP_CODE"),
+ 60008,
+ );
}
- );
- return res.json({
- token: await generateToken(user.id),
- });
-});
-
-export default router;
\ No newline at end of file
+ await User.update(
+ { id: req.user_id },
+ {
+ mfa_enabled: false,
+ totp_secret: "",
+ },
+ );
+
+ await BackupCode.update(
+ { user: { id: req.user_id } },
+ {
+ expired: true,
+ },
+ );
+
+ return res.json({
+ token: await generateToken(user.id),
+ });
+ },
+);
+
+export default router;
diff --git a/src/api/routes/users/@me/mfa/totp/enable.ts b/src/api/routes/users/@me/mfa/totp/enable.ts
index adafe180..75c64425 100644
--- a/src/api/routes/users/@me/mfa/totp/enable.ts
+++ b/src/api/routes/users/@me/mfa/totp/enable.ts
@@ -1,46 +1,62 @@
import { Router, Request, Response } from "express";
-import { User, generateToken, generateMfaBackupCodes, TotpEnableSchema } from "@fosscord/util";
+import {
+ User,
+ generateToken,
+ generateMfaBackupCodes,
+ TotpEnableSchema,
+} from "@fosscord/util";
import { route } from "@fosscord/api";
import bcrypt from "bcrypt";
import { HTTPError } from "lambert-server";
-import { verifyToken } from 'node-2fa';
+import { verifyToken } from "node-2fa";
const router = Router();
-router.post("/", route({ body: "TotpEnableSchema" }), async (req: Request, res: Response) => {
- const body = req.body as TotpEnableSchema;
-
- const user = await User.findOneOrFail({ where: { id: req.user_id }, select: ["data", "email"] });
-
- if (user.email == "demo@maddy.k.vu") throw new HTTPError("Demo user, sorry", 400);
-
- // TODO: Are guests allowed to enable 2fa?
- if (user.data.hash) {
- if (!await bcrypt.compare(body.password, user.data.hash)) {
- throw new HTTPError(req.t("auth:login.INVALID_PASSWORD"));
+router.post(
+ "/",
+ route({ body: "TotpEnableSchema" }),
+ async (req: Request, res: Response) => {
+ const body = req.body as TotpEnableSchema;
+
+ const user = await User.findOneOrFail({
+ where: { id: req.user_id },
+ select: ["data", "email"],
+ });
+
+ if (user.email == "demo@maddy.k.vu")
+ throw new HTTPError("Demo user, sorry", 400);
+
+ // TODO: Are guests allowed to enable 2fa?
+ if (user.data.hash) {
+ if (!(await bcrypt.compare(body.password, user.data.hash))) {
+ throw new HTTPError(req.t("auth:login.INVALID_PASSWORD"));
+ }
}
- }
-
- if (!body.secret)
- throw new HTTPError(req.t("auth:login.INVALID_TOTP_SECRET"), 60005);
-
- if (!body.code)
- throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
-
- if (verifyToken(body.secret, body.code)?.delta != 0)
- throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
-
- let backup_codes = generateMfaBackupCodes(req.user_id);
- await Promise.all(backup_codes.map(x => x.save()));
- await User.update(
- { id: req.user_id },
- { mfa_enabled: true, totp_secret: body.secret }
- );
-
- res.send({
- token: await generateToken(user.id),
- backup_codes: backup_codes.map(x => ({ ...x, expired: undefined })),
- });
-});
-export default router;
\ No newline at end of file
+ if (!body.secret)
+ throw new HTTPError(req.t("auth:login.INVALID_TOTP_SECRET"), 60005);
+
+ if (!body.code)
+ throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
+
+ if (verifyToken(body.secret, body.code)?.delta != 0)
+ throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
+
+ let backup_codes = generateMfaBackupCodes(req.user_id);
+ await Promise.all(backup_codes.map((x) => x.save()));
+ await User.update(
+ { id: req.user_id },
+ { mfa_enabled: true, totp_secret: body.secret },
+ );
+
+ res.send({
+ token: await generateToken(user.id),
+ backup_codes: backup_codes.map((x) => ({
+ ...x,
+ expired: undefined,
+ })),
+ });
+ },
+);
+
+export default router;
diff --git a/src/api/routes/users/@me/notes.ts b/src/api/routes/users/@me/notes.ts
index f938f088..e54eb897 100644
--- a/src/api/routes/users/@me/notes.ts
+++ b/src/api/routes/users/@me/notes.ts
@@ -11,7 +11,7 @@ router.get("/:id", route({}), async (req: Request, res: Response) => {
where: {
owner: { id: req.user_id },
target: { id: id },
- }
+ },
});
return res.json({
@@ -24,32 +24,40 @@ router.get("/:id", route({}), async (req: Request, res: Response) => {
router.put("/:id", route({}), async (req: Request, res: Response) => {
const { id } = req.params;
const owner = await User.findOneOrFail({ where: { id: req.user_id } });
- const target = await User.findOneOrFail({ where: { id: id } }); //if noted user does not exist throw
+ const target = await User.findOneOrFail({ where: { id: id } }); //if noted user does not exist throw
const { note } = req.body;
if (note && note.length) {
// upsert a note
- if (await Note.findOne({ where: { owner: { id: owner.id }, target: { id: target.id } } })) {
+ if (
+ await Note.findOne({
+ where: { owner: { id: owner.id }, target: { id: target.id } },
+ })
+ ) {
Note.update(
{ owner: { id: owner.id }, target: { id: target.id } },
- { owner, target, content: note }
+ { owner, target, content: note },
);
+ } else {
+ Note.insert({
+ id: Snowflake.generate(),
+ owner,
+ target,
+ content: note,
+ });
}
- else {
- Note.insert(
- { id: Snowflake.generate(), owner, target, content: note }
- );
- }
- }
- else {
- await Note.delete({ owner: { id: owner.id }, target: { id: target.id } });
+ } else {
+ await Note.delete({
+ owner: { id: owner.id },
+ target: { id: target.id },
+ });
}
await emitEvent({
event: "USER_NOTE_UPDATE",
data: {
note: note,
- id: target.id
+ id: target.id,
},
user_id: owner.id,
});
diff --git a/src/api/routes/users/@me/relationships.ts b/src/api/routes/users/@me/relationships.ts
index cd33704d..3eec704b 100644
--- a/src/api/routes/users/@me/relationships.ts
+++ b/src/api/routes/users/@me/relationships.ts
@@ -6,7 +6,7 @@ import {
RelationshipRemoveEvent,
emitEvent,
Relationship,
- Config
+ Config,
} from "@fosscord/util";
import { Router, Response, Request } from "express";
import { HTTPError } from "lambert-server";
@@ -15,13 +15,16 @@ import { route } from "@fosscord/api";
const router = Router();
-const userProjection: (keyof User)[] = ["relationships", ...PublicUserProjection];
+const userProjection: (keyof User)[] = [
+ "relationships",
+ ...PublicUserProjection,
+];
router.get("/", route({}), async (req: Request, res: Response) => {
const user = await User.findOneOrFail({
where: { id: req.user_id },
relations: ["relationships", "relationships.to"],
- select: ["id", "relationships"]
+ select: ["id", "relationships"],
});
//TODO DTO
@@ -30,49 +33,76 @@ router.get("/", route({}), async (req: Request, res: Response) => {
id: r.to.id,
type: r.type,
nickname: null,
- user: r.to.toPublicUser()
+ user: r.to.toPublicUser(),
};
});
return res.json(related_users);
});
-router.put("/:id", route({ body: "RelationshipPutSchema" }), async (req: Request, res: Response) => {
- return await updateRelationship(
- req,
- res,
- await User.findOneOrFail({ where: { id: req.params.id }, relations: ["relationships", "relationships.to"], select: userProjection }),
- req.body.type ?? RelationshipType.friends
- );
-});
+router.put(
+ "/:id",
+ route({ body: "RelationshipPutSchema" }),
+ async (req: Request, res: Response) => {
+ return await updateRelationship(
+ req,
+ res,
+ await User.findOneOrFail({
+ where: { id: req.params.id },
+ relations: ["relationships", "relationships.to"],
+ select: userProjection,
+ }),
+ req.body.type ?? RelationshipType.friends,
+ );
+ },
+);
-router.post("/", route({ body: "RelationshipPostSchema" }), async (req: Request, res: Response) => {
- return await updateRelationship(
- req,
- res,
- await User.findOneOrFail({
- relations: ["relationships", "relationships.to"],
- select: userProjection,
- where: {
- discriminator: String(req.body.discriminator).padStart(4, "0"), //Discord send the discriminator as integer, we need to add leading zeroes
- username: req.body.username
- }
- }),
- req.body.type
- );
-});
+router.post(
+ "/",
+ route({ body: "RelationshipPostSchema" }),
+ async (req: Request, res: Response) => {
+ return await updateRelationship(
+ req,
+ res,
+ await User.findOneOrFail({
+ relations: ["relationships", "relationships.to"],
+ select: userProjection,
+ where: {
+ discriminator: String(req.body.discriminator).padStart(
+ 4,
+ "0",
+ ), //Discord send the discriminator as integer, we need to add leading zeroes
+ username: req.body.username,
+ },
+ }),
+ req.body.type,
+ );
+ },
+);
router.delete("/:id", route({}), async (req: Request, res: Response) => {
const { id } = req.params;
- if (id === req.user_id) throw new HTTPError("You can't remove yourself as a friend");
+ if (id === req.user_id)
+ throw new HTTPError("You can't remove yourself as a friend");
- const user = await User.findOneOrFail({ where: { id: req.user_id }, select: userProjection, relations: ["relationships"] });
- const friend = await User.findOneOrFail({ where: { id: id }, select: userProjection, relations: ["relationships"] });
+ const user = await User.findOneOrFail({
+ where: { id: req.user_id },
+ select: userProjection,
+ relations: ["relationships"],
+ });
+ const friend = await User.findOneOrFail({
+ where: { id: id },
+ select: userProjection,
+ relations: ["relationships"],
+ });
const relationship = user.relationships.find((x) => x.to_id === id);
- const friendRequest = friend.relationships.find((x) => x.to_id === req.user_id);
+ const friendRequest = friend.relationships.find(
+ (x) => x.to_id === req.user_id,
+ );
- if (!relationship) throw new HTTPError("You are not friends with the user", 404);
+ if (!relationship)
+ throw new HTTPError("You are not friends with the user", 404);
if (relationship?.type === RelationshipType.blocked) {
// unblock user
@@ -81,8 +111,8 @@ router.delete("/:id", route({}), async (req: Request, res: Response) => {
emitEvent({
event: "RELATIONSHIP_REMOVE",
user_id: req.user_id,
- data: relationship.toPublicRelationship()
- } as RelationshipRemoveEvent)
+ data: relationship.toPublicRelationship(),
+ } as RelationshipRemoveEvent),
]);
return res.sendStatus(204);
}
@@ -92,8 +122,8 @@ router.delete("/:id", route({}), async (req: Request, res: Response) => {
await emitEvent({
event: "RELATIONSHIP_REMOVE",
data: friendRequest.toPublicRelationship(),
- user_id: id
- } as RelationshipRemoveEvent)
+ user_id: id,
+ } as RelationshipRemoveEvent),
]);
}
@@ -102,8 +132,8 @@ router.delete("/:id", route({}), async (req: Request, res: Response) => {
emitEvent({
event: "RELATIONSHIP_REMOVE",
data: relationship.toPublicRelationship(),
- user_id: req.user_id
- } as RelationshipRemoveEvent)
+ user_id: req.user_id,
+ } as RelationshipRemoveEvent),
]);
return res.sendStatus(204);
@@ -111,26 +141,40 @@ router.delete("/:id", route({}), async (req: Request, res: Response) => {
export default router;
-async function updateRelationship(req: Request, res: Response, friend: User, type: RelationshipType) {
+async function updateRelationship(
+ req: Request,
+ res: Response,
+ friend: User,
+ type: RelationshipType,
+) {
const id = friend.id;
- if (id === req.user_id) throw new HTTPError("You can't add yourself as a friend");
+ if (id === req.user_id)
+ throw new HTTPError("You can't add yourself as a friend");
const user = await User.findOneOrFail({
where: { id: req.user_id },
- relations: ["relationships", "relationships.to"], select: userProjection
+ relations: ["relationships", "relationships.to"],
+ select: userProjection,
});
var relationship = user.relationships.find((x) => x.to_id === id);
- const friendRequest = friend.relationships.find((x) => x.to_id === req.user_id);
+ const friendRequest = friend.relationships.find(
+ (x) => x.to_id === req.user_id,
+ );
// TODO: you can add infinitely many blocked users (should this be prevented?)
if (type === RelationshipType.blocked) {
if (relationship) {
- if (relationship.type === RelationshipType.blocked) throw new HTTPError("You already blocked the user");
+ if (relationship.type === RelationshipType.blocked)
+ throw new HTTPError("You already blocked the user");
relationship.type = RelationshipType.blocked;
await relationship.save();
} else {
- relationship = await Relationship.create({ to_id: id, type: RelationshipType.blocked, from_id: req.user_id }).save();
+ relationship = await Relationship.create({
+ to_id: id,
+ type: RelationshipType.blocked,
+ from_id: req.user_id,
+ }).save();
}
if (friendRequest && friendRequest.type !== RelationshipType.blocked) {
@@ -139,43 +183,56 @@ async function updateRelationship(req: Request, res: Response, friend: User, typ
emitEvent({
event: "RELATIONSHIP_REMOVE",
data: friendRequest.toPublicRelationship(),
- user_id: id
- } as RelationshipRemoveEvent)
+ user_id: id,
+ } as RelationshipRemoveEvent),
]);
}
await emitEvent({
event: "RELATIONSHIP_ADD",
data: relationship.toPublicRelationship(),
- user_id: req.user_id
+ user_id: req.user_id,
} as RelationshipAddEvent);
return res.sendStatus(204);
}
const { maxFriends } = Config.get().limits.user;
- if (user.relationships.length >= maxFriends) throw DiscordApiErrors.MAXIMUM_FRIENDS.withParams(maxFriends);
+ if (user.relationships.length >= maxFriends)
+ throw DiscordApiErrors.MAXIMUM_FRIENDS.withParams(maxFriends);
- var incoming_relationship = Relationship.create({ nickname: undefined, type: RelationshipType.incoming, to: user, from: friend });
+ var incoming_relationship = Relationship.create({
+ nickname: undefined,
+ type: RelationshipType.incoming,
+ to: user,
+ from: friend,
+ });
var outgoing_relationship = Relationship.create({
nickname: undefined,
type: RelationshipType.outgoing,
to: friend,
- from: user
+ from: user,
});
if (friendRequest) {
- if (friendRequest.type === RelationshipType.blocked) throw new HTTPError("The user blocked you");
- if (friendRequest.type === RelationshipType.friends) throw new HTTPError("You are already friends with the user");
+ if (friendRequest.type === RelationshipType.blocked)
+ throw new HTTPError("The user blocked you");
+ if (friendRequest.type === RelationshipType.friends)
+ throw new HTTPError("You are already friends with the user");
// accept friend request
incoming_relationship = friendRequest;
incoming_relationship.type = RelationshipType.friends;
}
if (relationship) {
- if (relationship.type === RelationshipType.outgoing) throw new HTTPError("You already sent a friend request");
- if (relationship.type === RelationshipType.blocked) throw new HTTPError("Unblock the user before sending a friend request");
- if (relationship.type === RelationshipType.friends) throw new HTTPError("You are already friends with the user");
+ if (relationship.type === RelationshipType.outgoing)
+ throw new HTTPError("You already sent a friend request");
+ if (relationship.type === RelationshipType.blocked)
+ throw new HTTPError(
+ "Unblock the user before sending a friend request",
+ );
+ if (relationship.type === RelationshipType.friends)
+ throw new HTTPError("You are already friends with the user");
outgoing_relationship = relationship;
outgoing_relationship.type = RelationshipType.friends;
}
@@ -186,16 +243,16 @@ async function updateRelationship(req: Request, res: Response, friend: User, typ
emitEvent({
event: "RELATIONSHIP_ADD",
data: outgoing_relationship.toPublicRelationship(),
- user_id: req.user_id
+ user_id: req.user_id,
} as RelationshipAddEvent),
emitEvent({
event: "RELATIONSHIP_ADD",
data: {
...incoming_relationship.toPublicRelationship(),
- should_notify: true
+ should_notify: true,
},
- user_id: id
- } as RelationshipAddEvent)
+ user_id: id,
+ } as RelationshipAddEvent),
]);
return res.sendStatus(204);
diff --git a/src/api/routes/users/@me/settings.ts b/src/api/routes/users/@me/settings.ts
index 9060baf7..30e5969c 100644
--- a/src/api/routes/users/@me/settings.ts
+++ b/src/api/routes/users/@me/settings.ts
@@ -4,25 +4,31 @@ import { route } from "@fosscord/api";
const router = Router();
-export interface UserSettingsSchema extends Partial<UserSettings> { }
+export interface UserSettingsSchema extends Partial<UserSettings> {}
router.get("/", route({}), async (req: Request, res: Response) => {
const user = await User.findOneOrFail({
where: { id: req.user_id },
- select: ["settings"]
+ select: ["settings"],
});
return res.json(user.settings);
});
-router.patch("/", route({ body: "UserSettingsSchema" }), async (req: Request, res: Response) => {
- const body = req.body as UserSettings;
- if (body.locale === "en") body.locale = "en-US"; // fix discord client crash on unkown locale
+router.patch(
+ "/",
+ route({ body: "UserSettingsSchema" }),
+ async (req: Request, res: Response) => {
+ const body = req.body as UserSettings;
+ if (body.locale === "en") body.locale = "en-US"; // fix discord client crash on unkown locale
- const user = await User.findOneOrFail({ where: { id: req.user_id, bot: false } });
- user.settings = { ...user.settings, ...body };
- await user.save();
+ const user = await User.findOneOrFail({
+ where: { id: req.user_id, bot: false },
+ });
+ user.settings = { ...user.settings, ...body };
+ await user.save();
- res.json(user.settings);
-});
+ res.json(user.settings);
+ },
+);
export default router;
|