mirror of
https://github.com/spacebarchat/server.git
synced 2026-03-30 16:05:41 +00:00
Prettier u4
This commit is contained in:
@@ -17,19 +17,9 @@
|
||||
*/
|
||||
|
||||
import { route } from "@spacebar/api";
|
||||
import {
|
||||
Config,
|
||||
DiscordApiErrors,
|
||||
Emoji,
|
||||
GuildEmojisUpdateEvent,
|
||||
Member,
|
||||
Snowflake,
|
||||
User,
|
||||
emitEvent,
|
||||
handleFile,
|
||||
} from "@spacebar/util";
|
||||
import { Config, DiscordApiErrors, Emoji, GuildEmojisUpdateEvent, Member, Snowflake, User, emitEvent, handleFile } from "@spacebar/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { EmojiCreateSchema, EmojiModifySchema } from "@spacebar/schemas"
|
||||
import { EmojiCreateSchema, EmojiModifySchema } from "@spacebar/schemas";
|
||||
|
||||
const router = Router({ mergeParams: true });
|
||||
|
||||
@@ -115,10 +105,7 @@ router.post(
|
||||
});
|
||||
const { maxEmojis } = Config.get().limits.guild;
|
||||
|
||||
if (emoji_count >= maxEmojis)
|
||||
throw DiscordApiErrors.MAXIMUM_NUMBER_OF_EMOJIS_REACHED.withParams(
|
||||
maxEmojis,
|
||||
);
|
||||
if (emoji_count >= maxEmojis) throw DiscordApiErrors.MAXIMUM_NUMBER_OF_EMOJIS_REACHED.withParams(maxEmojis);
|
||||
if (body.require_colons == null) body.require_colons = true;
|
||||
|
||||
const user = await User.findOneOrFail({ where: { id: req.user_id } });
|
||||
@@ -132,10 +119,7 @@ router.post(
|
||||
require_colons: body.require_colons ?? undefined, // schema allows nulls, db does not
|
||||
user: user,
|
||||
managed: false,
|
||||
animated:
|
||||
mimeType == "image/gif" ||
|
||||
mimeType == "image/apng" ||
|
||||
mimeType == "video/webm",
|
||||
animated: mimeType == "image/gif" || mimeType == "image/apng" || mimeType == "video/webm",
|
||||
available: true,
|
||||
roles: [],
|
||||
}).save();
|
||||
|
||||
@@ -17,22 +17,10 @@
|
||||
*/
|
||||
|
||||
import { route } from "@spacebar/api";
|
||||
import {
|
||||
Channel,
|
||||
DiscordApiErrors,
|
||||
Guild,
|
||||
GuildUpdateEvent,
|
||||
Member,
|
||||
Permissions,
|
||||
SpacebarApiErrors,
|
||||
emitEvent,
|
||||
getPermission,
|
||||
getRights,
|
||||
handleFile,
|
||||
} from "@spacebar/util";
|
||||
import { Channel, DiscordApiErrors, Guild, GuildUpdateEvent, Member, Permissions, SpacebarApiErrors, emitEvent, getPermission, getRights, handleFile } from "@spacebar/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { GuildUpdateSchema } from "@spacebar/schemas"
|
||||
import { GuildUpdateSchema } from "@spacebar/schemas";
|
||||
|
||||
const router = Router({ mergeParams: true });
|
||||
|
||||
@@ -54,15 +42,8 @@ router.get(
|
||||
async (req: Request, res: Response) => {
|
||||
const { guild_id } = req.params;
|
||||
|
||||
const [guild, member] = await Promise.all([
|
||||
Guild.findOneOrFail({ where: { id: guild_id } }),
|
||||
Member.findOne({ where: { guild_id: guild_id, id: req.user_id } }),
|
||||
]);
|
||||
if (!member)
|
||||
throw new HTTPError(
|
||||
"You are not a member of the guild you are trying to access",
|
||||
401,
|
||||
);
|
||||
const [guild, member] = await Promise.all([Guild.findOneOrFail({ where: { id: guild_id } }), Member.findOne({ where: { guild_id: guild_id, id: req.user_id } })]);
|
||||
if (!member) throw new HTTPError("You are not a member of the guild you are trying to access", 401);
|
||||
|
||||
return res.send({
|
||||
...guild,
|
||||
@@ -98,10 +79,7 @@ router.patch(
|
||||
const rights = await getRights(req.user_id);
|
||||
const permission = await getPermission(req.user_id, guild_id);
|
||||
|
||||
if (!rights.has("MANAGE_GUILDS") && !permission.has("MANAGE_GUILD"))
|
||||
throw DiscordApiErrors.MISSING_PERMISSIONS.withParams(
|
||||
"MANAGE_GUILDS",
|
||||
);
|
||||
if (!rights.has("MANAGE_GUILDS") && !permission.has("MANAGE_GUILD")) throw DiscordApiErrors.MISSING_PERMISSIONS.withParams("MANAGE_GUILDS");
|
||||
|
||||
const guild = await Guild.findOneOrFail({
|
||||
where: { id: guild_id },
|
||||
@@ -118,47 +96,25 @@ router.patch(
|
||||
|
||||
// TODO: guild update check image
|
||||
|
||||
if (body.icon && body.icon != guild.icon)
|
||||
body.icon = await handleFile(`/icons/${guild_id}`, body.icon);
|
||||
if (body.icon && body.icon != guild.icon) body.icon = await handleFile(`/icons/${guild_id}`, body.icon);
|
||||
|
||||
if (body.banner && body.banner !== guild.banner)
|
||||
body.banner = await handleFile(`/banners/${guild_id}`, body.banner);
|
||||
if (body.banner && body.banner !== guild.banner) body.banner = await handleFile(`/banners/${guild_id}`, body.banner);
|
||||
|
||||
if (body.splash && body.splash !== guild.splash)
|
||||
body.splash = await handleFile(
|
||||
`/splashes/${guild_id}`,
|
||||
body.splash,
|
||||
);
|
||||
if (body.splash && body.splash !== guild.splash) body.splash = await handleFile(`/splashes/${guild_id}`, body.splash);
|
||||
|
||||
if (
|
||||
body.discovery_splash &&
|
||||
body.discovery_splash !== guild.discovery_splash
|
||||
)
|
||||
body.discovery_splash = await handleFile(
|
||||
`/discovery-splashes/${guild_id}`,
|
||||
body.discovery_splash,
|
||||
);
|
||||
if (body.discovery_splash && body.discovery_splash !== guild.discovery_splash)
|
||||
body.discovery_splash = await handleFile(`/discovery-splashes/${guild_id}`, body.discovery_splash);
|
||||
|
||||
if (body.features) {
|
||||
const diff = guild.features
|
||||
.filter((x) => !body.features?.includes(x))
|
||||
.concat(
|
||||
body.features.filter((x) => !guild.features.includes(x)),
|
||||
);
|
||||
const diff = guild.features.filter((x) => !body.features?.includes(x)).concat(body.features.filter((x) => !guild.features.includes(x)));
|
||||
|
||||
// TODO move these
|
||||
const MUTABLE_FEATURES = [
|
||||
"COMMUNITY",
|
||||
"INVITES_DISABLED",
|
||||
"DISCOVERABLE",
|
||||
];
|
||||
const MUTABLE_FEATURES = ["COMMUNITY", "INVITES_DISABLED", "DISCOVERABLE"];
|
||||
|
||||
for (const feature of diff) {
|
||||
if (MUTABLE_FEATURES.includes(feature)) continue;
|
||||
|
||||
throw SpacebarApiErrors.FEATURE_IS_IMMUTABLE.withParams(
|
||||
feature,
|
||||
);
|
||||
throw SpacebarApiErrors.FEATURE_IS_IMMUTABLE.withParams(feature);
|
||||
}
|
||||
|
||||
// for some reason, they don't update in the assign.
|
||||
|
||||
@@ -17,15 +17,9 @@
|
||||
*/
|
||||
|
||||
import { route } from "@spacebar/api";
|
||||
import {
|
||||
emitEvent,
|
||||
GuildMemberUpdateEvent,
|
||||
handleFile,
|
||||
Member,
|
||||
OrmUtils,
|
||||
} from "@spacebar/util";
|
||||
import { emitEvent, GuildMemberUpdateEvent, handleFile, Member, OrmUtils } from "@spacebar/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { MemberChangeProfileSchema } from "@spacebar/schemas"
|
||||
import { MemberChangeProfileSchema } from "@spacebar/schemas";
|
||||
|
||||
const router = Router({ mergeParams: true });
|
||||
|
||||
@@ -56,11 +50,7 @@ router.patch(
|
||||
relations: ["roles", "user"],
|
||||
});
|
||||
|
||||
if (body.banner)
|
||||
body.banner = await handleFile(
|
||||
`/guilds/${guild_id}/users/${req.user_id}/avatars`,
|
||||
body.banner as string,
|
||||
);
|
||||
if (body.banner) body.banner = await handleFile(`/guilds/${guild_id}/users/${req.user_id}/avatars`, body.banner as string);
|
||||
|
||||
member = await OrmUtils.mergeDeep(member, body);
|
||||
|
||||
|
||||
@@ -23,12 +23,7 @@ import { IsNull, LessThan } from "typeorm";
|
||||
const router = Router({ mergeParams: true });
|
||||
|
||||
//Returns all inactive members, respecting role hierarchy
|
||||
const inactiveMembers = async (
|
||||
guild_id: string,
|
||||
user_id: string,
|
||||
days: number,
|
||||
roles: string[] = [],
|
||||
) => {
|
||||
const inactiveMembers = async (guild_id: string, user_id: string, days: number, roles: string[] = []) => {
|
||||
const date = new Date();
|
||||
date.setDate(date.getDate() - days);
|
||||
//Snowflake should have `generateFromTime` method? Or similar?
|
||||
@@ -54,10 +49,7 @@ const inactiveMembers = async (
|
||||
if (!members.length) return [];
|
||||
|
||||
//I'm sure I can do this in the above db query ( and it would probably be better to do so ), but oh well.
|
||||
if (roles.length && members.length)
|
||||
members = members.filter((user) =>
|
||||
user.roles?.some((role) => roles.includes(role.id)),
|
||||
);
|
||||
if (roles.length && members.length) members = members.filter((user) => user.roles?.some((role) => roles.includes(role.id)));
|
||||
|
||||
const me = await Member.findOneOrFail({
|
||||
where: { id: user_id, guild_id },
|
||||
@@ -95,12 +87,7 @@ router.get(
|
||||
let roles = req.query.include_roles;
|
||||
if (typeof roles === "string") roles = [roles]; //express will return array otherwise
|
||||
|
||||
const members = await inactiveMembers(
|
||||
req.params.guild_id,
|
||||
req.user_id,
|
||||
days,
|
||||
roles as string[],
|
||||
);
|
||||
const members = await inactiveMembers(req.params.guild_id, req.user_id, days, roles as string[]);
|
||||
|
||||
res.send({ pruned: members.length });
|
||||
},
|
||||
@@ -127,16 +114,9 @@ router.post(
|
||||
if (typeof roles === "string") roles = [roles];
|
||||
|
||||
const { guild_id } = req.params;
|
||||
const members = await inactiveMembers(
|
||||
guild_id,
|
||||
req.user_id,
|
||||
days,
|
||||
roles as string[],
|
||||
);
|
||||
const members = await inactiveMembers(guild_id, req.user_id, days, roles as string[]);
|
||||
|
||||
await Promise.all(
|
||||
members.map((x) => Member.removeFromGuild(x.id, guild_id)),
|
||||
);
|
||||
await Promise.all(members.map((x) => Member.removeFromGuild(x.id, guild_id)));
|
||||
|
||||
res.send({ purged: members.length });
|
||||
},
|
||||
|
||||
@@ -43,28 +43,20 @@ router.get(
|
||||
limits_user_maxBio: general.limits.user.maxBio,
|
||||
limits_guild_maxEmojis: general.limits.guild.maxEmojis,
|
||||
limits_guild_maxRoles: general.limits.guild.maxRoles,
|
||||
limits_message_maxCharacters:
|
||||
general.limits.message.maxCharacters,
|
||||
limits_message_maxAttachmentSize:
|
||||
general.limits.message.maxAttachmentSize,
|
||||
limits_message_maxEmbedDownloadSize:
|
||||
general.limits.message.maxEmbedDownloadSize,
|
||||
limits_message_maxCharacters: general.limits.message.maxCharacters,
|
||||
limits_message_maxAttachmentSize: general.limits.message.maxAttachmentSize,
|
||||
limits_message_maxEmbedDownloadSize: general.limits.message.maxEmbedDownloadSize,
|
||||
limits_channel_maxWebhooks: general.limits.channel.maxWebhooks,
|
||||
register_dateOfBirth_requiredc:
|
||||
general.register.dateOfBirth.required,
|
||||
register_dateOfBirth_requiredc: general.register.dateOfBirth.required,
|
||||
register_password_required: general.register.password.required,
|
||||
register_disabled: general.register.disabled,
|
||||
register_requireInvite: general.register.requireInvite,
|
||||
register_allowNewRegistration:
|
||||
general.register.allowNewRegistration,
|
||||
register_allowMultipleAccounts:
|
||||
general.register.allowMultipleAccounts,
|
||||
register_allowNewRegistration: general.register.allowNewRegistration,
|
||||
register_allowMultipleAccounts: general.register.allowMultipleAccounts,
|
||||
guild_autoJoin_canLeave: general.guild.autoJoin.canLeave,
|
||||
guild_autoJoin_guilds_x: general.guild.autoJoin.guilds,
|
||||
register_email_required: general.register.email.required,
|
||||
can_recover_account:
|
||||
general.email.provider != null &&
|
||||
general.general.frontPage != null,
|
||||
can_recover_account: general.email.provider != null && general.general.frontPage != null,
|
||||
};
|
||||
}
|
||||
res.send(outputtedConfig);
|
||||
|
||||
@@ -17,14 +17,7 @@
|
||||
*/
|
||||
|
||||
import { route } from "@spacebar/api";
|
||||
import {
|
||||
Config,
|
||||
getRights,
|
||||
Guild,
|
||||
Member,
|
||||
Message,
|
||||
User,
|
||||
} from "@spacebar/util";
|
||||
import { Config, getRights, Guild, Member, Message, User } from "@spacebar/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
const router = Router({ mergeParams: true });
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
import { route } from "@spacebar/api";
|
||||
import { Channel, DmChannelDTO, Recipient } from "@spacebar/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { DmChannelCreateSchema } from "@spacebar/schemas"
|
||||
import { DmChannelCreateSchema } from "@spacebar/schemas";
|
||||
|
||||
const router: Router = Router({ mergeParams: true });
|
||||
|
||||
@@ -37,13 +37,7 @@ router.get(
|
||||
where: { user_id: req.user_id, closed: false },
|
||||
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]))));
|
||||
},
|
||||
);
|
||||
|
||||
@@ -59,13 +53,7 @@ router.post(
|
||||
}),
|
||||
async (req: Request, res: Response) => {
|
||||
const body = req.body as DmChannelCreateSchema;
|
||||
res.json(
|
||||
await Channel.createDMChannel(
|
||||
body.recipients,
|
||||
req.user_id,
|
||||
body.name,
|
||||
),
|
||||
);
|
||||
res.json(await Channel.createDMChannel(body.recipients, req.user_id, body.name));
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -27,18 +27,7 @@ router.get("/", route({}), async (req: Request, res: Response) => {
|
||||
where: {
|
||||
user_id: req.user_id,
|
||||
},
|
||||
select: [
|
||||
"external_id",
|
||||
"type",
|
||||
"name",
|
||||
"verified",
|
||||
"visibility",
|
||||
"show_activity",
|
||||
"revoked",
|
||||
"token_data",
|
||||
"friend_sync",
|
||||
"integrations",
|
||||
],
|
||||
select: ["external_id", "type", "name", "verified", "visibility", "show_activity", "revoked", "token_data", "friend_sync", "integrations"],
|
||||
});
|
||||
|
||||
res.json(connections.map((x) => new ConnectedAccountDTO(x, true)));
|
||||
|
||||
@@ -17,15 +17,7 @@
|
||||
*/
|
||||
|
||||
import { route } from "@spacebar/api";
|
||||
import {
|
||||
Config,
|
||||
emitEvent,
|
||||
FieldErrors,
|
||||
generateToken,
|
||||
handleFile,
|
||||
User,
|
||||
UserUpdateEvent,
|
||||
} from "@spacebar/util";
|
||||
import { Config, emitEvent, FieldErrors, generateToken, handleFile, User, UserUpdateEvent } from "@spacebar/util";
|
||||
import bcrypt from "bcrypt";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { PrivateUserProjection, UserModifySchema } from "@spacebar/schemas";
|
||||
@@ -78,23 +70,12 @@ router.patch(
|
||||
// Populated on password change
|
||||
let newToken: string | undefined;
|
||||
|
||||
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.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 || "",
|
||||
);
|
||||
const same_password = await bcrypt.compare(body.password, user.data.hash || "");
|
||||
if (!same_password) {
|
||||
throw FieldErrors({
|
||||
password: {
|
||||
@@ -151,10 +132,7 @@ router.patch(
|
||||
}
|
||||
|
||||
const { maxUsername } = Config.get().limits.user;
|
||||
if (
|
||||
check_username.length > maxUsername ||
|
||||
check_username.length < 2
|
||||
) {
|
||||
if (check_username.length > maxUsername || check_username.length < 2) {
|
||||
throw FieldErrors({
|
||||
username: {
|
||||
code: "BASE_TYPE_BAD_LENGTH",
|
||||
|
||||
@@ -17,14 +17,9 @@
|
||||
*/
|
||||
|
||||
import { route } from "@spacebar/api";
|
||||
import {
|
||||
BackupCode,
|
||||
DiscordApiErrors,
|
||||
User,
|
||||
generateMfaBackupCodes,
|
||||
} from "@spacebar/util";
|
||||
import { BackupCode, DiscordApiErrors, User, generateMfaBackupCodes } from "@spacebar/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { CodesVerificationSchema } from "@spacebar/schemas"
|
||||
import { CodesVerificationSchema } from "@spacebar/schemas";
|
||||
|
||||
const router = Router({ mergeParams: true });
|
||||
|
||||
@@ -52,15 +47,11 @@ router.post(
|
||||
// Once that's done, this route can verify `key`
|
||||
|
||||
// const user = await User.findOneOrFail({ where: { id: req.user_id } });
|
||||
if ((await User.count({ where: { id: req.user_id } })) === 0)
|
||||
throw DiscordApiErrors.UNKNOWN_USER;
|
||||
if ((await User.count({ where: { id: req.user_id } })) === 0) throw DiscordApiErrors.UNKNOWN_USER;
|
||||
|
||||
let codes: BackupCode[];
|
||||
if (regenerate) {
|
||||
await BackupCode.update(
|
||||
{ user: { id: req.user_id } },
|
||||
{ expired: true },
|
||||
);
|
||||
await BackupCode.update({ user: { id: req.user_id } }, { expired: true });
|
||||
|
||||
codes = generateMfaBackupCodes(req.user_id);
|
||||
await Promise.all(codes.map((x) => x.save()));
|
||||
|
||||
@@ -17,15 +17,10 @@
|
||||
*/
|
||||
|
||||
import { route } from "@spacebar/api";
|
||||
import {
|
||||
BackupCode,
|
||||
FieldErrors,
|
||||
generateMfaBackupCodes,
|
||||
User,
|
||||
} from "@spacebar/util";
|
||||
import { BackupCode, FieldErrors, generateMfaBackupCodes, User } from "@spacebar/util";
|
||||
import bcrypt from "bcrypt";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { MfaCodesSchema } from "@spacebar/schemas"
|
||||
import { MfaCodesSchema } from "@spacebar/schemas";
|
||||
|
||||
const router = Router({ mergeParams: true });
|
||||
|
||||
@@ -36,8 +31,7 @@ router.post(
|
||||
route({
|
||||
requestBody: "MfaCodesSchema",
|
||||
deprecated: true,
|
||||
description:
|
||||
"This route is replaced with users/@me/mfa/codes-verification in newer clients",
|
||||
description: "This route is replaced with users/@me/mfa/codes-verification in newer clients",
|
||||
responses: {
|
||||
200: {
|
||||
body: "APIBackupCodeArray",
|
||||
@@ -69,10 +63,7 @@ router.post(
|
||||
|
||||
let codes: BackupCode[];
|
||||
if (regenerate) {
|
||||
await BackupCode.update(
|
||||
{ user: { id: req.user_id } },
|
||||
{ expired: true },
|
||||
);
|
||||
await BackupCode.update({ user: { id: req.user_id } }, { expired: true });
|
||||
|
||||
codes = generateMfaBackupCodes(req.user_id);
|
||||
await Promise.all(codes.map((x) => x.save()));
|
||||
|
||||
@@ -17,15 +17,11 @@
|
||||
*/
|
||||
|
||||
import { route } from "@spacebar/api";
|
||||
import {
|
||||
BackupCode,
|
||||
User,
|
||||
generateToken,
|
||||
} from "@spacebar/util";
|
||||
import { BackupCode, User, generateToken } from "@spacebar/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { verifyToken } from "node-2fa";
|
||||
import { TotpDisableSchema } from "@spacebar/schemas"
|
||||
import { TotpDisableSchema } from "@spacebar/schemas";
|
||||
|
||||
const router = Router({ mergeParams: true });
|
||||
|
||||
@@ -53,11 +49,7 @@ router.post(
|
||||
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,
|
||||
);
|
||||
if (!ret || ret.delta != 0) throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
|
||||
}
|
||||
|
||||
await User.update(
|
||||
|
||||
@@ -17,16 +17,12 @@
|
||||
*/
|
||||
|
||||
import { route } from "@spacebar/api";
|
||||
import {
|
||||
User,
|
||||
generateMfaBackupCodes,
|
||||
generateToken,
|
||||
} from "@spacebar/util";
|
||||
import { User, generateMfaBackupCodes, generateToken } from "@spacebar/util";
|
||||
import bcrypt from "bcrypt";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { verifyToken } from "node-2fa";
|
||||
import { TotpEnableSchema } from "@spacebar/schemas"
|
||||
import { TotpEnableSchema } from "@spacebar/schemas";
|
||||
|
||||
const router = Router({ mergeParams: true });
|
||||
|
||||
@@ -61,21 +57,15 @@ router.post(
|
||||
}
|
||||
}
|
||||
|
||||
if (!body.secret)
|
||||
throw new HTTPError(req.t("auth:login.INVALID_TOTP_SECRET"), 60005);
|
||||
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 (!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);
|
||||
if (verifyToken(body.secret, body.code)?.delta != 0) throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
|
||||
|
||||
const 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 },
|
||||
);
|
||||
await User.update({ id: req.user_id }, { mfa_enabled: true, totp_secret: body.secret });
|
||||
|
||||
res.send({
|
||||
token: await generateToken(user.id),
|
||||
|
||||
@@ -17,31 +17,19 @@
|
||||
*/
|
||||
|
||||
import { route } from "@spacebar/api";
|
||||
import {
|
||||
DiscordApiErrors,
|
||||
FieldErrors,
|
||||
generateWebAuthnTicket,
|
||||
SecurityKey,
|
||||
User,
|
||||
verifyWebAuthnToken,
|
||||
WebAuthn,
|
||||
} from "@spacebar/util";
|
||||
import { DiscordApiErrors, FieldErrors, generateWebAuthnTicket, SecurityKey, User, verifyWebAuthnToken, WebAuthn } from "@spacebar/util";
|
||||
import bcrypt from "bcrypt";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { ExpectedAttestationResult } from "fido2-lib";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { CreateWebAuthnCredentialSchema, GenerateWebAuthnCredentialsSchema, WebAuthnPostSchema } from "@spacebar/schemas"
|
||||
import { CreateWebAuthnCredentialSchema, GenerateWebAuthnCredentialsSchema, WebAuthnPostSchema } from "@spacebar/schemas";
|
||||
const router = Router({ mergeParams: true });
|
||||
|
||||
const isGenerateSchema = (
|
||||
body: WebAuthnPostSchema,
|
||||
): body is GenerateWebAuthnCredentialsSchema => {
|
||||
const isGenerateSchema = (body: WebAuthnPostSchema): body is GenerateWebAuthnCredentialsSchema => {
|
||||
return "password" in body;
|
||||
};
|
||||
|
||||
const isCreateSchema = (
|
||||
body: WebAuthnPostSchema,
|
||||
): body is CreateWebAuthnCredentialSchema => {
|
||||
const isCreateSchema = (body: WebAuthnPostSchema): body is CreateWebAuthnCredentialSchema => {
|
||||
return "credential" in body;
|
||||
};
|
||||
|
||||
@@ -92,24 +80,13 @@ router.post(
|
||||
where: {
|
||||
id: req.user_id,
|
||||
},
|
||||
select: [
|
||||
"data",
|
||||
"id",
|
||||
"disabled",
|
||||
"deleted",
|
||||
"totp_secret",
|
||||
"mfa_enabled",
|
||||
"username",
|
||||
],
|
||||
select: ["data", "id", "disabled", "deleted", "totp_secret", "mfa_enabled", "username"],
|
||||
relations: ["settings"],
|
||||
});
|
||||
|
||||
if (isGenerateSchema(req.body)) {
|
||||
const { password } = req.body;
|
||||
const same_password = await bcrypt.compare(
|
||||
password,
|
||||
user.data.hash || "",
|
||||
);
|
||||
const same_password = await bcrypt.compare(password, user.data.hash || "");
|
||||
if (!same_password) {
|
||||
throw FieldErrors({
|
||||
password: {
|
||||
@@ -119,14 +96,11 @@ router.post(
|
||||
});
|
||||
}
|
||||
|
||||
const registrationOptions =
|
||||
await WebAuthn.fido2.attestationOptions();
|
||||
const registrationOptions = await WebAuthn.fido2.attestationOptions();
|
||||
const challenge = JSON.stringify({
|
||||
publicKey: {
|
||||
...registrationOptions,
|
||||
challenge: Buffer.from(
|
||||
registrationOptions.challenge,
|
||||
).toString("base64"),
|
||||
challenge: Buffer.from(registrationOptions.challenge).toString("base64"),
|
||||
user: {
|
||||
id: user.id,
|
||||
name: user.username,
|
||||
@@ -149,35 +123,20 @@ router.post(
|
||||
|
||||
const clientAttestationResponse = JSON.parse(credential);
|
||||
|
||||
if (!clientAttestationResponse.rawId)
|
||||
throw new HTTPError("Missing rawId", 400);
|
||||
if (!clientAttestationResponse.rawId) throw new HTTPError("Missing rawId", 400);
|
||||
|
||||
const rawIdBuffer = Buffer.from(
|
||||
clientAttestationResponse.rawId,
|
||||
"base64",
|
||||
);
|
||||
const rawIdBuffer = Buffer.from(clientAttestationResponse.rawId, "base64");
|
||||
clientAttestationResponse.rawId = toArrayBuffer(rawIdBuffer);
|
||||
|
||||
const attestationExpectations: ExpectedAttestationResult =
|
||||
JSON.parse(
|
||||
Buffer.from(
|
||||
clientAttestationResponse.response.clientDataJSON,
|
||||
"base64",
|
||||
).toString(),
|
||||
);
|
||||
const attestationExpectations: ExpectedAttestationResult = JSON.parse(Buffer.from(clientAttestationResponse.response.clientDataJSON, "base64").toString());
|
||||
|
||||
const regResult = await WebAuthn.fido2.attestationResult(
|
||||
clientAttestationResponse,
|
||||
{
|
||||
...attestationExpectations,
|
||||
factor: "second",
|
||||
},
|
||||
);
|
||||
const regResult = await WebAuthn.fido2.attestationResult(clientAttestationResponse, {
|
||||
...attestationExpectations,
|
||||
factor: "second",
|
||||
});
|
||||
|
||||
const authnrData = regResult.authnrData;
|
||||
const keyId = Buffer.from(authnrData.get("credId")).toString(
|
||||
"base64",
|
||||
);
|
||||
const keyId = Buffer.from(authnrData.get("credId")).toString("base64");
|
||||
const counter = authnrData.get("counter");
|
||||
const publicKey = authnrData.get("credentialPublicKeyPem");
|
||||
|
||||
@@ -189,10 +148,7 @@ router.post(
|
||||
key_id: keyId,
|
||||
});
|
||||
|
||||
await Promise.all([
|
||||
securityKey.save(),
|
||||
User.update({ id: req.user_id }, { webauthn_enabled: true }),
|
||||
]);
|
||||
await Promise.all([securityKey.save(), User.update({ id: req.user_id }, { webauthn_enabled: true })]);
|
||||
|
||||
return res.json({
|
||||
name,
|
||||
|
||||
@@ -17,25 +17,14 @@
|
||||
*/
|
||||
|
||||
import { route } from "@spacebar/api";
|
||||
import {
|
||||
Config,
|
||||
DiscordApiErrors,
|
||||
Relationship,
|
||||
RelationshipAddEvent,
|
||||
RelationshipRemoveEvent,
|
||||
User,
|
||||
emitEvent,
|
||||
} from "@spacebar/util";
|
||||
import { Config, DiscordApiErrors, Relationship, RelationshipAddEvent, RelationshipRemoveEvent, User, emitEvent } from "@spacebar/util";
|
||||
import { Request, Response, Router } from "express";
|
||||
import { HTTPError } from "lambert-server";
|
||||
import { PublicUserProjection, RelationshipType } from "@spacebar/schemas";
|
||||
|
||||
const router = Router({ mergeParams: true });
|
||||
|
||||
const userProjection: (keyof User)[] = [
|
||||
"relationships",
|
||||
...PublicUserProjection,
|
||||
];
|
||||
const userProjection: (keyof User)[] = ["relationships", ...PublicUserProjection];
|
||||
|
||||
router.get(
|
||||
"/",
|
||||
@@ -111,10 +100,7 @@ router.post(
|
||||
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
|
||||
discriminator: String(req.body.discriminator).padStart(4, "0"), //Discord send the discriminator as integer, we need to add leading zeroes
|
||||
username: req.body.username,
|
||||
},
|
||||
}),
|
||||
@@ -138,8 +124,7 @@ router.delete(
|
||||
}),
|
||||
async (req: Request, res: Response) => {
|
||||
const { user_id } = req.params;
|
||||
if (user_id === req.user_id)
|
||||
throw new HTTPError("You can't remove yourself as a friend");
|
||||
if (user_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 },
|
||||
@@ -153,12 +138,9 @@ router.delete(
|
||||
});
|
||||
|
||||
const relationship = user.relationships.find((x) => x.to_id === user_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
|
||||
@@ -198,15 +180,9 @@ router.delete(
|
||||
|
||||
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 },
|
||||
@@ -215,15 +191,12 @@ async function updateRelationship(
|
||||
});
|
||||
|
||||
let 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 {
|
||||
@@ -255,8 +228,7 @@ async function updateRelationship(
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
let incoming_relationship = Relationship.create({
|
||||
nickname: undefined,
|
||||
@@ -272,24 +244,17 @@ async function updateRelationship(
|
||||
});
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -18,14 +18,10 @@
|
||||
|
||||
import { route } from "@spacebar/api";
|
||||
import { Request, Response, Router } from "express";
|
||||
import {
|
||||
emitEvent,
|
||||
OrmUtils,
|
||||
UserSettingsProtos,
|
||||
} from "@spacebar/util";
|
||||
import { emitEvent, OrmUtils, UserSettingsProtos } from "@spacebar/util";
|
||||
import { PreloadedUserSettings } from "discord-protos";
|
||||
import { JsonValue } from "@protobuf-ts/runtime";
|
||||
import { SettingsProtoJsonResponse, SettingsProtoResponse, SettingsProtoUpdateJsonSchema, SettingsProtoUpdateSchema } from "@spacebar/schemas"
|
||||
import { SettingsProtoJsonResponse, SettingsProtoResponse, SettingsProtoUpdateJsonSchema, SettingsProtoUpdateSchema } from "@spacebar/schemas";
|
||||
|
||||
const router: Router = Router({ mergeParams: true });
|
||||
|
||||
@@ -41,8 +37,7 @@ router.get(
|
||||
query: {
|
||||
atomic: {
|
||||
type: "boolean",
|
||||
description:
|
||||
"Whether to try to apply the settings update atomically (default false)",
|
||||
description: "Whether to try to apply the settings update atomically (default false)",
|
||||
},
|
||||
},
|
||||
}),
|
||||
@@ -50,9 +45,7 @@ router.get(
|
||||
const userSettings = await UserSettingsProtos.getOrDefault(req.user_id);
|
||||
|
||||
res.json({
|
||||
settings: PreloadedUserSettings.toBase64(
|
||||
userSettings.userSettings!,
|
||||
),
|
||||
settings: PreloadedUserSettings.toBase64(userSettings.userSettings!),
|
||||
} as SettingsProtoResponse);
|
||||
},
|
||||
);
|
||||
@@ -68,17 +61,11 @@ router.patch(
|
||||
},
|
||||
}),
|
||||
async (req: Request, res: Response) => {
|
||||
const { settings, required_data_version } =
|
||||
req.body as SettingsProtoUpdateSchema;
|
||||
const { settings, required_data_version } = req.body as SettingsProtoUpdateSchema;
|
||||
const { atomic } = req.query;
|
||||
const updatedSettings = PreloadedUserSettings.fromBase64(settings);
|
||||
|
||||
const resultObj = await patchUserSettings(
|
||||
req.user_id,
|
||||
updatedSettings,
|
||||
required_data_version,
|
||||
atomic == "true",
|
||||
);
|
||||
const resultObj = await patchUserSettings(req.user_id, updatedSettings, required_data_version, atomic == "true");
|
||||
|
||||
res.json({
|
||||
settings: PreloadedUserSettings.toBase64(resultObj.settings),
|
||||
@@ -119,23 +106,16 @@ router.patch(
|
||||
query: {
|
||||
atomic: {
|
||||
type: "boolean",
|
||||
description:
|
||||
"Whether to try to apply the settings update atomically (default false)",
|
||||
description: "Whether to try to apply the settings update atomically (default false)",
|
||||
},
|
||||
},
|
||||
}),
|
||||
async (req: Request, res: Response) => {
|
||||
const { settings, required_data_version } =
|
||||
req.body as SettingsProtoUpdateJsonSchema;
|
||||
const { settings, required_data_version } = req.body as SettingsProtoUpdateJsonSchema;
|
||||
const { atomic } = req.query;
|
||||
const updatedSettings = PreloadedUserSettings.fromJson(settings);
|
||||
|
||||
const resultObj = await patchUserSettings(
|
||||
req.user_id,
|
||||
updatedSettings,
|
||||
required_data_version,
|
||||
atomic == "true",
|
||||
);
|
||||
const resultObj = await patchUserSettings(req.user_id, updatedSettings, required_data_version, atomic == "true");
|
||||
|
||||
res.json({
|
||||
settings: PreloadedUserSettings.toJson(resultObj.settings),
|
||||
@@ -146,20 +126,11 @@ router.patch(
|
||||
|
||||
//#endregion
|
||||
|
||||
async function patchUserSettings(
|
||||
userId: string,
|
||||
updatedSettings: PreloadedUserSettings,
|
||||
required_data_version: number | undefined,
|
||||
atomic: boolean = false,
|
||||
) {
|
||||
async function patchUserSettings(userId: string, updatedSettings: PreloadedUserSettings, required_data_version: number | undefined, atomic: boolean = false) {
|
||||
const userSettings = await UserSettingsProtos.getOrDefault(userId);
|
||||
let settings = userSettings.userSettings!;
|
||||
|
||||
if (
|
||||
required_data_version &&
|
||||
settings.versions &&
|
||||
settings.versions.dataVersion > required_data_version
|
||||
) {
|
||||
if (required_data_version && settings.versions && settings.versions.dataVersion > required_data_version) {
|
||||
return {
|
||||
settings: settings,
|
||||
out_of_date: true,
|
||||
@@ -167,24 +138,15 @@ async function patchUserSettings(
|
||||
}
|
||||
|
||||
if ((process.env.LOG_PROTO_UPDATES || process.env.LOG_PROTO_SETTINGS_UPDATES) && process.env.LOG_PROTO_SETTINGS_UPDATES !== "false")
|
||||
console.log(
|
||||
`Updating user settings for user ${userId} with atomic=${atomic}:`,
|
||||
updatedSettings,
|
||||
);
|
||||
console.log(`Updating user settings for user ${userId} with atomic=${atomic}:`, updatedSettings);
|
||||
|
||||
if (!atomic) {
|
||||
settings = PreloadedUserSettings.fromJson(
|
||||
Object.assign(
|
||||
PreloadedUserSettings.toJson(settings) as object,
|
||||
PreloadedUserSettings.toJson(updatedSettings) as object,
|
||||
) as JsonValue,
|
||||
Object.assign(PreloadedUserSettings.toJson(settings) as object, PreloadedUserSettings.toJson(updatedSettings) as object) as JsonValue,
|
||||
);
|
||||
} else {
|
||||
settings = PreloadedUserSettings.fromJson(
|
||||
OrmUtils.mergeDeep(
|
||||
PreloadedUserSettings.toJson(settings) as object,
|
||||
PreloadedUserSettings.toJson(updatedSettings) as object,
|
||||
) as JsonValue,
|
||||
OrmUtils.mergeDeep(PreloadedUserSettings.toJson(settings) as object, PreloadedUserSettings.toJson(updatedSettings) as object) as JsonValue,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -202,14 +164,14 @@ async function patchUserSettings(
|
||||
data: {
|
||||
settings: {
|
||||
proto: PreloadedUserSettings.toBase64(settings),
|
||||
type: 1
|
||||
type: 1,
|
||||
},
|
||||
json_settings: {
|
||||
proto: PreloadedUserSettings.toJson(settings),
|
||||
type: "user_settings"
|
||||
type: "user_settings",
|
||||
},
|
||||
partial: false, // Unsure how this should behave
|
||||
}
|
||||
},
|
||||
});
|
||||
// This should also send a USER_SETTINGS_UPDATE event, but that isn't sent
|
||||
// when using the USER_SETTINGS_PROTOS capability, so we ignore it for now.
|
||||
|
||||
@@ -18,14 +18,10 @@
|
||||
|
||||
import { route } from "@spacebar/api";
|
||||
import { Request, Response, Router } from "express";
|
||||
import {
|
||||
emitEvent,
|
||||
OrmUtils,
|
||||
UserSettingsProtos,
|
||||
} from "@spacebar/util";
|
||||
import { emitEvent, OrmUtils, UserSettingsProtos } from "@spacebar/util";
|
||||
import { FrecencyUserSettings } from "discord-protos";
|
||||
import { JsonValue } from "@protobuf-ts/runtime";
|
||||
import { SettingsProtoJsonResponse, SettingsProtoResponse, SettingsProtoUpdateJsonSchema, SettingsProtoUpdateSchema } from "@spacebar/schemas"
|
||||
import { SettingsProtoJsonResponse, SettingsProtoResponse, SettingsProtoUpdateJsonSchema, SettingsProtoUpdateSchema } from "@spacebar/schemas";
|
||||
|
||||
const router: Router = Router({ mergeParams: true });
|
||||
|
||||
@@ -41,8 +37,7 @@ router.get(
|
||||
query: {
|
||||
atomic: {
|
||||
type: "boolean",
|
||||
description:
|
||||
"Whether to try to apply the settings update atomically (default false)",
|
||||
description: "Whether to try to apply the settings update atomically (default false)",
|
||||
},
|
||||
},
|
||||
}),
|
||||
@@ -50,9 +45,7 @@ router.get(
|
||||
const userSettings = await UserSettingsProtos.getOrDefault(req.user_id);
|
||||
|
||||
res.json({
|
||||
settings: FrecencyUserSettings.toBase64(
|
||||
userSettings.frecencySettings!,
|
||||
),
|
||||
settings: FrecencyUserSettings.toBase64(userSettings.frecencySettings!),
|
||||
} as SettingsProtoResponse);
|
||||
},
|
||||
);
|
||||
@@ -68,17 +61,11 @@ router.patch(
|
||||
},
|
||||
}),
|
||||
async (req: Request, res: Response) => {
|
||||
const { settings, required_data_version } =
|
||||
req.body as SettingsProtoUpdateSchema;
|
||||
const { settings, required_data_version } = req.body as SettingsProtoUpdateSchema;
|
||||
const { atomic } = req.query;
|
||||
const updatedSettings = FrecencyUserSettings.fromBase64(settings);
|
||||
|
||||
const resultObj = await patchUserSettings(
|
||||
req.user_id,
|
||||
updatedSettings,
|
||||
required_data_version,
|
||||
atomic == "true",
|
||||
);
|
||||
const resultObj = await patchUserSettings(req.user_id, updatedSettings, required_data_version, atomic == "true");
|
||||
|
||||
res.json({
|
||||
settings: FrecencyUserSettings.toBase64(resultObj.settings),
|
||||
@@ -102,9 +89,7 @@ router.get(
|
||||
const userSettings = await UserSettingsProtos.getOrDefault(req.user_id);
|
||||
|
||||
res.json({
|
||||
settings: FrecencyUserSettings.toJson(
|
||||
userSettings.frecencySettings!,
|
||||
),
|
||||
settings: FrecencyUserSettings.toJson(userSettings.frecencySettings!),
|
||||
} as SettingsProtoJsonResponse);
|
||||
},
|
||||
);
|
||||
@@ -121,23 +106,16 @@ router.patch(
|
||||
query: {
|
||||
atomic: {
|
||||
type: "boolean",
|
||||
description:
|
||||
"Whether to try to apply the settings update atomically (default false)",
|
||||
description: "Whether to try to apply the settings update atomically (default false)",
|
||||
},
|
||||
},
|
||||
}),
|
||||
async (req: Request, res: Response) => {
|
||||
const { settings, required_data_version } =
|
||||
req.body as SettingsProtoUpdateJsonSchema;
|
||||
const { settings, required_data_version } = req.body as SettingsProtoUpdateJsonSchema;
|
||||
const { atomic } = req.query;
|
||||
const updatedSettings = FrecencyUserSettings.fromJson(settings);
|
||||
|
||||
const resultObj = await patchUserSettings(
|
||||
req.user_id,
|
||||
updatedSettings,
|
||||
required_data_version,
|
||||
atomic == "true",
|
||||
);
|
||||
const resultObj = await patchUserSettings(req.user_id, updatedSettings, required_data_version, atomic == "true");
|
||||
|
||||
res.json({
|
||||
settings: FrecencyUserSettings.toJson(resultObj.settings),
|
||||
@@ -148,20 +126,11 @@ router.patch(
|
||||
|
||||
//#endregion
|
||||
|
||||
async function patchUserSettings(
|
||||
userId: string,
|
||||
updatedSettings: FrecencyUserSettings,
|
||||
required_data_version: number | undefined,
|
||||
atomic: boolean = false,
|
||||
) {
|
||||
async function patchUserSettings(userId: string, updatedSettings: FrecencyUserSettings, required_data_version: number | undefined, atomic: boolean = false) {
|
||||
const userSettings = await UserSettingsProtos.getOrDefault(userId);
|
||||
let settings = userSettings.frecencySettings!;
|
||||
|
||||
if (
|
||||
required_data_version &&
|
||||
settings.versions &&
|
||||
settings.versions.dataVersion > required_data_version
|
||||
) {
|
||||
if (required_data_version && settings.versions && settings.versions.dataVersion > required_data_version) {
|
||||
return {
|
||||
settings: settings,
|
||||
out_of_date: true,
|
||||
@@ -169,24 +138,15 @@ async function patchUserSettings(
|
||||
}
|
||||
|
||||
if ((process.env.LOG_PROTO_UPDATES || process.env.LOG_PROTO_FRECENCY_UPDATES) && process.env.LOG_PROTO_FRECENCY_UPDATES !== "false")
|
||||
console.log(
|
||||
`Updating frecency settings for user ${userId} with atomic=${atomic}:`,
|
||||
updatedSettings,
|
||||
);
|
||||
console.log(`Updating frecency settings for user ${userId} with atomic=${atomic}:`, updatedSettings);
|
||||
|
||||
if (!atomic) {
|
||||
settings = FrecencyUserSettings.fromJson(
|
||||
Object.assign(
|
||||
FrecencyUserSettings.toJson(settings) as object,
|
||||
FrecencyUserSettings.toJson(updatedSettings) as object,
|
||||
) as JsonValue,
|
||||
Object.assign(FrecencyUserSettings.toJson(settings) as object, FrecencyUserSettings.toJson(updatedSettings) as object) as JsonValue,
|
||||
);
|
||||
} else {
|
||||
settings = FrecencyUserSettings.fromJson(
|
||||
OrmUtils.mergeDeep(
|
||||
FrecencyUserSettings.toJson(settings) as object,
|
||||
FrecencyUserSettings.toJson(updatedSettings) as object,
|
||||
) as JsonValue,
|
||||
OrmUtils.mergeDeep(FrecencyUserSettings.toJson(settings) as object, FrecencyUserSettings.toJson(updatedSettings) as object) as JsonValue,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -204,14 +164,14 @@ async function patchUserSettings(
|
||||
data: {
|
||||
settings: {
|
||||
proto: FrecencyUserSettings.toBase64(settings),
|
||||
type: 2
|
||||
type: 2,
|
||||
},
|
||||
json_settings: {
|
||||
proto: FrecencyUserSettings.toJson(settings),
|
||||
type: "frecency_settings"
|
||||
type: "frecency_settings",
|
||||
},
|
||||
partial: false, // Unsure how this should behave
|
||||
}
|
||||
},
|
||||
});
|
||||
// This should also send a USER_SETTINGS_UPDATE event, but that isn't sent
|
||||
// when using the USER_SETTINGS_PROTOS capability, so we ignore it for now.
|
||||
|
||||
Reference in New Issue
Block a user