summary refs log tree commit diff
path: root/src/routes
diff options
context:
space:
mode:
Diffstat (limited to 'src/routes')
-rw-r--r--src/routes/auth/login.ts20
-rw-r--r--src/routes/auth/register.ts5
-rw-r--r--src/routes/channels/#channel_id/messages/index.ts20
-rw-r--r--src/routes/guilds/#guild_id/bans.ts2
-rw-r--r--src/routes/guilds/#guild_id/channels.ts7
-rw-r--r--src/routes/guilds/#guild_id/delete.ts18
-rw-r--r--src/routes/guilds/#guild_id/index.ts7
-rw-r--r--src/routes/guilds/#guild_id/vanity-url.ts33
-rw-r--r--src/routes/ping.ts9
-rw-r--r--src/routes/users/#id/profile.ts1
-rw-r--r--src/routes/users/@me/disable.ts16
-rw-r--r--src/routes/users/@me/index.ts17
-rw-r--r--src/routes/users/@me/profile.ts1
-rw-r--r--src/routes/users/@me/relationships.ts60
14 files changed, 156 insertions, 60 deletions
diff --git a/src/routes/auth/login.ts b/src/routes/auth/login.ts

index af00a46d..c92ddccc 100644 --- a/src/routes/auth/login.ts +++ b/src/routes/auth/login.ts
@@ -9,7 +9,8 @@ import RateLimit from "../../middlewares/RateLimit"; const router: Router = Router(); export default router; -// TODO: check if user is deleted/restricted +// TODO: check if user is deleted --> prohibit login + router.post( "/", RateLimit({ count: 5, window: 60, onylIp: true }), @@ -22,7 +23,7 @@ router.post( $gift_code_sku_id: String }), async (req: Request, res: Response) => { - const { login, password, captcha_key } = req.body; + const { login, password, captcha_key, undelete } = req.body; const email = adjustEmail(login); const query: any[] = [{ phone: login }]; if (email) query.push({ email }); @@ -62,6 +63,13 @@ router.post( throw FieldErrors({ login: { message: req.t("auth:login.INVALID_LOGIN"), code: "INVALID_LOGIN" } }); }); + if (user.disabled && undelete) { + // undelete refers to un'disable' here + await UserModel.updateOne({ id: req.user_id }, { disabled: false }).exec(); + } else if (user.disabled) { + return res.status(400).json({ message: req.t("auth:login.ACCOUNT_DISABLED"), code: 20013 }); + } + // the salt is saved in the password refer to bcrypt docs const same_password = await bcrypt.compare(password, user.user_data.hash || ""); if (!same_password) { @@ -100,14 +108,14 @@ export async function generateToken(id: string) { /** * POST /auth/login * @argument { login: "email@gmail.com", password: "cleartextpassword", undelete: false, captcha_key: null, login_source: null, gift_code_sku_id: null, } - + * MFA required: * @returns {"token": null, "mfa": true, "sms": true, "ticket": "SOME TICKET JWT TOKEN"} - + * Captcha required: * @returns {"captcha_key": ["captcha-required"], "captcha_sitekey": null, "captcha_service": "recaptcha"} - + * Sucess: * @returns {"token": "USERTOKEN", "user_settings": {"locale": "en", "theme": "dark"}} - + */ diff --git a/src/routes/auth/register.ts b/src/routes/auth/register.ts
index 279103bc..eb5cd97d 100644 --- a/src/routes/auth/register.ts +++ b/src/routes/auth/register.ts
@@ -197,12 +197,13 @@ router.post( discriminator, avatar: null, accent_color: null, + banner: null, bot: false, system: false, desktop: false, mobile: false, - premium: false, - premium_type: 0, + premium: true, + premium_type: 2, phone: null, bio: "", mfa_enabled: false, diff --git a/src/routes/channels/#channel_id/messages/index.ts b/src/routes/channels/#channel_id/messages/index.ts
index 4e42d546..59494c7e 100644 --- a/src/routes/channels/#channel_id/messages/index.ts +++ b/src/routes/channels/#channel_id/messages/index.ts
@@ -30,7 +30,13 @@ export function isTextChannel(type: ChannelType): boolean { // get messages router.get("/", async (req: Request, res: Response) => { const channel_id = req.params.channel_id; - const channel = await ChannelModel.findOne({ id: channel_id }, { guild_id: true, type: true, permission_overwrites: true }).exec(); + const channel = await ChannelModel.findOne( + { id: channel_id }, + { guild_id: true, type: true, permission_overwrites: true, recipient_ids: true, owner_id: true } + ) + .lean() // lean is needed, because we don't want to populate .recipients that also auto deletes .recipient_ids + .exec(); + if (!channel) throw new HTTPError("Channel not found", 404); isTextChannel(channel.type); @@ -46,6 +52,7 @@ router.get("/", async (req: Request, res: Response) => { if (!limit) limit = 50; var halfLimit = Math.floor(limit / 2); + // @ts-ignore const permissions = await getPermission(req.user_id, channel.guild_id, channel_id, { channel }); permissions.hasThrow("VIEW_CHANNEL"); if (!permissions.has("READ_MESSAGE_HISTORY")) return res.json([]); @@ -126,7 +133,16 @@ router.post("/", messageUpload.single("file"), async (req: Request, res: Respons const embeds = []; if (body.embed) embeds.push(body.embed); - const data = await sendMessage({ ...body, type: 0, pinned: false, author_id: req.user_id, embeds, channel_id, attachments, edited_timestamp: null }); + const data = await sendMessage({ + ...body, + type: 0, + pinned: false, + author_id: req.user_id, + embeds, + channel_id, + attachments, + edited_timestamp: null + }); return res.send(data); }); diff --git a/src/routes/guilds/#guild_id/bans.ts b/src/routes/guilds/#guild_id/bans.ts
index 4d9bad37..d9752f61 100644 --- a/src/routes/guilds/#guild_id/bans.ts +++ b/src/routes/guilds/#guild_id/bans.ts
@@ -16,7 +16,7 @@ router.get("/", async (req: Request, res: Response) => { const guild = await GuildModel.exists({ id: guild_id }); if (!guild) throw new HTTPError("Guild not found", 404); - var bans = await BanModel.find({ guild_id: guild_id }, { user: true, reason: true }).exec(); + var bans = await BanModel.find({ guild_id: guild_id }, { user_id: true, reason: true }).exec(); return res.json(toObject(bans)); }); diff --git a/src/routes/guilds/#guild_id/channels.ts b/src/routes/guilds/#guild_id/channels.ts
index 90b4473d..15cc7394 100644 --- a/src/routes/guilds/#guild_id/channels.ts +++ b/src/routes/guilds/#guild_id/channels.ts
@@ -23,15 +23,18 @@ router.get("/", async (req: Request, res: Response) => { res.json(toObject(channels)); }); +// TODO: check if channel type is permitted +// TODO: check if parent_id exists router.post("/", check(ChannelModifySchema), async (req: Request, res: Response) => { const { guild_id } = req.params; const body = req.body as ChannelModifySchema; const channel = await createChannel({ ...body, guild_id }, req.user_id); - res.json(channel); + res.json(toObject(channel)); }); +// TODO: check if parent_id exists router.patch("/", check(ChannelModifySchema), async (req: Request, res: Response) => { const { guild_id } = req.params; const body = req.body as ChannelModifySchema; @@ -41,7 +44,7 @@ router.patch("/", check(ChannelModifySchema), async (req: Request, res: Response await emitEvent({ event: "CHANNEL_UPDATE", data: channel } as ChannelUpdateEvent); - res.json(channel); + res.json(toObject(channel)); }); export default router; diff --git a/src/routes/guilds/#guild_id/delete.ts b/src/routes/guilds/#guild_id/delete.ts
index c363db25..6cca289e 100644 --- a/src/routes/guilds/#guild_id/delete.ts +++ b/src/routes/guilds/#guild_id/delete.ts
@@ -4,6 +4,7 @@ import { GuildDeleteEvent, GuildModel, InviteModel, + MemberModel, MessageModel, RoleModel, UserModel @@ -30,13 +31,16 @@ router.post("/", async (req: Request, res: Response) => { guild_id: guild_id } as GuildDeleteEvent); - await GuildModel.deleteOne({ id: guild_id }).exec(); - await UserModel.updateMany({ guilds: guild_id }, { $pull: { guilds: guild_id } }).exec(); - await RoleModel.deleteMany({ guild_id }).exec(); - await ChannelModel.deleteMany({ guild_id }).exec(); - await EmojiModel.deleteMany({ guild_id }).exec(); - await InviteModel.deleteMany({ guild_id }).exec(); - await MessageModel.deleteMany({ guild_id }).exec(); + await Promise.all([ + GuildModel.deleteOne({ id: guild_id }).exec(), + UserModel.updateMany({ guilds: guild_id }, { $pull: { guilds: guild_id } }).exec(), + RoleModel.deleteMany({ guild_id }).exec(), + ChannelModel.deleteMany({ guild_id }).exec(), + EmojiModel.deleteMany({ guild_id }).exec(), + InviteModel.deleteMany({ guild_id }).exec(), + MessageModel.deleteMany({ guild_id }).exec(), + MemberModel.deleteMany({ guild_id }).exec() + ]); return res.sendStatus(204); }); diff --git a/src/routes/guilds/#guild_id/index.ts b/src/routes/guilds/#guild_id/index.ts
index 3af49106..dc4ddb39 100644 --- a/src/routes/guilds/#guild_id/index.ts +++ b/src/routes/guilds/#guild_id/index.ts
@@ -17,6 +17,7 @@ import { HTTPError } from "lambert-server"; import { GuildUpdateSchema } from "../../../schema/Guild"; import { emitEvent } from "../../../util/Event"; import { check } from "../../../util/instanceOf"; +import { handleFile } from "../../../util/cdn"; import "missing-native-js-functions"; const router = Router(); @@ -42,6 +43,10 @@ router.patch("/", check(GuildUpdateSchema), async (req: Request, res: Response) const perms = await getPermission(req.user_id, guild_id); perms.hasThrow("MANAGE_GUILD"); + if (body.icon) body.icon = await handleFile(`/icons/${guild_id}`, body.icon); + if (body.banner) body.banner = await handleFile(`/banners/${guild_id}`, body.banner); + if (body.splash) body.splash = await handleFile(`/splashes/${guild_id}`, body.splash); + const guild = await GuildModel.findOneAndUpdate({ id: guild_id }, body) .populate({ path: "joined_at", match: { id: req.user_id } }) .exec(); @@ -50,7 +55,7 @@ router.patch("/", check(GuildUpdateSchema), async (req: Request, res: Response) emitEvent({ event: "GUILD_UPDATE", data: data, guild_id } as GuildUpdateEvent); - return res.send(data); + return res.json(data); }); export default router; diff --git a/src/routes/guilds/#guild_id/vanity-url.ts b/src/routes/guilds/#guild_id/vanity-url.ts
index 30c98d19..323b2647 100644 --- a/src/routes/guilds/#guild_id/vanity-url.ts +++ b/src/routes/guilds/#guild_id/vanity-url.ts
@@ -1,16 +1,45 @@ -import { GuildModel } from "@fosscord/server-util"; +import { getPermission, GuildModel, InviteModel, trimSpecial } from "@fosscord/server-util"; import { Router, Request, Response } from "express"; import { HTTPError } from "lambert-server"; +import { check, Length } from "../../../util/instanceOf"; +import { isMember } from "../../../util/Member"; const router = Router(); +const InviteRegex = /\W/g; + router.get("/", async (req: Request, res: Response) => { const { guild_id } = req.params; + await isMember(req.user_id, guild_id); const guild = await GuildModel.findOne({ id: guild_id }).exec(); if (!guild.vanity_url) throw new HTTPError("This guild has no vanity url", 204); - return res.json({ vanity_url: guild.vanity_url }); + return res.json({ code: guild.vanity_url.code }); +}); + +// TODO: check if guild is elgible for vanity url +router.patch("/", check({ code: new Length(String, 0, 20) }), async (req: Request, res: Response) => { + const { guild_id } = req.params; + var code = req.body.code.replace(InviteRegex); + if (!code) code = null; + + const permission = await getPermission(req.user_id, guild_id); + permission.hasThrow("MANAGE_GUILD"); + + const alreadyExists = await Promise.all([ + GuildModel.findOne({ "vanity_url.code": code }) + .exec() + .catch(() => null), + InviteModel.findOne({ code: code }) + .exec() + .catch(() => null) + ]); + if (alreadyExists.some((x) => x)) throw new HTTPError("Vanity url already exists", 400); + + await GuildModel.updateOne({ id: guild_id }, { "vanity_url.code": code }).exec(); + + return res.json({ code: code }); }); export default router; diff --git a/src/routes/ping.ts b/src/routes/ping.ts new file mode 100644
index 00000000..38daf81e --- /dev/null +++ b/src/routes/ping.ts
@@ -0,0 +1,9 @@ +import { Router, Response, Request } from "express"; + +const router = Router(); + +router.get("/", (req: Request, res: Response) => { + res.send("pong"); +}); + +export default router; diff --git a/src/routes/users/#id/profile.ts b/src/routes/users/#id/profile.ts
index b86b0b90..4b4b9439 100644 --- a/src/routes/users/#id/profile.ts +++ b/src/routes/users/#id/profile.ts
@@ -17,6 +17,7 @@ router.get("/", async (req: Request, res: Response) => { public_flags: user.public_flags, avatar: user.avatar, accent_color: user.accent_color, + banner: user.banner, bio: req.user_bot ? null : user.bio, bot: user.bot, } diff --git a/src/routes/users/@me/disable.ts b/src/routes/users/@me/disable.ts
index b16ef783..0e5b734e 100644 --- a/src/routes/users/@me/disable.ts +++ b/src/routes/users/@me/disable.ts
@@ -1,10 +1,20 @@ +import { UserModel } from "@fosscord/server-util"; import { Router, Response, Request } from "express"; +import bcrypt from "bcrypt"; const router = Router(); -router.post("/", (req: Request, res: Response) => { - // TODO: - res.sendStatus(204); +router.post("/", async (req: Request, res: Response) => { + const user = await UserModel.findOne({ id: req.user_id }).exec(); //User object + + let correctpass = await bcrypt.compare(req.body.password, user!.user_data.hash); //Not sure if user typed right password :/ + if (correctpass) { + await UserModel.updateOne({ id: req.user_id }, { disabled: true }).exec(); + + res.sendStatus(204); + } else { + res.status(400).json({ message: "Password does not match", code: 50018 }); + } }); export default router; diff --git a/src/routes/users/@me/index.ts b/src/routes/users/@me/index.ts
index 68196afe..f6b29958 100644 --- a/src/routes/users/@me/index.ts +++ b/src/routes/users/@me/index.ts
@@ -1,10 +1,9 @@ import { Router, Request, Response } from "express"; import { UserModel, toObject, PublicUserProjection } from "@fosscord/server-util"; -import { HTTPError } from "lambert-server"; import { getPublicUser } from "../../../util/User"; import { UserModifySchema } from "../../../schema/User"; import { check } from "../../../util/instanceOf"; -import { uploadFile } from "../../../util/cdn"; +import { handleFile } from "../../../util/cdn"; const router: Router = Router(); @@ -15,18 +14,8 @@ router.get("/", async (req: Request, res: Response) => { router.patch("/", check(UserModifySchema), async (req: Request, res: Response) => { const body = req.body as UserModifySchema; - if (body.avatar) { - try { - const mimetype = body.avatar.split(":")[1].split(";")[0]; - const buffer = Buffer.from(body.avatar.split(",")[1], "base64"); - - // @ts-ignore - const { id } = await uploadFile(`/avatars/${req.user_id}`, { buffer, mimetype, originalname: "avatar" }); - body.avatar = id; - } catch (error) { - throw new HTTPError("Invalid avatar"); - } - } + 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); const user = await UserModel.findOneAndUpdate({ id: req.user_id }, body, { projection: PublicUserProjection }).exec(); // TODO: dispatch user update event diff --git a/src/routes/users/@me/profile.ts b/src/routes/users/@me/profile.ts
index 0d295d05..b67d1964 100644 --- a/src/routes/users/@me/profile.ts +++ b/src/routes/users/@me/profile.ts
@@ -17,6 +17,7 @@ router.get("/", async (req: Request, res: Response) => { public_flags: user.public_flags, avatar: user.avatar, accent_color: user.accent_color, + banner: user.banner, bio: user.bio, bot: user.bot, } diff --git a/src/routes/users/@me/relationships.ts b/src/routes/users/@me/relationships.ts
index b874ec9a..a8f03143 100644 --- a/src/routes/users/@me/relationships.ts +++ b/src/routes/users/@me/relationships.ts
@@ -4,43 +4,50 @@ import { PublicUserProjection, toObject, RelationshipType, - RelationshipRemoveEvent + RelationshipRemoveEvent, + UserDocument } from "@fosscord/server-util"; import { Router, Response, Request } from "express"; -import { check, HTTPError } from "lambert-server"; +import { HTTPError } from "lambert-server"; import { emitEvent } from "../../../util/Event"; +import { check, Length } from "../../../util/instanceOf"; const router = Router(); const userProjection = { "user_data.relationships": true, ...PublicUserProjection }; -router.put("/:id", check({ $type: Number }), async (req: Request, res: Response) => { - const { id } = req.params; +router.get("/", async (req: Request, res: Response) => { + const user = await UserModel.findOne({ id: req.user_id }, { user_data: { relationships: true } }) + .populate({ path: "user_data.relationships.id", model: UserModel }) + .exec(); + + return res.json(toObject(user.user_data.relationships)); +}); + +async function addRelationship(req: Request, res: Response, friend: UserDocument, type: RelationshipType) { + const id = friend.id; if (id === req.user_id) throw new HTTPError("You can't add yourself as a friend"); - const body = req.body as { type?: number }; const user = await UserModel.findOne({ id: req.user_id }, userProjection).exec(); - if (!user) throw new HTTPError("Invalid token", 400); + const newUserRelationships = [...user.user_data.relationships]; + const newFriendRelationships = [...friend.user_data.relationships]; - const friend = await UserModel.findOne({ id }, userProjection).exec(); - if (!friend) throw new HTTPError("User not found", 404); + var relationship = newUserRelationships.find((x) => x.id === id); + const friendRequest = newFriendRelationships.find((x) => x.id === req.user_id); - var relationship = user.user_data.relationships.find((x) => x.id === id); - const friendRequest = friend.user_data.relationships.find((x) => x.id === req.user_id); - - if (body.type === RelationshipType.blocked) { + if (type === RelationshipType.blocked) { if (relationship) { if (relationship.type === RelationshipType.blocked) throw new HTTPError("You already blocked the user"); relationship.type = RelationshipType.blocked; } else { relationship = { id, type: RelationshipType.blocked }; - user.user_data.relationships.push(relationship); + newUserRelationships.push(relationship); } if (friendRequest && friendRequest.type !== RelationshipType.blocked) { - friend.user_data.relationships.remove(friendRequest); + newFriendRelationships.remove(friendRequest); await Promise.all([ - friend.save(), + UserModel.updateOne({ id: friend.id }, { "user_data.relationships": newFriendRelationships }).exec(), emitEvent({ event: "RELATIONSHIP_REMOVE", data: friendRequest, @@ -50,7 +57,7 @@ router.put("/:id", check({ $type: Number }), async (req: Request, res: Response) } await Promise.all([ - user.save(), + UserModel.updateOne({ id: req.user_id }, { "user_data.relationships": newUserRelationships }).exec(), emitEvent({ event: "RELATIONSHIP_ADD", data: { @@ -74,17 +81,17 @@ router.put("/:id", check({ $type: Number }), async (req: Request, res: Response) incoming_relationship = friendRequest; incoming_relationship.type = RelationshipType.friends; outgoing_relationship.type = RelationshipType.friends; - } else friend.user_data.relationships.push(incoming_relationship); + } else newFriendRelationships.push(incoming_relationship); 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"); - } else user.user_data.relationships.push(outgoing_relationship); + } else newUserRelationships.push(outgoing_relationship); await Promise.all([ - user.save(), - friend.save(), + UserModel.updateOne({ id: req.user_id }, { "user_data.relationships": newUserRelationships }).exec(), + UserModel.updateOne({ id: friend.id }, { "user_data.relationships": newFriendRelationships }).exec(), emitEvent({ event: "RELATIONSHIP_ADD", data: { @@ -105,6 +112,19 @@ router.put("/:id", check({ $type: Number }), async (req: Request, res: Response) ]); return res.sendStatus(204); +} + +router.put("/:id", check({ $type: new Length(Number, 1, 4) }), async (req: Request, res: Response) => { + return await addRelationship(req, res, await UserModel.findOne({ id: req.params.id }), req.body.type); +}); + +router.post("/", check({ discriminator: String, username: String }), async (req: Request, res: Response) => { + return await addRelationship( + req, + res, + await UserModel.findOne(req.body as { discriminator: string; username: string }).exec(), + req.body.type + ); }); router.delete("/:id", async (req: Request, res: Response) => {