diff options
author | Erkin Alp Güney <erkinalp9035@gmail.com> | 2022-03-05 17:49:23 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-05 17:49:23 +0300 |
commit | f972bfc5287b492556eb05582bc6741e0d59b820 (patch) | |
tree | 63f855ae36294319352c5e826c400046a6c6318c | |
parent | Added email sanitisation to /users/@me PATCH. Could previously have email as ... (diff) | |
parent | document which field is which (diff) | |
download | server-f972bfc5287b492556eb05582bc6741e0d59b820.tar.xz |
Merge branch 'master' into fix/claim_accounts
-rw-r--r-- | api/assets/openapi.json | 7 | ||||
-rw-r--r-- | api/package-lock.json | 20 | ||||
-rw-r--r-- | api/src/routes/guilds/#guild_id/bans.ts | 67 | ||||
-rw-r--r-- | api/src/routes/users/#id/profile.ts | 16 | ||||
-rw-r--r-- | api/src/routes/users/@me/index.ts | 4 | ||||
-rw-r--r-- | bundle/package-lock.json | 22 | ||||
-rw-r--r-- | bundle/package.json | 3 | ||||
-rw-r--r-- | gateway/package-lock.json | 20 | ||||
-rw-r--r-- | gateway/src/opcodes/Identify.ts | 2 | ||||
-rw-r--r-- | util/package-lock.json | 12 | ||||
-rw-r--r-- | util/src/entities/Member.ts | 4 | ||||
-rw-r--r-- | util/src/entities/ReadState.ts | 11 | ||||
-rw-r--r-- | util/src/entities/User.ts | 5 |
13 files changed, 138 insertions, 55 deletions
diff --git a/api/assets/openapi.json b/api/assets/openapi.json index 15e55bf9..1af0600d 100644 --- a/api/assets/openapi.json +++ b/api/assets/openapi.json @@ -2821,6 +2821,10 @@ "type": "string", "format": "date-time" }, + "premium_since": { + "type": "string", + "format": "date-time" + }, "verified": { "type": "boolean" }, @@ -3800,7 +3804,8 @@ "format": "date-time" }, "premium_since": { - "type": "integer" + "type": "string", + "format": "date-time" }, "deaf": { "type": "boolean" diff --git a/api/package-lock.json b/api/package-lock.json index a7c29a79..e3e29800 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -6711,8 +6711,9 @@ } }, "../util/node_modules/url-parse": { - "version": "1.5.3", - "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==", + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "dependencies": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -15124,8 +15125,9 @@ } }, "node_modules/url-parse": { - "version": "1.5.3", - "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==", + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "dependencies": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -21697,8 +21699,9 @@ } }, "url-parse": { - "version": "1.5.3", - "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==", + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "requires": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -26849,8 +26852,9 @@ } }, "url-parse": { - "version": "1.5.3", - "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==", + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "requires": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" diff --git a/api/src/routes/guilds/#guild_id/bans.ts b/api/src/routes/guilds/#guild_id/bans.ts index 1e09a38d..7ccf34d7 100644 --- a/api/src/routes/guilds/#guild_id/bans.ts +++ b/api/src/routes/guilds/#guild_id/bans.ts @@ -1,5 +1,5 @@ import { Request, Response, Router } from "express"; -import { emitEvent, getPermission, GuildBanAddEvent, GuildBanRemoveEvent, Guild, Ban, User, Member } from "@fosscord/util"; +import { DiscordApiErrors, emitEvent, getPermission, GuildBanAddEvent, GuildBanRemoveEvent, Guild, Ban, User, Member } from "@fosscord/util"; import { HTTPError } from "lambert-server"; import { getIpAdress, route } from "@fosscord/api"; @@ -17,6 +17,14 @@ export interface BanRegistrySchema { reason?: string | undefined; }; +export interface BanModeratorSchema { + id: string; + user_id: string; + guild_id: string; + executor_id: string; + reason?: string | undefined; +}; + const router: Router = Router(); /* TODO: Deleting the secrets is just a temporary go-around. Views should be implemented for both safety and better handling. */ @@ -27,11 +35,14 @@ router.get("/", route({ permission: "BAN_MEMBERS" }), async (req: Request, res: let bans = await Ban.find({ guild_id: guild_id }); /* Filter secret from database registry.*/ + + bans.filter(ban => ban.user_id !== ban.executor_id); + // pretend self-bans don't exist to prevent victim chasing bans.forEach((registry: BanRegistrySchema) => { delete registry.ip; }); - + return res.json(bans); }); @@ -41,7 +52,12 @@ router.get("/:user", route({ permission: "BAN_MEMBERS" }), async (req: Request, let ban = await Ban.findOneOrFail({ guild_id: guild_id, user_id: user_id }) as BanRegistrySchema; + if (ban.user_id === ban.executor_id) throw DiscordApiErrors.UNKNOWN_BAN; + // pretend self-bans don't exist to prevent victim chasing + /* Filter secret from registry. */ + + ban = ban as BanModeratorSchema; delete ban.ip @@ -52,10 +68,12 @@ router.put("/:user_id", route({ body: "BanCreateSchema", permission: "BAN_MEMBER const { guild_id } = req.params; const banned_user_id = req.params.user_id; - const banned_user = await User.getPublicUser(banned_user_id); - - if (req.user_id === banned_user_id) throw new HTTPError("You can't ban yourself", 400); + if ( (req.user_id === banned_user_id) && (banned_user_id === req.permission!.cache.guild?.owner_id)) + throw new HTTPError("You are the guild owner, hence can't ban yourself", 403); + if (req.permission!.cache.guild?.owner_id === banned_user_id) throw new HTTPError("You can't ban the owner", 400); + + const banned_user = await User.getPublicUser(banned_user_id); const ban = new Ban({ user_id: banned_user_id, @@ -81,11 +99,48 @@ router.put("/:user_id", route({ body: "BanCreateSchema", permission: "BAN_MEMBER return res.json(ban); }); +router.put("/@me", route({ body: "BanCreateSchema"}), async (req: Request, res: Response) => { + const { guild_id } = req.params; + + const banned_user = await User.getPublicUser(req.params.user_id); + + if (req.permission!.cache.guild?.owner_id === req.params.user_id) + throw new HTTPError("You are the guild owner, hence can't ban yourself", 403); + + const ban = new Ban({ + user_id: req.params.user_id, + guild_id: guild_id, + ip: getIpAdress(req), + executor_id: req.params.user_id, + reason: req.body.reason // || otherwise empty + }); + + await Promise.all([ + Member.removeFromGuild(req.user_id, guild_id), + ban.save(), + emitEvent({ + event: "GUILD_BAN_ADD", + data: { + guild_id: guild_id, + user: banned_user + }, + guild_id: guild_id + } as GuildBanAddEvent) + ]); + + return res.json(ban); +}); + router.delete("/:user_id", route({ permission: "BAN_MEMBERS" }), async (req: Request, res: Response) => { const { guild_id, user_id } = req.params; + let ban = await Ban.findOneOrFail({ guild_id: guild_id, user_id: user_id }); + + if (ban.user_id === ban.executor_id) throw DiscordApiErrors.UNKNOWN_BAN; + // make self-bans irreversible and hide them from view to avoid victim chasing + const banned_user = await User.getPublicUser(user_id); - + await Promise.all([ Ban.delete({ user_id: user_id, diff --git a/api/src/routes/users/#id/profile.ts b/api/src/routes/users/#id/profile.ts index 9481451d..4dbb84cf 100644 --- a/api/src/routes/users/#id/profile.ts +++ b/api/src/routes/users/#id/profile.ts @@ -16,22 +16,30 @@ router.get("/", route({ test: { response: { body: "UserProfileResponse" } } }), const user = await User.getPublicUser(req.params.id, { relations: ["connected_accounts"] }); var mutual_guilds: object[] = []; - + var premium_guild_since; const requested_member = await Member.find( { id: req.params.id, }) const self_member = await Member.find( { id: req.user_id, }) for(const rmem of requested_member) { + if(rmem.premium_since) { + if(premium_guild_since){ + if(premium_guild_since > rmem.premium_since) { + premium_guild_since = rmem.premium_since; + } + } else { + premium_guild_since = rmem.premium_since; + } + } for(const smem of self_member) { if (smem.guild_id === rmem.guild_id) { mutual_guilds.push({id: rmem.guild_id, nick: rmem.nick}) } } } - res.json({ connected_accounts: user.connected_accounts, - premium_guild_since: null, // TODO - premium_since: null, // TODO + premium_guild_since: premium_guild_since, // TODO + premium_since: user.premium_since, // TODO mutual_guilds: mutual_guilds, // TODO {id: "", nick: null} when ?with_mutual_guilds=true user: { username: user.username, diff --git a/api/src/routes/users/@me/index.ts b/api/src/routes/users/@me/index.ts index 93d2cb01..bf62e7fc 100644 --- a/api/src/routes/users/@me/index.ts +++ b/api/src/routes/users/@me/index.ts @@ -65,8 +65,8 @@ router.patch("/", route({ body: "UserModifySchema" }), async (req: Request, res: } var check_username = body?.username?.replace(/\s/g, ''); - //claiming an account does not provide username so check if username in body before throw - if (!check_username && body.username) { + + if(!check_username && !body?.avatar && !body?.banner) { throw FieldErrors({ username: { code: "BASE_TYPE_REQUIRED", message: req.t("common:field.BASE_TYPE_REQUIRED") } }); diff --git a/bundle/package-lock.json b/bundle/package-lock.json index 485f3bf4..a9129c24 100644 --- a/bundle/package-lock.json +++ b/bundle/package-lock.json @@ -7610,11 +7610,6 @@ "thenify-all": "^1.0.0" } }, - "node_modules/nan": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", - "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==" - }, "node_modules/nanocolors": { "version": "0.2.12", "integrity": "sha512-SFNdALvzW+rVlzqexid6epYdt8H9Zol7xDoQarioEFcFN0JHo4CYNztAxmtfgGTVRCmFlEOqqhBpoFGKqSAMug==" @@ -9470,7 +9465,6 @@ "integrity": "sha512-roEOz41hxui2Q7uYnWsjMOTry6TcNUNmp8audCx18gF10P2NknwdpF+E+HKvz/F2NvPKGGBF4NGc+ZPQ+AABwg==", "hasInstallScript": true, "dependencies": { - "nan": "^2.12.1", "node-pre-gyp": "^0.11.0" } }, @@ -10528,8 +10522,9 @@ } }, "node_modules/url-parse": { - "version": "1.5.3", - "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==", + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "dependencies": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -16638,11 +16633,6 @@ "thenify-all": "^1.0.0" } }, - "nan": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", - "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==" - }, "nanocolors": { "version": "0.2.12", "integrity": "sha512-SFNdALvzW+rVlzqexid6epYdt8H9Zol7xDoQarioEFcFN0JHo4CYNztAxmtfgGTVRCmFlEOqqhBpoFGKqSAMug==" @@ -18040,7 +18030,6 @@ "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-4.2.0.tgz", "integrity": "sha512-roEOz41hxui2Q7uYnWsjMOTry6TcNUNmp8audCx18gF10P2NknwdpF+E+HKvz/F2NvPKGGBF4NGc+ZPQ+AABwg==", "requires": { - "nan": "^2.12.1", "node-pre-gyp": "^0.11.0" } }, @@ -18732,8 +18721,9 @@ } }, "url-parse": { - "version": "1.5.3", - "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==", + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "requires": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" diff --git a/bundle/package.json b/bundle/package.json index 8915665d..0b3fc817 100644 --- a/bundle/package.json +++ b/bundle/package.json @@ -105,6 +105,7 @@ "typeorm": "^0.2.37", "typescript": "^4.1.2", "typescript-json-schema": "^0.50.1", - "ws": "^7.4.2" + "ws": "^7.4.2", + "nan": "^2.15.0" } } diff --git a/gateway/package-lock.json b/gateway/package-lock.json index 878799d2..9b3841af 100644 --- a/gateway/package-lock.json +++ b/gateway/package-lock.json @@ -6679,8 +6679,9 @@ } }, "../util/node_modules/url-parse": { - "version": "1.5.3", - "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==", + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "dependencies": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -9896,8 +9897,9 @@ } }, "node_modules/url-parse": { - "version": "1.5.3", - "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==", + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "dependencies": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -15260,8 +15262,9 @@ } }, "url-parse": { - "version": "1.5.3", - "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==", + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "requires": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -17624,8 +17627,9 @@ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, "url-parse": { - "version": "1.5.3", - "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==", + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "requires": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" diff --git a/gateway/src/opcodes/Identify.ts b/gateway/src/opcodes/Identify.ts index f39ac808..904aa963 100644 --- a/gateway/src/opcodes/Identify.ts +++ b/gateway/src/opcodes/Identify.ts @@ -173,6 +173,7 @@ export async function onIdentify(this: WebSocket, data: Payload) { avatar: related_user.avatar, bot: related_user.bot, bio: related_user.bio, + premium_since: user.premium_since }; users.push(public_related_user); } @@ -225,6 +226,7 @@ export async function onIdentify(this: WebSocket, data: Payload) { accent_color: user.accent_color || 0, banner: user.banner, bio: user.bio, + premium_since: user.premium_since }; const d: ReadyEventData = { diff --git a/util/package-lock.json b/util/package-lock.json index c5e96742..82e90b36 100644 --- a/util/package-lock.json +++ b/util/package-lock.json @@ -7623,9 +7623,9 @@ } }, "node_modules/url-parse": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz", - "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==", + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "dependencies": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -14029,9 +14029,9 @@ } }, "url-parse": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz", - "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==", + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "requires": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" diff --git a/util/src/entities/Member.ts b/util/src/entities/Member.ts index 0f7be2a7..3c5f9db0 100644 --- a/util/src/entities/Member.ts +++ b/util/src/entities/Member.ts @@ -86,7 +86,7 @@ export class Member extends BaseClassWithoutId { joined_at: Date; @Column({ nullable: true }) - premium_since?: number; + premium_since?: Date; @Column() deaf: boolean; @@ -245,7 +245,7 @@ export class Member extends BaseClassWithoutId { nick: undefined, roles: [guild_id], // @everyone role joined_at: new Date(), - premium_since: undefined, + premium_since: new Date(), deaf: false, mute: false, pending: false, diff --git a/util/src/entities/ReadState.ts b/util/src/entities/ReadState.ts index ebef89be..e6d73105 100644 --- a/util/src/entities/ReadState.ts +++ b/util/src/entities/ReadState.ts @@ -31,8 +31,17 @@ export class ReadState extends BaseClass { }) user: User; + // fully read marker @Column({ nullable: true }) - last_message_id: string; + last_message_id: string; + + // public read receipt + @Column({ nullable: true }) + public_ack: string; + + // notification cursor / private read receipt + @Column({ nullable: true }) + notifications_cursor: string; @Column({ nullable: true }) last_pin_timestamp?: Date; diff --git a/util/src/entities/User.ts b/util/src/entities/User.ts index f157ac39..1d18c838 100644 --- a/util/src/entities/User.ts +++ b/util/src/entities/User.ts @@ -16,6 +16,7 @@ export enum PublicUserEnum { banner, bio, bot, + premium_since, } export type PublicUserKeys = keyof typeof PublicUserEnum; @@ -110,6 +111,9 @@ export class User extends BaseClass { @Column() created_at: Date; // registration date + @Column({ nullable: true }) + premium_since: Date; // premium date + @Column({ select: false }) verified: boolean; // if the user is offically verified @@ -246,6 +250,7 @@ export class User extends BaseClass { id: Snowflake.generate(), bot: false, system: false, + premium_since: new Date(), desktop: false, mobile: false, premium: true, |