diff --git a/api/src/routes/auth/verify/view-backup-codes-challenge.ts b/api/src/routes/auth/verify/view-backup-codes-challenge.ts
new file mode 100644
index 00000000..be651686
--- /dev/null
+++ b/api/src/routes/auth/verify/view-backup-codes-challenge.ts
@@ -0,0 +1,26 @@
+import { Router, Request, Response } from "express";
+import { route } from "@fosscord/api";
+import { FieldErrors, User } from "@fosscord/util";
+import bcrypt from "bcrypt";
+const router = Router();
+
+export interface BackupCodesChallengeSchema {
+ password: string;
+}
+
+router.post("/", route({ body: "BackupCodesChallengeSchema" }), async (req: Request, res: Response) => {
+ const { password } = req.body as BackupCodesChallengeSchema;
+
+ const user = await User.findOneOrFail({ 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" } });
+ }
+
+ return res.json({
+ nonce: "NoncePlaceholder",
+ regenerate_nonce: "RegenNoncePlaceholder",
+ })
+});
+
+export default router;
diff --git a/api/src/routes/guilds/#guild_id/index.ts b/api/src/routes/guilds/#guild_id/index.ts
index 4ec3df72..45e30a74 100644
--- a/api/src/routes/guilds/#guild_id/index.ts
+++ b/api/src/routes/guilds/#guild_id/index.ts
@@ -20,6 +20,7 @@ export interface GuildUpdateSchema extends Omit<GuildCreateSchema, "channels"> {
afk_timeout?: number;
afk_channel_id?: string;
preferred_locale?: string;
+ premium_progress_bar_enabled?: boolean;
}
router.get("/", route({}), async (req: Request, res: Response) => {
diff --git a/api/src/routes/guilds/#guild_id/member-verification.ts b/api/src/routes/guilds/#guild_id/member-verification.ts
new file mode 100644
index 00000000..265a1b35
--- /dev/null
+++ b/api/src/routes/guilds/#guild_id/member-verification.ts
@@ -0,0 +1,14 @@
+import { Router, Request, Response } from "express";
+import { route } from "@fosscord/api";
+const router = Router();
+
+router.get("/",route({}), async (req: Request, res: Response) => {
+ // TODO: member verification
+
+ res.status(404).json({
+ message: "Unknown Guild Member Verification Form",
+ code: 10068
+ });
+});
+
+export default router;
diff --git a/api/src/routes/guilds/#guild_id/roles/#role_id/index.ts b/api/src/routes/guilds/#guild_id/roles/#role_id/index.ts
index 2ad01682..f3d707e0 100644
--- a/api/src/routes/guilds/#guild_id/roles/#role_id/index.ts
+++ b/api/src/routes/guilds/#guild_id/roles/#role_id/index.ts
@@ -42,6 +42,7 @@ router.patch("/", route({ body: "RoleModifySchema", permission: "MANAGE_ROLES" }
const body = req.body as RoleModifySchema;
if (body.icon) body.icon = await handleFile(`/role-icons/${role_id}`, body.icon as string);
+ else body.icon = undefined;
const role = new Role({
...body,
diff --git a/api/src/routes/guilds/#guild_id/welcome_screen.ts b/api/src/routes/guilds/#guild_id/welcome-screen.ts
index 7141f17e..5c7a9daa 100644
--- a/api/src/routes/guilds/#guild_id/welcome_screen.ts
+++ b/api/src/routes/guilds/#guild_id/welcome-screen.ts
@@ -10,7 +10,7 @@ export interface GuildUpdateWelcomeScreenSchema {
channel_id: string;
description: string;
emoji_id?: string;
- emoji_name: string;
+ emoji_name?: string;
}[];
enabled?: boolean;
description?: string;
@@ -36,6 +36,8 @@ router.patch("/", route({ body: "GuildUpdateWelcomeScreenSchema", permission: "M
if (body.description) guild.welcome_screen.description = body.description;
if (body.enabled != null) guild.welcome_screen.enabled = body.enabled;
+ await guild.save();
+
res.sendStatus(204);
});
diff --git a/api/src/routes/guilds/index.ts b/api/src/routes/guilds/index.ts
index 10721413..489dea49 100644
--- a/api/src/routes/guilds/index.ts
+++ b/api/src/routes/guilds/index.ts
@@ -9,7 +9,7 @@ export interface GuildCreateSchema {
/**
* @maxLength 100
*/
- name: string;
+ name?: string;
region?: string;
icon?: string | null;
channels?: ChannelModifySchema[];
diff --git a/api/src/routes/store/published-listings/skus/#sku_id/subscription-plans.ts b/api/src/routes/store/published-listings/skus/#sku_id/subscription-plans.ts
index 723a5160..03162ec8 100644
--- a/api/src/routes/store/published-listings/skus/#sku_id/subscription-plans.ts
+++ b/api/src/routes/store/published-listings/skus/#sku_id/subscription-plans.ts
@@ -5,6 +5,22 @@ const router: Router = Router();
const skus = new Map([
[
+ "978380684370378762",
+ [
+ {
+ id: "978380692553465866",
+ name: "Nitro Lite Monthly",
+ interval: 1,
+ interval_count: 1,
+ tag_inclusive: true,
+ sku_id: "978380684370378762",
+ currency: "usd",
+ price: 0,
+ price_tier: null,
+ }
+ ]
+ ],
+ [
"521842865731534868",
[
{
diff --git a/api/src/routes/users/@me/index.ts b/api/src/routes/users/@me/index.ts
index 1af413c4..107e59c4 100644
--- a/api/src/routes/users/@me/index.ts
+++ b/api/src/routes/users/@me/index.ts
@@ -21,6 +21,7 @@ export interface UserModifySchema {
password?: string;
new_password?: string;
code?: string;
+ discriminator?: string;
}
router.get("/", route({}), async (req: Request, res: Response) => {
diff --git a/api/src/routes/users/@me/mfa/codes-verification.ts b/api/src/routes/users/@me/mfa/codes-verification.ts
new file mode 100644
index 00000000..3aca44a6
--- /dev/null
+++ b/api/src/routes/users/@me/mfa/codes-verification.ts
@@ -0,0 +1,45 @@
+import { Router, Request, Response } from "express";
+import { route } from "@fosscord/api";
+import { BackupCode, generateMfaBackupCodes, User } from "@fosscord/util";
+
+const router = Router();
+
+export interface CodesVerificationSchema {
+ key: string;
+ nonce: string;
+ regenerate?: boolean;
+}
+
+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({ 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({
+ user: {
+ id: req.user_id,
+ },
+ expired: false,
+ });
+ }
+
+ return res.json({
+ backup_codes: codes.map(x => ({ ...x, expired: undefined })),
+ })
+});
+
+export default router;
|