diff options
Diffstat (limited to 'src/api')
80 files changed, 360 insertions, 312 deletions
diff --git a/src/api/Server.ts b/src/api/Server.ts index 4660e6b1..0177be40 100644 --- a/src/api/Server.ts +++ b/src/api/Server.ts @@ -22,7 +22,7 @@ import { Authentication, CORS } from "./middlewares/"; import { Config, initDatabase, initEvent, Sentry } from "@fosscord/util"; import { ErrorHandler } from "./middlewares/ErrorHandler"; import { BodyParser } from "./middlewares/BodyParser"; -import { Router, Request, Response, NextFunction } from "express"; +import { Router, Request, Response } from "express"; import path from "path"; import { initRateLimits } from "./middlewares/RateLimit"; import TestClient from "./middlewares/TestClient"; @@ -32,12 +32,12 @@ import { initInstance } from "./util/handlers/Instance"; import { registerRoutes } from "@fosscord/util"; import { red } from "picocolors"; -export interface FosscordServerOptions extends ServerOptions {} +export type FosscordServerOptions = ServerOptions; declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace namespace Express { interface Request { - // @ts-ignore server: FosscordServer; } } @@ -47,6 +47,7 @@ export class FosscordServer extends Server { public declare options: FosscordServerOptions; constructor(opts?: Partial<FosscordServerOptions>) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore super({ ...opts, errorHandler: false, jsonBody: false }); } @@ -58,12 +59,12 @@ export class FosscordServer extends Server { await initInstance(); await Sentry.init(this.app); - let logRequests = process.env["LOG_REQUESTS"] != undefined; + const logRequests = process.env["LOG_REQUESTS"] != undefined; if (logRequests) { this.app.use( morgan("combined", { skip: (req, res) => { - var skip = !( + let skip = !( process.env["LOG_REQUESTS"]?.includes( res.statusCode.toString(), ) ?? false @@ -80,7 +81,9 @@ export class FosscordServer extends Server { this.app.use(BodyParser({ inflate: true, limit: "10mb" })); const app = this.app; - const api = Router(); // @ts-ignore + const api = Router(); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore this.app = api; api.use(Authentication); @@ -95,7 +98,7 @@ export class FosscordServer extends Server { // 404 is not an error in express, so this should not be an error middleware // this is a fine place to put the 404 handler because its after we register the routes // and since its not an error middleware, our error handler below still works. - api.use("*", (req: Request, res: Response, next: NextFunction) => { + api.use("*", (req: Request, res: Response) => { res.status(404).json({ message: "404 endpoint not found", code: 0, diff --git a/src/api/middlewares/Authentication.ts b/src/api/middlewares/Authentication.ts index 208c54d6..8e0dcc7c 100644 --- a/src/api/middlewares/Authentication.ts +++ b/src/api/middlewares/Authentication.ts @@ -54,11 +54,12 @@ export const API_PREFIX = /^\/api(\/v\d+)?/; export const API_PREFIX_TRAILING_SLASH = /^\/api(\/v\d+)?\//; declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace namespace Express { interface Request { user_id: string; user_bot: boolean; - token: string; + token: { id: string; iat: number }; rights: Rights; } } @@ -87,7 +88,7 @@ export async function Authentication( try { const { jwtSecret } = Config.get().security; - const { decoded, user }: any = await checkToken( + const { decoded, user } = await checkToken( req.headers.authorization, jwtSecret, ); @@ -97,7 +98,8 @@ export async function Authentication( req.user_bot = user.bot; req.rights = new Rights(Number(user.rights)); return next(); - } catch (error: any) { - return next(new HTTPError(error?.toString(), 400)); + } catch (error) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return next(new HTTPError(error!.toString(), 400)); } } diff --git a/src/api/middlewares/RateLimit.ts b/src/api/middlewares/RateLimit.ts index ae102c94..1a28f356 100644 --- a/src/api/middlewares/RateLimit.ts +++ b/src/api/middlewares/RateLimit.ts @@ -42,7 +42,7 @@ type RateLimit = { expires_at: Date; }; -let Cache = new Map<string, RateLimit>(); +const Cache = new Map<string, RateLimit>(); const EventRateLimit = "RATELIMIT"; export default function rateLimit(opts: { @@ -57,12 +57,8 @@ export default function rateLimit(opts: { error?: boolean; success?: boolean; onlyIp?: boolean; -}): any { - return async ( - req: Request, - res: Response, - next: NextFunction, - ): Promise<any> => { +}) { + return async (req: Request, res: Response, next: NextFunction) => { // exempt user? if so, immediately short circuit if (req.user_id) { const rights = await getRights(req.user_id); @@ -85,7 +81,7 @@ export default function rateLimit(opts: { ) max_hits = opts.MODIFY; - let offender = Cache.get(executor_id + bucket_id); + const offender = Cache.get(executor_id + bucket_id); if (offender) { let reset = offender.expires_at.getTime(); diff --git a/src/api/routes/applications/#id/bot/index.ts b/src/api/routes/applications/#id/bot/index.ts index 7d0a637e..9bc3c571 100644 --- a/src/api/routes/applications/#id/bot/index.ts +++ b/src/api/routes/applications/#id/bot/index.ts @@ -64,8 +64,8 @@ router.post("/", route({}), async (req: Request, res: Response) => { }); router.post("/reset", route({}), async (req: Request, res: Response) => { - let bot = await User.findOneOrFail({ where: { id: req.params.id } }); - let owner = await User.findOneOrFail({ where: { id: req.user_id } }); + const bot = await User.findOneOrFail({ where: { id: req.params.id } }); + const owner = await User.findOneOrFail({ where: { id: req.user_id } }); if (owner.id != req.user_id) throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION; @@ -80,7 +80,7 @@ router.post("/reset", route({}), async (req: Request, res: Response) => { await bot.save(); - let token = await generateToken(bot.id); + const token = await generateToken(bot.id); res.json({ token }).status(200); }); diff --git a/src/api/routes/applications/#id/index.ts b/src/api/routes/applications/#id/index.ts index 2b283880..59e90168 100644 --- a/src/api/routes/applications/#id/index.ts +++ b/src/api/routes/applications/#id/index.ts @@ -20,10 +20,8 @@ import { Request, Response, Router } from "express"; import { route } from "@fosscord/api"; import { Application, - OrmUtils, DiscordApiErrors, ApplicationModifySchema, - User, } from "@fosscord/util"; import { verifyToken } from "node-2fa"; import { HTTPError } from "lambert-server"; diff --git a/src/api/routes/applications/#id/skus.ts b/src/api/routes/applications/#id/skus.ts index 23e6eb6b..5a3a479f 100644 --- a/src/api/routes/applications/#id/skus.ts +++ b/src/api/routes/applications/#id/skus.ts @@ -18,7 +18,6 @@ import { Request, Response, Router } from "express"; import { route } from "@fosscord/api"; -import { Application, OrmUtils, Team, trimSpecial, User } from "@fosscord/util"; const router: Router = Router(); diff --git a/src/api/routes/applications/index.ts b/src/api/routes/applications/index.ts index 6ea24870..859ee145 100644 --- a/src/api/routes/applications/index.ts +++ b/src/api/routes/applications/index.ts @@ -28,7 +28,7 @@ import { const router: Router = Router(); router.get("/", route({}), async (req: Request, res: Response) => { - let results = await Application.find({ + const results = await Application.find({ where: { owner: { id: req.user_id } }, relations: ["owner", "bot"], }); diff --git a/src/api/routes/auth/generate-registration-tokens.ts b/src/api/routes/auth/generate-registration-tokens.ts index 64e3b0a6..c79d2a59 100644 --- a/src/api/routes/auth/generate-registration-tokens.ts +++ b/src/api/routes/auth/generate-registration-tokens.ts @@ -32,7 +32,7 @@ router.get( ? parseInt(req.query.length as string) : 255; - let tokens: ValidRegistrationToken[] = []; + const tokens: ValidRegistrationToken[] = []; for (let i = 0; i < count; i++) { const token = ValidRegistrationToken.create({ diff --git a/src/api/routes/auth/login.ts b/src/api/routes/auth/login.ts index 5f1b7a14..4d367546 100644 --- a/src/api/routes/auth/login.ts +++ b/src/api/routes/auth/login.ts @@ -74,7 +74,7 @@ router.post( "totp_secret", "mfa_enabled", ], - }).catch((e) => { + }).catch(() => { throw FieldErrors({ login: { message: req.t("auth:login.INVALID_LOGIN"), diff --git a/src/api/routes/auth/mfa/totp.ts b/src/api/routes/auth/mfa/totp.ts index 42485535..65cdd397 100644 --- a/src/api/routes/auth/mfa/totp.ts +++ b/src/api/routes/auth/mfa/totp.ts @@ -27,8 +27,8 @@ router.post( "/", route({ body: "TotpSchema" }), async (req: Request, res: Response) => { - const { code, ticket, gift_code_sku_id, login_source } = - req.body as TotpSchema; + // const { code, ticket, gift_code_sku_id, login_source } = + const { code, ticket } = req.body as TotpSchema; const user = await User.findOneOrFail({ where: { @@ -47,7 +47,7 @@ router.post( }); if (!backup) { - const ret = verifyToken(user.totp_secret!, code); + const ret = verifyToken(user.totp_secret || "", code); if (!ret || ret.delta != 0) throw new HTTPError( req.t("auth:login.INVALID_TOTP_CODE"), diff --git a/src/api/routes/auth/register.ts b/src/api/routes/auth/register.ts index b98f17c5..0bf8efae 100644 --- a/src/api/routes/auth/register.ts +++ b/src/api/routes/auth/register.ts @@ -36,7 +36,7 @@ import { } from "@fosscord/api"; import bcrypt from "bcrypt"; import { HTTPError } from "lambert-server"; -import { LessThan, MoreThan } from "typeorm"; +import { MoreThan } from "typeorm"; const router: Router = Router(); @@ -53,12 +53,12 @@ router.post( let regTokenUsed = false; if (req.get("Referrer") && req.get("Referrer")?.includes("token=")) { // eg theyre on https://staging.fosscord.com/register?token=whatever - const token = req.get("Referrer")!.split("token=")[1].split("&")[0]; + const token = req.get("Referrer")?.split("token=")[1].split("&")[0]; if (token) { - const regToken = await ValidRegistrationToken.findOne({ + const regToken = await ValidRegistrationToken.findOneOrFail({ where: { token, expires_at: MoreThan(new Date()) }, }); - await ValidRegistrationToken.delete({ token }); + await regToken.remove(); regTokenUsed = true; console.log( `[REGISTER] Registration token ${token} used for registration!`, @@ -71,7 +71,7 @@ router.post( } // email will be slightly modified version of the user supplied email -> e.g. protection against GMail Trick - let email = adjustEmail(body.email); + const email = adjustEmail(body.email); // check if registration is allowed if (!regTokenUsed && !register.allowNewRegistration) { diff --git a/src/api/routes/channels/#channel_id/followers.ts b/src/api/routes/channels/#channel_id/followers.ts index 0ff784df..a9d5d4ee 100644 --- a/src/api/routes/channels/#channel_id/followers.ts +++ b/src/api/routes/channels/#channel_id/followers.ts @@ -16,7 +16,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -import { Router, Response, Request } from "express"; +import { Router } from "express"; const router: Router = Router(); // TODO: diff --git a/src/api/routes/channels/#channel_id/index.ts b/src/api/routes/channels/#channel_id/index.ts index 5bcd3a84..4a2023d2 100644 --- a/src/api/routes/channels/#channel_id/index.ts +++ b/src/api/routes/channels/#channel_id/index.ts @@ -92,7 +92,7 @@ router.patch( "/", route({ body: "ChannelModifySchema", permission: "MANAGE_CHANNELS" }), async (req: Request, res: Response) => { - var payload = req.body as ChannelModifySchema; + const payload = req.body as ChannelModifySchema; const { channel_id } = req.params; if (payload.icon) payload.icon = await handleFile( diff --git a/src/api/routes/channels/#channel_id/invites.ts b/src/api/routes/channels/#channel_id/invites.ts index b9105bea..49620aaf 100644 --- a/src/api/routes/channels/#channel_id/invites.ts +++ b/src/api/routes/channels/#channel_id/invites.ts @@ -86,7 +86,6 @@ router.get( "/", route({ permission: "MANAGE_CHANNELS" }), async (req: Request, res: Response) => { - const { user_id } = req; const { channel_id } = req.params; const channel = await Channel.findOneOrFail({ where: { id: channel_id }, diff --git a/src/api/routes/channels/#channel_id/messages/#message_id/index.ts b/src/api/routes/channels/#channel_id/messages/#message_id/index.ts index 3d9a69be..9ea33340 100644 --- a/src/api/routes/channels/#channel_id/messages/#message_id/index.ts +++ b/src/api/routes/channels/#channel_id/messages/#message_id/index.ts @@ -30,7 +30,6 @@ import { Snowflake, uploadFile, MessageCreateSchema, - DiscordApiErrors, } from "@fosscord/util"; import { Router, Response, Request } from "express"; import multer from "multer"; @@ -59,7 +58,7 @@ router.patch( }), async (req: Request, res: Response) => { const { message_id, channel_id } = req.params; - var body = req.body as MessageCreateSchema; + let body = req.body as MessageCreateSchema; const message = await Message.findOneOrFail({ where: { id: message_id, channel_id }, @@ -85,6 +84,7 @@ router.patch( const new_message = await handleMessage({ ...message, // TODO: should message_reference be overridable? + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore message_reference: message.message_reference, ...body, @@ -127,7 +127,7 @@ router.put( }), async (req: Request, res: Response) => { const { channel_id, message_id } = req.params; - var body = req.body as MessageCreateSchema; + const body = req.body as MessageCreateSchema; const attachments: Attachment[] = []; const rights = await getRights(req.user_id); @@ -171,7 +171,7 @@ router.put( const embeds = body.embeds || []; if (body.embed) embeds.push(body.embed); - let message = await handleMessage({ + const message = await handleMessage({ ...body, type: 0, pinned: false, @@ -197,7 +197,10 @@ router.put( channel.save(), ]); - postHandleMessage(message).catch((e) => {}); // no await as it shouldnt block the message send function and silently catch error + // no await as it shouldnt block the message send function and silently catch error + postHandleMessage(message).catch((e) => + console.error("[Message] post-message handler failed", e), + ); return res.json(message); }, diff --git a/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts b/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts index bf6d43e5..c3598b24 100644 --- a/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts +++ b/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts @@ -165,13 +165,13 @@ router.put( x.emoji.name === emoji.name, ); - if (!already_added) req.permission!.hasThrow("ADD_REACTIONS"); + if (!already_added) req.permission?.hasThrow("ADD_REACTIONS"); if (emoji.id) { const external_emoji = await Emoji.findOneOrFail({ where: { id: emoji.id }, }); - if (!already_added) req.permission!.hasThrow("USE_EXTERNAL_EMOJIS"); + if (!already_added) req.permission?.hasThrow("USE_EXTERNAL_EMOJIS"); emoji.animated = external_emoji.animated; emoji.name = external_emoji.name; } @@ -214,7 +214,8 @@ router.delete( "/:emoji/:user_id", route({}), async (req: Request, res: Response) => { - var { message_id, channel_id, user_id } = req.params; + let { user_id } = req.params; + const { message_id, channel_id } = req.params; const emoji = getEmoji(req.params.emoji); diff --git a/src/api/routes/channels/#channel_id/messages/bulk-delete.ts b/src/api/routes/channels/#channel_id/messages/bulk-delete.ts index ad5d24c8..ee039d3e 100644 --- a/src/api/routes/channels/#channel_id/messages/bulk-delete.ts +++ b/src/api/routes/channels/#channel_id/messages/bulk-delete.ts @@ -50,7 +50,7 @@ router.post( const rights = await getRights(req.user_id); rights.hasThrow("SELF_DELETE_MESSAGES"); - let superuser = rights.has("MANAGE_MESSAGES"); + const superuser = rights.has("MANAGE_MESSAGES"); const permission = await getPermission( req.user_id, channel?.guild_id, diff --git a/src/api/routes/channels/#channel_id/messages/index.ts b/src/api/routes/channels/#channel_id/messages/index.ts index 6e4f06a2..76f6a0dc 100644 --- a/src/api/routes/channels/#channel_id/messages/index.ts +++ b/src/api/routes/channels/#channel_id/messages/index.ts @@ -31,23 +31,16 @@ import { Snowflake, uploadFile, Member, - Role, MessageCreateSchema, ReadState, - DiscordApiErrors, - getRights, Rights, + Reaction, + User, } from "@fosscord/util"; import { HTTPError } from "lambert-server"; -import { - handleMessage, - postHandleMessage, - route, - getIpAdress, -} from "@fosscord/api"; +import { handleMessage, postHandleMessage, route } from "@fosscord/api"; import multer from "multer"; -import { yellow } from "picocolors"; -import { FindManyOptions, LessThan, MoreThan } from "typeorm"; +import { FindManyOptions, FindOperator, LessThan, MoreThan } from "typeorm"; import { URL } from "url"; const router: Router = Router(); @@ -93,7 +86,7 @@ router.get("/", async (req: Request, res: Response) => { if (limit < 1 || limit > 100) throw new HTTPError("limit must be between 1 and 100", 422); - var halfLimit = Math.floor(limit / 2); + const halfLimit = Math.floor(limit / 2); const permissions = await getPermission( req.user_id, @@ -103,7 +96,9 @@ router.get("/", async (req: Request, res: Response) => { permissions.hasThrow("VIEW_CHANNEL"); if (!permissions.has("READ_MESSAGE_HISTORY")) return res.json([]); - var query: FindManyOptions<Message> & { where: { id?: any } } = { + const query: FindManyOptions<Message> & { + where: { id?: FindOperator<string> | FindOperator<string>[] }; + } = { order: { timestamp: "DESC" }, take: limit, where: { channel_id }, @@ -140,23 +135,21 @@ router.get("/", async (req: Request, res: Response) => { const endpoint = Config.get().cdn.endpointPublic; return res.json( - messages.map((x: any) => { - (x.reactions || []).forEach((x: any) => { - // @ts-ignore - if ((x.user_ids || []).includes(req.user_id)) x.me = true; - // @ts-ignore - delete x.user_ids; + messages.map((x: Partial<Message>) => { + (x.reactions || []).forEach((y: Partial<Reaction>) => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + //@ts-ignore + if ((y.user_ids || []).includes(req.user_id)) y.me = true; + delete y.user_ids; }); - // @ts-ignore if (!x.author) - x.author = { + x.author = User.create({ id: "4", discriminator: "0000", username: "Fosscord Ghost", - public_flags: "0", - avatar: null, - }; - x.attachments?.forEach((y: any) => { + public_flags: 0, + }); + x.attachments?.forEach((y: Attachment) => { // dynamically set attachment proxy_url in case the endpoint changed const uri = y.proxy_url.startsWith("http") ? y.proxy_url @@ -168,7 +161,7 @@ router.get("/", async (req: Request, res: Response) => { /** Some clients ( discord.js ) only check if a property exists within the response, - which causes erorrs when, say, the `application` property is `null`. + which causes errors when, say, the `application` property is `null`. **/ // for (var curr in x) { @@ -216,7 +209,7 @@ router.post( }), async (req: Request, res: Response) => { const { channel_id } = req.params; - var body = req.body as MessageCreateSchema; + const body = req.body as MessageCreateSchema; const attachments: Attachment[] = []; const channel = await Channel.findOneOrFail({ @@ -244,7 +237,7 @@ router.post( } if (!req.rights.has(Rights.FLAGS.BYPASS_RATE_LIMITS)) { - var limits = Config.get().limits; + const limits = Config.get().limits; if (limits.absoluteRate.register.enabled) { const count = await Message.count({ where: { @@ -269,7 +262,7 @@ router.post( } const files = (req.files as Express.Multer.File[]) ?? []; - for (var currFile of files) { + for (const currFile of files) { try { const file = await uploadFile( `/attachments/${channel.id}`, @@ -279,13 +272,13 @@ router.post( Attachment.create({ ...file, proxy_url: file.url }), ); } catch (error) { - return res.status(400).json({ message: error!.toString() }); + return res.status(400).json({ message: error?.toString() }); } } const embeds = body.embeds || []; if (body.embed) embeds.push(body.embed); - let message = await handleMessage({ + const message = await handleMessage({ ...body, type: 0, pinned: false, @@ -304,7 +297,7 @@ router.post( // Only one recipients should be closed here, since in group DMs the recipient is deleted not closed await Promise.all( - channel.recipients!.map((recipient) => { + channel.recipients?.map((recipient) => { if (recipient.closed) { recipient.closed = false; return Promise.all([ @@ -318,7 +311,7 @@ router.post( }), ]); } - }), + }) || [], ); } @@ -332,6 +325,7 @@ router.post( }); } + // eslint-disable-next-line @typescript-eslint/ban-ts-comment //@ts-ignore message.member.roles = message.member.roles .filter((x) => x.id != x.guild_id) @@ -362,7 +356,10 @@ router.post( channel.save(), ]); - postHandleMessage(message).catch((e) => {}); // no await as it shouldnt block the message send function and silently catch error + // no await as it shouldnt block the message send function and silently catch error + postHandleMessage(message).catch((e) => + console.error("[Message] post-message handler failed", e), + ); return res.json(message); }, diff --git a/src/api/routes/channels/#channel_id/permissions.ts b/src/api/routes/channels/#channel_id/permissions.ts index 7aa29700..da448678 100644 --- a/src/api/routes/channels/#channel_id/permissions.ts +++ b/src/api/routes/channels/#channel_id/permissions.ts @@ -43,7 +43,7 @@ router.put( const { channel_id, overwrite_id } = req.params; const body = req.body as ChannelPermissionOverwriteSchema; - var channel = await Channel.findOneOrFail({ + const channel = await Channel.findOneOrFail({ where: { id: channel_id }, }); if (!channel.guild_id) throw new HTTPError("Channel not found", 404); @@ -56,22 +56,24 @@ router.put( throw new HTTPError("user not found", 404); } else throw new HTTPError("type not supported", 501); - //@ts-ignore - var overwrite: ChannelPermissionOverwrite = + let overwrite: ChannelPermissionOverwrite | undefined = channel.permission_overwrites?.find((x) => x.id === overwrite_id); if (!overwrite) { - // @ts-ignore overwrite = { id: overwrite_id, type: body.type, + allow: "0", + deny: "0", }; - channel.permission_overwrites!.push(overwrite); + channel.permission_overwrites?.push(overwrite); } overwrite.allow = String( - req.permission!.bitfield & (BigInt(body.allow) || BigInt("0")), + (req.permission?.bitfield || 0n) & + (BigInt(body.allow) || BigInt("0")), ); overwrite.deny = String( - req.permission!.bitfield & (BigInt(body.deny) || BigInt("0")), + (req.permission?.bitfield || 0n) & + (BigInt(body.deny) || BigInt("0")), ); await Promise.all([ @@ -99,7 +101,7 @@ router.delete( }); if (!channel.guild_id) throw new HTTPError("Channel not found", 404); - channel.permission_overwrites = channel.permission_overwrites!.filter( + channel.permission_overwrites = channel.permission_overwrites?.filter( (x) => x.id === overwrite_id, ); diff --git a/src/api/routes/channels/#channel_id/pins.ts b/src/api/routes/channels/#channel_id/pins.ts index f48e0ff5..28419383 100644 --- a/src/api/routes/channels/#channel_id/pins.ts +++ b/src/api/routes/channels/#channel_id/pins.ts @@ -21,13 +21,11 @@ import { ChannelPinsUpdateEvent, Config, emitEvent, - getPermission, Message, MessageUpdateEvent, DiscordApiErrors, } from "@fosscord/util"; import { Router, Request, Response } from "express"; -import { HTTPError } from "lambert-server"; import { route } from "@fosscord/api"; const router: Router = Router(); @@ -43,7 +41,7 @@ router.put( }); // * in dm channels anyone can pin messages -> only check for guilds - if (message.guild_id) req.permission!.hasThrow("MANAGE_MESSAGES"); + if (message.guild_id) req.permission?.hasThrow("MANAGE_MESSAGES"); const pinned_count = await Message.count({ where: { channel: { id: channel_id }, pinned: true }, @@ -83,7 +81,7 @@ router.delete( const channel = await Channel.findOneOrFail({ where: { id: channel_id }, }); - if (channel.guild_id) req.permission!.hasThrow("MANAGE_MESSAGES"); + if (channel.guild_id) req.permission?.hasThrow("MANAGE_MESSAGES"); const message = await Message.findOneOrFail({ where: { id: message_id }, @@ -120,7 +118,7 @@ router.get( async (req: Request, res: Response) => { const { channel_id } = req.params; - let pins = await Message.find({ + const pins = await Message.find({ where: { channel_id: channel_id, pinned: true }, }); diff --git a/src/api/routes/channels/#channel_id/purge.ts b/src/api/routes/channels/#channel_id/purge.ts index 05660acf..04d8cfa2 100644 --- a/src/api/routes/channels/#channel_id/purge.ts +++ b/src/api/routes/channels/#channel_id/purge.ts @@ -19,10 +19,9 @@ import { HTTPError } from "lambert-server"; import { route } from "@fosscord/api"; import { isTextChannel } from "./messages"; -import { FindManyOptions, Between, Not } from "typeorm"; +import { FindManyOptions, Between, Not, FindOperator } from "typeorm"; import { Channel, - Config, emitEvent, getPermission, getRights, @@ -69,7 +68,9 @@ router.post( // TODO: send the deletion event bite-by-bite to prevent client stress - var query: FindManyOptions<Message> & { where: { id?: any } } = { + const query: FindManyOptions<Message> & { + where: { id?: FindOperator<string> }; + } = { order: { id: "ASC" }, // take: limit, where: { @@ -93,7 +94,6 @@ router.post( }; const messages = await Message.find(query); - const endpoint = Config.get().cdn.endpointPublic; if (messages.length == 0) { res.sendStatus(304); diff --git a/src/api/routes/channels/#channel_id/recipients.ts b/src/api/routes/channels/#channel_id/recipients.ts index 6928dd34..252a8ef0 100644 --- a/src/api/routes/channels/#channel_id/recipients.ts +++ b/src/api/routes/channels/#channel_id/recipients.ts @@ -41,7 +41,7 @@ router.put("/:user_id", route({}), async (req: Request, res: Response) => { if (channel.type !== ChannelType.GROUP_DM) { const recipients = [ - ...channel.recipients!.map((r) => r.user_id), + ...(channel.recipients?.map((r) => r.user_id) || []), user_id, ].unique(); @@ -51,11 +51,11 @@ router.put("/:user_id", route({}), async (req: Request, res: Response) => { ); return res.status(201).json(new_channel); } else { - if (channel.recipients!.map((r) => r.user_id).includes(user_id)) { + if (channel.recipients?.map((r) => r.user_id).includes(user_id)) { throw DiscordApiErrors.INVALID_RECIPIENT; //TODO is this the right error? } - channel.recipients!.push( + channel.recipients?.push( Recipient.create({ channel_id: channel_id, user_id: user_id }), ); await channel.save(); @@ -95,7 +95,7 @@ router.delete("/:user_id", route({}), async (req: Request, res: Response) => { ) throw DiscordApiErrors.MISSING_PERMISSIONS; - if (!channel.recipients!.map((r) => r.user_id).includes(user_id)) { + if (!channel.recipients?.map((r) => r.user_id).includes(user_id)) { throw DiscordApiErrors.INVALID_RECIPIENT; //TODO is this the right error? } diff --git a/src/api/routes/channels/#channel_id/webhooks.ts b/src/api/routes/channels/#channel_id/webhooks.ts index 511933c3..31cae747 100644 --- a/src/api/routes/channels/#channel_id/webhooks.ts +++ b/src/api/routes/channels/#channel_id/webhooks.ts @@ -55,10 +55,10 @@ router.post( const webhook_count = await Webhook.count({ where: { channel_id } }); const { maxWebhooks } = Config.get().limits.channel; - if (webhook_count > maxWebhooks) + if (maxWebhooks && webhook_count > maxWebhooks) throw DiscordApiErrors.MAXIMUM_WEBHOOKS.withParams(maxWebhooks); - var { avatar, name } = req.body as WebhookCreateSchema; + let { avatar, name } = req.body as WebhookCreateSchema; name = trimSpecial(name); // TODO: move this diff --git a/src/api/routes/discoverable-guilds.ts b/src/api/routes/discoverable-guilds.ts index 522861eb..8f90d73c 100644 --- a/src/api/routes/discoverable-guilds.ts +++ b/src/api/routes/discoverable-guilds.ts @@ -26,8 +26,8 @@ const router = Router(); router.get("/", route({}), async (req: Request, res: Response) => { const { offset, limit, categories } = req.query; - var showAllGuilds = Config.get().guild.discovery.showAllGuilds; - var configLimit = Config.get().guild.discovery.limit; + const showAllGuilds = Config.get().guild.discovery.showAllGuilds; + const configLimit = Config.get().guild.discovery.limit; let guilds; if (categories == undefined) { guilds = showAllGuilds diff --git a/src/api/routes/discovery.ts b/src/api/routes/discovery.ts index 411c3bc5..1414a617 100644 --- a/src/api/routes/discovery.ts +++ b/src/api/routes/discovery.ts @@ -26,7 +26,8 @@ router.get("/categories", route({}), async (req: Request, res: Response) => { // TODO: // Get locale instead - const { locale, primary_only } = req.query; + // const { locale, primary_only } = req.query; + const { primary_only } = req.query; const out = primary_only ? await Categories.find() diff --git a/src/api/routes/download/index.ts b/src/api/routes/download.ts index 246c8834..b6c03a48 100644 --- a/src/api/routes/download/index.ts +++ b/src/api/routes/download.ts @@ -22,11 +22,6 @@ import { FieldErrors, Release } from "@fosscord/util"; const router = Router(); -/* - TODO: Putting the download route in /routes/download.ts doesn't register the route, for some reason - But putting it here *does* -*/ - router.get("/", route({}), async (req: Request, res: Response) => { const { platform } = req.query; diff --git a/src/api/routes/gifs/search.ts b/src/api/routes/gifs/search.ts index 02022004..ae63d643 100644 --- a/src/api/routes/gifs/search.ts +++ b/src/api/routes/gifs/search.ts @@ -41,7 +41,7 @@ router.get("/", route({}), async (req: Request, res: Response) => { }, ); - const { results } = (await response.json()) as any; // TODO: types + const { results } = await response.json(); res.json(results.map(parseGifResult)).status(200); }); diff --git a/src/api/routes/gifs/trending-gifs.ts b/src/api/routes/gifs/trending-gifs.ts index d3fdb00a..d0698fa0 100644 --- a/src/api/routes/gifs/trending-gifs.ts +++ b/src/api/routes/gifs/trending-gifs.ts @@ -41,7 +41,7 @@ router.get("/", route({}), async (req: Request, res: Response) => { }, ); - const { results } = (await response.json()) as any; // TODO: types + const { results } = await response.json(); res.json(results.map(parseGifResult)).status(200); }); diff --git a/src/api/routes/gifs/trending.ts b/src/api/routes/gifs/trending.ts index 5dc43e85..5c872df8 100644 --- a/src/api/routes/gifs/trending.ts +++ b/src/api/routes/gifs/trending.ts @@ -25,7 +25,57 @@ import { HTTPError } from "lambert-server"; const router = Router(); -export function parseGifResult(result: any) { +// TODO: Move somewhere else +enum TENOR_GIF_TYPES { + gif, + mediumgif, + tinygif, + nanogif, + mp4, + loopedmp4, + tinymp4, + nanomp4, + webm, + tinywebm, + nanowebm, +} + +type TENOR_MEDIA = { + preview: string; + url: string; + dims: number[]; + size: number; +}; + +type TENOR_GIF = { + created: number; + hasaudio: boolean; + id: string; + media: { [type in keyof typeof TENOR_GIF_TYPES]: TENOR_MEDIA }[]; + tags: string[]; + title: string; + itemurl: string; + hascaption: boolean; + url: string; +}; + +type TENOR_CATEGORY = { + searchterm: string; + path: string; + image: string; + name: string; +}; + +type TENOR_CATEGORIES_RESULTS = { + tags: TENOR_CATEGORY[]; +}; + +type TENOR_TRENDING_RESULTS = { + next: string; + results: TENOR_GIF[]; +}; + +export function parseGifResult(result: TENOR_GIF) { return { id: result.id, title: result.title, @@ -50,7 +100,8 @@ export function getGifApiKey() { router.get("/", route({}), async (req: Request, res: Response) => { // TODO: Custom providers // TODO: return gifs as mp4 - const { media_format, locale } = req.query; + // const { media_format, locale } = req.query; + const { locale } = req.query; const apiKey = getGifApiKey(); @@ -75,11 +126,11 @@ router.get("/", route({}), async (req: Request, res: Response) => { ), ]); - const { tags } = (await responseSource.json()) as any; // TODO: types - const { results } = (await trendGifSource.json()) as any; //TODO: types; + const { tags } = (await responseSource.json()) as TENOR_CATEGORIES_RESULTS; + const { results } = (await trendGifSource.json()) as TENOR_TRENDING_RESULTS; res.json({ - categories: tags.map((x: any) => ({ + categories: tags.map((x) => ({ name: x.searchterm, src: x.image, })), diff --git a/src/api/routes/guild-recommendations.ts b/src/api/routes/guild-recommendations.ts index 13c08734..ac2ad9e7 100644 --- a/src/api/routes/guild-recommendations.ts +++ b/src/api/routes/guild-recommendations.ts @@ -25,10 +25,11 @@ import { Like } from "typeorm"; const router = Router(); router.get("/", route({}), async (req: Request, res: Response) => { - const { limit, personalization_disabled } = req.query; - var showAllGuilds = Config.get().guild.discovery.showAllGuilds; + // const { limit, personalization_disabled } = req.query; + const { limit } = req.query; + const showAllGuilds = Config.get().guild.discovery.showAllGuilds; - const genLoadId = (size: Number) => + const genLoadId = (size: number) => [...Array(size)] .map(() => Math.floor(Math.random() * 16).toString(16)) .join(""); diff --git a/src/api/routes/guilds/#guild_id/bans.ts b/src/api/routes/guilds/#guild_id/bans.ts index efb06fa0..b044689f 100644 --- a/src/api/routes/guilds/#guild_id/bans.ts +++ b/src/api/routes/guilds/#guild_id/bans.ts @@ -41,8 +41,8 @@ router.get( async (req: Request, res: Response) => { const { guild_id } = req.params; - let bans = await Ban.find({ where: { guild_id: guild_id } }); - let promisesToAwait: object[] = []; + const bans = await Ban.find({ where: { guild_id: guild_id } }); + const promisesToAwait: object[] = []; const bansObj: object[] = []; bans.filter((ban) => ban.user_id !== ban.executor_id); // pretend self-bans don't exist to prevent victim chasing @@ -104,14 +104,14 @@ router.put( if ( req.user_id === banned_user_id && - banned_user_id === req.permission!.cache.guild?.owner_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) + 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); @@ -149,7 +149,7 @@ router.put( const banned_user = await User.getPublicUser(req.params.user_id); - if (req.permission!.cache.guild?.owner_id === 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, @@ -186,7 +186,7 @@ router.delete( async (req: Request, res: Response) => { const { guild_id, user_id } = req.params; - let ban = await Ban.findOneOrFail({ + const ban = await Ban.findOneOrFail({ where: { guild_id: guild_id, user_id: user_id }, }); diff --git a/src/api/routes/guilds/#guild_id/channels.ts b/src/api/routes/guilds/#guild_id/channels.ts index b72f5ddb..acdb5f19 100644 --- a/src/api/routes/guilds/#guild_id/channels.ts +++ b/src/api/routes/guilds/#guild_id/channels.ts @@ -68,7 +68,7 @@ router.patch( 400, ); - const opts: any = {}; + const opts: Partial<Channel> = {}; if (x.position != null) opts.position = x.position; if (x.parent_id) { diff --git a/src/api/routes/guilds/#guild_id/delete.ts b/src/api/routes/guilds/#guild_id/delete.ts index 551c6829..9a13c9b4 100644 --- a/src/api/routes/guilds/#guild_id/delete.ts +++ b/src/api/routes/guilds/#guild_id/delete.ts @@ -16,17 +16,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -import { - Channel, - emitEvent, - GuildDeleteEvent, - Guild, - Member, - Message, - Role, - Invite, - Emoji, -} from "@fosscord/util"; +import { emitEvent, GuildDeleteEvent, Guild } from "@fosscord/util"; import { Router, Request, Response } from "express"; import { HTTPError } from "lambert-server"; import { route } from "@fosscord/api"; @@ -36,7 +26,7 @@ const router = Router(); // discord prefixes this route with /delete instead of using the delete method // docs are wrong https://discord.com/developers/docs/resources/guild#delete-guild router.post("/", route({}), async (req: Request, res: Response) => { - var { guild_id } = req.params; + const { guild_id } = req.params; const guild = await Guild.findOneOrFail({ where: { id: guild_id }, diff --git a/src/api/routes/guilds/#guild_id/discovery-requirements.ts b/src/api/routes/guilds/#guild_id/discovery-requirements.ts index 11dcc33e..de2da6ee 100644 --- a/src/api/routes/guilds/#guild_id/discovery-requirements.ts +++ b/src/api/routes/guilds/#guild_id/discovery-requirements.ts @@ -16,8 +16,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -import { Guild, Config } from "@fosscord/util"; - import { Router, Request, Response } from "express"; import { route } from "@fosscord/api"; diff --git a/src/api/routes/guilds/#guild_id/index.ts b/src/api/routes/guilds/#guild_id/index.ts index 0df90f56..c262a088 100644 --- a/src/api/routes/guilds/#guild_id/index.ts +++ b/src/api/routes/guilds/#guild_id/index.ts @@ -47,10 +47,10 @@ router.get("/", route({}), async (req: Request, res: Response) => { 401, ); - // @ts-ignore - guild.joined_at = member?.joined_at; - - return res.send(guild); + return res.send({ + ...guild, + joined_at: member?.joined_at, + }); }); router.patch( @@ -68,7 +68,7 @@ router.patch( "MANAGE_GUILDS", ); - var guild = await Guild.findOneOrFail({ + const guild = await Guild.findOneOrFail({ where: { id: guild_id }, relations: ["emojis", "roles", "stickers"], }); @@ -110,7 +110,7 @@ router.patch( "DISCOVERABLE", ]; - for (var feature of diff) { + for (const feature of diff) { if (MUTABLE_FEATURES.includes(feature)) continue; throw FosscordApiErrors.FEATURE_IS_IMMUTABLE.withParams( diff --git a/src/api/routes/guilds/#guild_id/invites.ts b/src/api/routes/guilds/#guild_id/invites.ts index 6e9cc3e6..dd099992 100644 --- a/src/api/routes/guilds/#guild_id/invites.ts +++ b/src/api/routes/guilds/#guild_id/invites.ts @@ -16,7 +16,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -import { getPermission, Invite, PublicInviteRelation } from "@fosscord/util"; +import { Invite, PublicInviteRelation } from "@fosscord/util"; import { route } from "@fosscord/api"; import { Request, Response, Router } from "express"; diff --git a/src/api/routes/guilds/#guild_id/members/#member_id/index.ts b/src/api/routes/guilds/#guild_id/members/#member_id/index.ts index 2cf7c08b..2daa7d9b 100644 --- a/src/api/routes/guilds/#guild_id/members/#member_id/index.ts +++ b/src/api/routes/guilds/#guild_id/members/#member_id/index.ts @@ -49,11 +49,12 @@ router.patch( "/", route({ body: "MemberChangeSchema" }), async (req: Request, res: Response) => { - let { guild_id, member_id } = req.params; - if (member_id === "@me") member_id = req.user_id; + const { guild_id } = req.params; + const member_id = + req.params.member_id === "@me" ? req.user_id : req.params.member_id; const body = req.body as MemberChangeSchema; - let member = await Member.findOneOrFail({ + const member = await Member.findOneOrFail({ where: { id: member_id, guild_id }, relations: ["roles", "user"], }); @@ -101,7 +102,8 @@ router.put("/", route({}), async (req: Request, res: Response) => { const rights = await getRights(req.user_id); - let { guild_id, member_id } = req.params; + const { guild_id } = req.params; + let { member_id } = req.params; if (member_id === "@me") { member_id = req.user_id; rights.hasThrow("JOIN_GUILDS"); @@ -109,19 +111,19 @@ router.put("/", route({}), async (req: Request, res: Response) => { // TODO: join others by controller } - var guild = await Guild.findOneOrFail({ + const guild = await Guild.findOneOrFail({ where: { id: guild_id }, }); - var emoji = await Emoji.find({ + const emoji = await Emoji.find({ where: { guild_id: guild_id }, }); - var roles = await Role.find({ + const roles = await Role.find({ where: { guild_id: guild_id }, }); - var stickers = await Sticker.find({ + const stickers = await Sticker.find({ where: { guild_id: guild_id }, }); diff --git a/src/api/routes/guilds/#guild_id/members/#member_id/nick.ts b/src/api/routes/guilds/#guild_id/members/#member_id/nick.ts index 619b66f7..c93eab08 100644 --- a/src/api/routes/guilds/#guild_id/members/#member_id/nick.ts +++ b/src/api/routes/guilds/#guild_id/members/#member_id/nick.ts @@ -26,12 +26,12 @@ router.patch( "/", route({ body: "MemberNickChangeSchema" }), async (req: Request, res: Response) => { - var { guild_id, member_id } = req.params; - var permissionString: PermissionResolvable = "MANAGE_NICKNAMES"; - if (member_id === "@me") { - member_id = req.user_id; - permissionString = "CHANGE_NICKNAME"; - } + const { guild_id } = req.params; + let permissionString: PermissionResolvable = "MANAGE_NICKNAMES"; + const member_id = + req.params.member_id === "@me" + ? ((permissionString = "CHANGE_NICKNAME"), req.user_id) + : req.params.member_id; const perms = await getPermission(req.user_id, guild_id); perms.hasThrow(permissionString); diff --git a/src/api/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts b/src/api/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts index e64893b7..16c5e789 100644 --- a/src/api/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts +++ b/src/api/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts @@ -16,7 +16,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -import { getPermission, Member } from "@fosscord/util"; +import { Member } from "@fosscord/util"; import { route } from "@fosscord/api"; import { Request, Response, Router } from "express"; diff --git a/src/api/routes/guilds/#guild_id/members/index.ts b/src/api/routes/guilds/#guild_id/members/index.ts index b96210f3..51e9eb1f 100644 --- a/src/api/routes/guilds/#guild_id/members/index.ts +++ b/src/api/routes/guilds/#guild_id/members/index.ts @@ -17,7 +17,7 @@ */ import { Request, Response, Router } from "express"; -import { Guild, Member, PublicMemberProjection } from "@fosscord/util"; +import { Member, PublicMemberProjection } from "@fosscord/util"; import { route } from "@fosscord/api"; import { MoreThan } from "typeorm"; import { HTTPError } from "lambert-server"; diff --git a/src/api/routes/guilds/#guild_id/messages/search.ts b/src/api/routes/guilds/#guild_id/messages/search.ts index 7061b5f0..601167ee 100644 --- a/src/api/routes/guilds/#guild_id/messages/search.ts +++ b/src/api/routes/guilds/#guild_id/messages/search.ts @@ -16,6 +16,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ +/* eslint-disable @typescript-eslint/ban-ts-comment */ + import { Request, Response, Router } from "express"; import { route } from "@fosscord/api"; import { getPermission, FieldErrors, Message, Channel } from "@fosscord/util"; @@ -28,10 +30,10 @@ router.get("/", route({}), async (req: Request, res: Response) => { const { channel_id, content, - include_nsfw, // TODO + // include_nsfw, // TODO offset, sort_order, - sort_by, // TODO: Handle 'relevance' + // sort_by, // TODO: Handle 'relevance' limit, author_id, } = req.query; @@ -62,7 +64,7 @@ router.get("/", route({}), async (req: Request, res: Response) => { if (!permissions.has("READ_MESSAGE_HISTORY")) return res.json({ messages: [], total_results: 0 }); - var query: FindManyOptions<Message> = { + const query: FindManyOptions<Message> = { order: { timestamp: sort_order ? (sort_order.toUpperCase() as "ASC" | "DESC") @@ -87,7 +89,7 @@ router.get("/", route({}), async (req: Request, res: Response) => { skip: offset ? Number(offset) : 0, }; //@ts-ignore - if (channel_id) query.where!.channel = { id: channel_id }; + if (channel_id) query.where.channel = { id: channel_id }; else { // get all channel IDs that this user can access const channels = await Channel.find({ @@ -96,7 +98,7 @@ router.get("/", route({}), async (req: Request, res: Response) => { }); const ids = []; - for (var channel of channels) { + for (const channel of channels) { const perm = await getPermission( req.user_id, req.params.guild_id, @@ -108,12 +110,12 @@ router.get("/", route({}), async (req: Request, res: Response) => { } //@ts-ignore - query.where!.channel = { id: In(ids) }; + query.where.channel = { id: In(ids) }; } //@ts-ignore - if (author_id) query.where!.author = { id: author_id }; + if (author_id) query.where.author = { id: author_id }; //@ts-ignore - if (content) query.where!.content = Like(`%${content}%`); + if (content) query.where.content = Like(`%${content}%`); const messages: Message[] = await Message.find(query); diff --git a/src/api/routes/guilds/#guild_id/profile/index.ts b/src/api/routes/guilds/#guild_id/profile/index.ts index 5771fbf1..cbf0ff6a 100644 --- a/src/api/routes/guilds/#guild_id/profile/index.ts +++ b/src/api/routes/guilds/#guild_id/profile/index.ts @@ -33,8 +33,9 @@ router.patch( "/:member_id", route({ body: "MemberChangeProfileSchema" }), async (req: Request, res: Response) => { - let { guild_id, member_id } = req.params; - if (member_id === "@me") member_id = req.user_id; + const { guild_id } = req.params; + // const member_id = + // req.params.member_id === "@me" ? req.user_id : req.params.member_id; const body = req.body as MemberChangeProfileSchema; let member = await Member.findOneOrFail({ diff --git a/src/api/routes/guilds/#guild_id/prune.ts b/src/api/routes/guilds/#guild_id/prune.ts index 1199df54..37b70f63 100644 --- a/src/api/routes/guilds/#guild_id/prune.ts +++ b/src/api/routes/guilds/#guild_id/prune.ts @@ -29,16 +29,16 @@ export const inactiveMembers = async ( days: number, roles: string[] = [], ) => { - var date = new Date(); + const date = new Date(); date.setDate(date.getDate() - days); //Snowflake should have `generateFromTime` method? Or similar? - var minId = BigInt(date.valueOf() - Snowflake.EPOCH) << BigInt(22); + const minId = BigInt(date.valueOf() - Snowflake.EPOCH) << BigInt(22); /** idea: ability to customise the cutoff variable possible candidates: public read receipt, last presence, last VC leave **/ - var members = await Member.find({ + let members = await Member.find({ where: [ { guild_id, @@ -83,7 +83,7 @@ export const inactiveMembers = async ( router.get("/", route({}), async (req: Request, res: Response) => { const days = parseInt(req.query.days as string); - var roles = req.query.include_roles; + let roles = req.query.include_roles; if (typeof roles === "string") roles = [roles]; //express will return array otherwise const members = await inactiveMembers( @@ -102,7 +102,7 @@ router.post( async (req: Request, res: Response) => { const days = parseInt(req.body.days); - var roles = req.query.include_roles; + let roles = req.query.include_roles; if (typeof roles === "string") roles = [roles]; const { guild_id } = req.params; diff --git a/src/api/routes/guilds/#guild_id/regions.ts b/src/api/routes/guilds/#guild_id/regions.ts index a9c04a39..61ba00bf 100644 --- a/src/api/routes/guilds/#guild_id/regions.ts +++ b/src/api/routes/guilds/#guild_id/regions.ts @@ -16,10 +16,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -import { Config, Guild, Member } from "@fosscord/util"; +import { Guild } from "@fosscord/util"; import { Request, Response, Router } from "express"; -import { getVoiceRegions, route } from "@fosscord/api"; -import { getIpAdress } from "@fosscord/api"; +import { getVoiceRegions, route, getIpAdress } from "@fosscord/api"; const router = Router(); diff --git a/src/api/routes/guilds/#guild_id/roles/#role_id/index.ts b/src/api/routes/guilds/#guild_id/roles/#role_id/index.ts index 22eb439a..48e77897 100644 --- a/src/api/routes/guilds/#guild_id/roles/#role_id/index.ts +++ b/src/api/routes/guilds/#guild_id/roles/#role_id/index.ts @@ -87,7 +87,8 @@ router.patch( role.assign({ ...body, permissions: String( - req.permission!.bitfield & BigInt(body.permissions || "0"), + (req.permission?.bitfield || 0n) & + BigInt(body.permissions || "0"), ), }); diff --git a/src/api/routes/guilds/#guild_id/roles/index.ts b/src/api/routes/guilds/#guild_id/roles/index.ts index feab84ef..54d4b12c 100644 --- a/src/api/routes/guilds/#guild_id/roles/index.ts +++ b/src/api/routes/guilds/#guild_id/roles/index.ts @@ -68,7 +68,8 @@ router.post( guild_id: guild_id, managed: false, permissions: String( - req.permission!.bitfield & BigInt(body.permissions || "0"), + (req.permission?.bitfield || 0n) & + BigInt(body.permissions || "0"), ), tags: undefined, icon: undefined, diff --git a/src/api/routes/guilds/#guild_id/templates.ts b/src/api/routes/guilds/#guild_id/templates.ts index f5244313..284bbccf 100644 --- a/src/api/routes/guilds/#guild_id/templates.ts +++ b/src/api/routes/guilds/#guild_id/templates.ts @@ -44,7 +44,7 @@ const TemplateGuildProjection: (keyof Guild)[] = [ router.get("/", route({}), async (req: Request, res: Response) => { const { guild_id } = req.params; - var templates = await Template.find({ + const templates = await Template.find({ where: { source_guild_id: guild_id }, }); @@ -60,9 +60,9 @@ router.post( where: { id: guild_id }, select: TemplateGuildProjection, }); - const exists = await Template.findOneOrFail({ + const exists = await Template.findOne({ where: { id: guild_id }, - }).catch((e) => {}); + }); if (exists) throw new HTTPError("Template already exists", 400); const template = await Template.create({ diff --git a/src/api/routes/guilds/#guild_id/voice-states/#user_id/index.ts b/src/api/routes/guilds/#guild_id/voice-states/#user_id/index.ts index 9883ef0d..3577df17 100644 --- a/src/api/routes/guilds/#guild_id/voice-states/#user_id/index.ts +++ b/src/api/routes/guilds/#guild_id/voice-states/#user_id/index.ts @@ -37,8 +37,9 @@ router.patch( route({ body: "VoiceStateUpdateSchema" }), async (req: Request, res: Response) => { const body = req.body as VoiceStateUpdateSchema; - var { guild_id, user_id } = req.params; - if (user_id === "@me") user_id = req.user_id; + const { guild_id } = req.params; + const user_id = + req.params.user_id === "@me" ? req.user_id : req.params.user_id; const perms = await getPermission( req.user_id, diff --git a/src/api/routes/guilds/#guild_id/widget.json.ts b/src/api/routes/guilds/#guild_id/widget.json.ts index 46b8aa8b..9319d058 100644 --- a/src/api/routes/guilds/#guild_id/widget.json.ts +++ b/src/api/routes/guilds/#guild_id/widget.json.ts @@ -17,14 +17,7 @@ */ import { Request, Response, Router } from "express"; -import { - Config, - Permissions, - Guild, - Invite, - Channel, - Member, -} from "@fosscord/util"; +import { Permissions, Guild, Invite, Channel, Member } from "@fosscord/util"; import { HTTPError } from "lambert-server"; import { random, route } from "@fosscord/api"; @@ -46,7 +39,7 @@ router.get("/", route({}), async (req: Request, res: Response) => { if (!guild.widget_enabled) throw new HTTPError("Widget Disabled", 404); // Fetch existing widget invite for widget channel - var invite = await Invite.findOne({ + let invite = await Invite.findOne({ where: { channel_id: guild.widget_channel_id }, }); @@ -70,7 +63,7 @@ router.get("/", route({}), async (req: Request, res: Response) => { } // Fetch voice channels, and the @everyone permissions object - const channels = [] as any[]; + const channels: { id: string; name: string; position: number }[] = []; ( await Channel.find({ @@ -88,15 +81,15 @@ router.get("/", route({}), async (req: Request, res: Response) => { ) { channels.push({ id: doc.id, - name: doc.name, - position: doc.position, + name: doc.name ?? "Unknown channel", + position: doc.position ?? 0, }); } }); // Fetch members // TODO: Understand how Discord's max 100 random member sample works, and apply to here (see top of this file) - let members = await Member.find({ where: { guild_id: guild_id } }); + const members = await Member.find({ where: { guild_id: guild_id } }); // Construct object to respond with const data = { diff --git a/src/api/routes/guilds/#guild_id/widget.png.ts b/src/api/routes/guilds/#guild_id/widget.png.ts index 1c6a62ac..65de8978 100644 --- a/src/api/routes/guilds/#guild_id/widget.png.ts +++ b/src/api/routes/guilds/#guild_id/widget.png.ts @@ -16,6 +16,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ +/* eslint-disable @typescript-eslint/no-explicit-any */ + import { Request, Response, Router } from "express"; import { Guild } from "@fosscord/util"; import { HTTPError } from "lambert-server"; @@ -161,8 +163,7 @@ async function drawIcon( scale: number, icon: string, ) { - // @ts-ignore - const img = new require("canvas").Image(); + const img = new (require("canvas").Image)(); img.src = icon; // Do some canvas clipping magic! diff --git a/src/api/routes/guilds/index.ts b/src/api/routes/guilds/index.ts index 125d25b0..64af4bd1 100644 --- a/src/api/routes/guilds/index.ts +++ b/src/api/routes/guilds/index.ts @@ -18,7 +18,6 @@ import { Router, Request, Response } from "express"; import { - Role, Guild, Config, getRights, @@ -52,6 +51,7 @@ router.post( const { autoJoin } = Config.get().guild; if (autoJoin.enabled && !autoJoin.guilds?.length) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore await Config.set({ guild: { autoJoin: { guilds: [guild.id] } } }); } diff --git a/src/api/routes/guilds/templates/index.ts b/src/api/routes/guilds/templates/index.ts index f3bb3ef1..a43337d8 100644 --- a/src/api/routes/guilds/templates/index.ts +++ b/src/api/routes/guilds/templates/index.ts @@ -86,8 +86,8 @@ router.post( const { enabled, allowTemplateCreation, - allowDiscordTemplates, - allowRaws, + // allowDiscordTemplates, + // allowRaws, } = Config.get().templates; if (!enabled) return res @@ -121,7 +121,7 @@ router.post( const guild_id = Snowflake.generate(); - const [guild, role] = await Promise.all([ + const [guild] = await Promise.all([ Guild.create({ ...body, ...template.serialized_source_guild, diff --git a/src/api/routes/oauth2/authorize.ts b/src/api/routes/oauth2/authorize.ts index be9b39b4..e238b72f 100644 --- a/src/api/routes/oauth2/authorize.ts +++ b/src/api/routes/oauth2/authorize.ts @@ -27,16 +27,14 @@ import { Member, Permissions, User, - getRights, - Rights, - MemberPrivateProjection, } from "@fosscord/util"; const router = Router(); // TODO: scopes, other oauth types router.get("/", route({}), async (req: Request, res: Response) => { - const { client_id, scope, response_type, redirect_url } = req.query; + // const { client_id, scope, response_type, redirect_url } = req.query; + const { client_id } = req.query; const app = await Application.findOne({ where: { @@ -68,6 +66,7 @@ router.get("/", route({}), async (req: Request, res: Response) => { }, }, relations: ["guild", "roles"], + // eslint-disable-next-line @typescript-eslint/ban-ts-comment //@ts-ignore // prettier-ignore select: ["guild.id", "guild.name", "guild.icon", "guild.mfa_level", "guild.owner_id", "roles.id"], @@ -139,7 +138,8 @@ router.post( route({ body: "ApplicationAuthorizeSchema" }), async (req: Request, res: Response) => { const body = req.body as ApplicationAuthorizeSchema; - const { client_id, scope, response_type, redirect_url } = req.query; + // const { client_id, scope, response_type, redirect_url } = req.query; + const { client_id } = req.query; // TODO: captcha verification // TODO: MFA verification @@ -153,7 +153,7 @@ router.post( // getPermission cache won't exist if we're owner if ( Object.keys(perms.cache || {}).length > 0 && - perms.cache.member!.user.bot + perms.cache.member?.user.bot ) throw DiscordApiErrors.UNAUTHORIZED; perms.hasThrow("MANAGE_GUILD"); diff --git a/src/api/routes/partners/#guild_id/requirements.ts b/src/api/routes/partners/#guild_id/requirements.ts index 11dcc33e..de2da6ee 100644 --- a/src/api/routes/partners/#guild_id/requirements.ts +++ b/src/api/routes/partners/#guild_id/requirements.ts @@ -16,8 +16,6 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -import { Guild, Config } from "@fosscord/util"; - import { Router, Request, Response } from "express"; import { route } from "@fosscord/api"; diff --git a/src/api/routes/policies/instance/domains.ts b/src/api/routes/policies/instance/domains.ts index 929cf65c..33c06765 100644 --- a/src/api/routes/policies/instance/domains.ts +++ b/src/api/routes/policies/instance/domains.ts @@ -19,7 +19,6 @@ import { Router, Request, Response } from "express"; import { route } from "@fosscord/api"; import { Config } from "@fosscord/util"; -import { config } from "dotenv"; const router = Router(); router.get("/", route({}), async (req: Request, res: Response) => { diff --git a/src/api/routes/store/published-listings/applications.ts b/src/api/routes/store/published-listings/applications.ts index 16604960..ec9168b1 100644 --- a/src/api/routes/store/published-listings/applications.ts +++ b/src/api/routes/store/published-listings/applications.ts @@ -23,7 +23,7 @@ const router: Router = Router(); router.get("/:id", route({}), async (req: Request, res: Response) => { //TODO - const id = req.params.id; + // const id = req.params.id; res.json({ id: "", summary: "", diff --git a/src/api/routes/store/published-listings/skus.ts b/src/api/routes/store/published-listings/skus.ts index 16604960..ec9168b1 100644 --- a/src/api/routes/store/published-listings/skus.ts +++ b/src/api/routes/store/published-listings/skus.ts @@ -23,7 +23,7 @@ const router: Router = Router(); router.get("/:id", route({}), async (req: Request, res: Response) => { //TODO - const id = req.params.id; + // const id = req.params.id; res.json({ id: "", summary: "", diff --git a/src/api/routes/updates.ts b/src/api/routes/updates.ts index 5555fcda..5c237465 100644 --- a/src/api/routes/updates.ts +++ b/src/api/routes/updates.ts @@ -18,12 +18,11 @@ import { Router, Response, Request } from "express"; import { route } from "@fosscord/api"; -import { Config, FieldErrors, Release } from "@fosscord/util"; +import { FieldErrors, Release } from "@fosscord/util"; const router = Router(); router.get("/", route({}), async (req: Request, res: Response) => { - const { client } = Config.get(); const platform = req.query.platform; if (!platform) diff --git a/src/api/routes/users/#id/delete.ts b/src/api/routes/users/#id/delete.ts index e7caeb05..9bc3f9f8 100644 --- a/src/api/routes/users/#id/delete.ts +++ b/src/api/routes/users/#id/delete.ts @@ -23,7 +23,6 @@ import { PrivateUserProjection, User, UserDeleteEvent, - UserDeleteSchema, } from "@fosscord/util"; import { Request, Response, Router } from "express"; @@ -33,7 +32,7 @@ router.post( "/", route({ right: "MANAGE_USERS" }), async (req: Request, res: Response) => { - let user = await User.findOneOrFail({ + await User.findOneOrFail({ where: { id: req.params.id }, select: [...PrivateUserProjection, "data"], }); diff --git a/src/api/routes/users/#id/profile.ts b/src/api/routes/users/#id/profile.ts index 1103bb48..dbf95a52 100644 --- a/src/api/routes/users/#id/profile.ts +++ b/src/api/routes/users/#id/profile.ts @@ -19,11 +19,9 @@ import { Router, Request, Response } from "express"; import { PublicConnectedAccount, - PublicUser, User, UserPublic, Member, - Guild, UserProfileModifySchema, handleFile, PrivateUserProjection, @@ -53,8 +51,8 @@ router.get( relations: ["connected_accounts"], }); - var mutual_guilds: object[] = []; - var premium_guild_since; + const mutual_guilds: object[] = []; + let premium_guild_since; if (with_mutual_guilds == "true") { const requested_member = await Member.find({ @@ -169,7 +167,7 @@ router.patch( `/banners/${req.user_id}`, body.banner as string, ); - let user = await User.findOneOrFail({ + const user = await User.findOneOrFail({ where: { id: req.user_id }, select: [...PrivateUserProjection, "data"], }); @@ -177,6 +175,7 @@ router.patch( user.assign(body); await user.save(); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore delete user.data; diff --git a/src/api/routes/users/#id/relationships.ts b/src/api/routes/users/#id/relationships.ts index aa36967a..e915e3ff 100644 --- a/src/api/routes/users/#id/relationships.ts +++ b/src/api/routes/users/#id/relationships.ts @@ -36,7 +36,7 @@ router.get( "/", route({ test: { response: { body: "UserRelationsResponse" } } }), async (req: Request, res: Response) => { - var mutual_relations: object[] = []; + const mutual_relations: object[] = []; const requested_relations = await User.findOneOrFail({ where: { id: req.params.id }, relations: ["relationships"], @@ -53,7 +53,7 @@ router.get( rmem.type === 1 && rmem.to_id !== req.user_id ) { - var relation_user = await User.getPublicUser(rmem.to_id); + const relation_user = await User.getPublicUser(rmem.to_id); mutual_relations.push({ id: relation_user.id, diff --git a/src/api/routes/users/@me/delete.ts b/src/api/routes/users/@me/delete.ts index a6ae2d13..8043eae3 100644 --- a/src/api/routes/users/@me/delete.ts +++ b/src/api/routes/users/@me/delete.ts @@ -17,7 +17,7 @@ */ import { Router, Request, Response } from "express"; -import { Guild, Member, User } from "@fosscord/util"; +import { Member, User } from "@fosscord/util"; import { route } from "@fosscord/api"; import bcrypt from "bcrypt"; import { HTTPError } from "lambert-server"; 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 0525bea2..72c95d6b 100644 --- a/src/api/routes/users/@me/guilds/#guild_id/settings.ts +++ b/src/api/routes/users/@me/guilds/#guild_id/settings.ts @@ -43,7 +43,7 @@ router.patch( const body = req.body as UserGuildSettingsSchema; if (body.channel_overrides) { - for (var channel in body.channel_overrides) { + for (const channel in body.channel_overrides) { Channel.findOneOrFail({ where: { id: channel } }); } } diff --git a/src/api/routes/users/@me/index.ts b/src/api/routes/users/@me/index.ts index 596e2575..0d3c3135 100644 --- a/src/api/routes/users/@me/index.ts +++ b/src/api/routes/users/@me/index.ts @@ -55,7 +55,7 @@ router.patch( }); // Populated on password change - var newToken: string | undefined; + let newToken: string | undefined; if (body.avatar) body.avatar = await handleFile( @@ -120,7 +120,7 @@ router.patch( } if (body.username) { - var check_username = body?.username?.replace(/\s/g, ""); + const check_username = body?.username?.replace(/\s/g, ""); if (!check_username) { throw FieldErrors({ username: { @@ -153,7 +153,8 @@ router.patch( user.validate(); await user.save(); - // @ts-ignore + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + //@ts-ignore delete user.data; // TODO: send update member list event in gateway diff --git a/src/api/routes/users/@me/mfa/codes-verification.ts b/src/api/routes/users/@me/mfa/codes-verification.ts index ac16f7e7..24f018c9 100644 --- a/src/api/routes/users/@me/mfa/codes-verification.ts +++ b/src/api/routes/users/@me/mfa/codes-verification.ts @@ -23,6 +23,7 @@ import { generateMfaBackupCodes, User, CodesVerificationSchema, + DiscordApiErrors, } from "@fosscord/util"; const router = Router(); @@ -31,14 +32,17 @@ router.post( "/", route({ body: "CodesVerificationSchema" }), async (req: Request, res: Response) => { - const { key, nonce, regenerate } = req.body as CodesVerificationSchema; + // const { key, nonce, regenerate } = req.body as CodesVerificationSchema; + const { 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 } }); + // const user = await User.findOneOrFail({ where: { id: req.user_id } }); + if ((await User.count({ where: { id: req.user_id } })) === 0) + throw DiscordApiErrors.UNKNOWN_USER; - var codes: BackupCode[]; + let codes: BackupCode[]; if (regenerate) { await BackupCode.update( { user: { id: req.user_id } }, diff --git a/src/api/routes/users/@me/mfa/codes.ts b/src/api/routes/users/@me/mfa/codes.ts index 09b9b329..e2600400 100644 --- a/src/api/routes/users/@me/mfa/codes.ts +++ b/src/api/routes/users/@me/mfa/codes.ts @@ -51,7 +51,7 @@ router.post( }); } - var codes: BackupCode[]; + let codes: BackupCode[]; if (regenerate) { await BackupCode.update( { user: { id: req.user_id } }, diff --git a/src/api/routes/users/@me/mfa/totp/disable.ts b/src/api/routes/users/@me/mfa/totp/disable.ts index c399ba33..e35691ae 100644 --- a/src/api/routes/users/@me/mfa/totp/disable.ts +++ b/src/api/routes/users/@me/mfa/totp/disable.ts @@ -42,7 +42,7 @@ router.post( const backup = await BackupCode.findOne({ where: { code: body.code } }); if (!backup) { - const ret = verifyToken(user.totp_secret!, body.code); + const ret = verifyToken(user.totp_secret || "", body.code); if (!ret || ret.delta != 0) throw new HTTPError( req.t("auth:login.INVALID_TOTP_CODE"), diff --git a/src/api/routes/users/@me/mfa/totp/enable.ts b/src/api/routes/users/@me/mfa/totp/enable.ts index a59983ac..f6519ad0 100644 --- a/src/api/routes/users/@me/mfa/totp/enable.ts +++ b/src/api/routes/users/@me/mfa/totp/enable.ts @@ -57,7 +57,7 @@ router.post( 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); + const backup_codes = generateMfaBackupCodes(req.user_id); await Promise.all(backup_codes.map((x) => x.save())); await User.update( { id: req.user_id }, diff --git a/src/api/routes/users/@me/relationships.ts b/src/api/routes/users/@me/relationships.ts index de684a34..4dfb4c33 100644 --- a/src/api/routes/users/@me/relationships.ts +++ b/src/api/routes/users/@me/relationships.ts @@ -175,7 +175,7 @@ async function updateRelationship( select: userProjection, }); - var relationship = user.relationships.find((x) => x.to_id === id); + let relationship = user.relationships.find((x) => x.to_id === id); const friendRequest = friend.relationships.find( (x) => x.to_id === req.user_id, ); @@ -219,13 +219,13 @@ async function updateRelationship( if (user.relationships.length >= maxFriends) throw DiscordApiErrors.MAXIMUM_FRIENDS.withParams(maxFriends); - var incoming_relationship = Relationship.create({ + let incoming_relationship = Relationship.create({ nickname: undefined, type: RelationshipType.incoming, to: user, from: friend, }); - var outgoing_relationship = Relationship.create({ + let outgoing_relationship = Relationship.create({ nickname: undefined, type: RelationshipType.outgoing, to: friend, diff --git a/src/api/routes/users/@me/settings.ts b/src/api/routes/users/@me/settings.ts index ad922084..c883bb30 100644 --- a/src/api/routes/users/@me/settings.ts +++ b/src/api/routes/users/@me/settings.ts @@ -17,7 +17,7 @@ */ import { Router, Response, Request } from "express"; -import { OrmUtils, User, UserSettingsSchema } from "@fosscord/util"; +import { User, UserSettingsSchema } from "@fosscord/util"; import { route } from "@fosscord/api"; const router = Router(); diff --git a/src/api/start.ts b/src/api/start.ts index e80a7d4a..7975d085 100644 --- a/src/api/start.ts +++ b/src/api/start.ts @@ -26,7 +26,7 @@ config(); import { FosscordServer } from "./Server"; import cluster from "cluster"; import os from "os"; -var cores = 1; +let cores = 1; try { cores = Number(process.env.THREADS) || os.cpus().length; } catch { @@ -41,16 +41,17 @@ if (cluster.isPrimary && process.env.NODE_ENV == "production") { cluster.fork(); } - cluster.on("exit", (worker, code, signal) => { + cluster.on("exit", (worker) => { console.log(`worker ${worker.process.pid} died, restart worker`); cluster.fork(); }); } else { - var port = Number(process.env.PORT) || 3001; + const port = Number(process.env.PORT) || 3001; const server = new FosscordServer({ port }); server.start().catch(console.error); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore global.server = server; } diff --git a/src/api/util/handlers/Instance.ts b/src/api/util/handlers/Instance.ts index acac1fb8..08157208 100644 --- a/src/api/util/handlers/Instance.ts +++ b/src/api/util/handlers/Instance.ts @@ -16,7 +16,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -import { Config, Guild, Session } from "@fosscord/util"; +import { Session } from "@fosscord/util"; export async function initInstance() { // TODO: clean up database and delete tombstone data @@ -24,15 +24,14 @@ export async function initInstance() { // create default guild and add it to auto join // TODO: check if any current user is not part of autoJoinGuilds - const { autoJoin } = Config.get().guild; + // const { autoJoin } = Config.get().guild; - if (autoJoin.enabled && !autoJoin.guilds?.length) { - let guild = await Guild.findOne({ where: {}, select: ["id"] }); - if (guild) { - // @ts-ignore - await Config.set({ guild: { autoJoin: { guilds: [guild.id] } } }); - } - } + // if (autoJoin.enabled && !autoJoin.guilds?.length) { + // const guild = await Guild.findOne({ where: {}, select: ["id"] }); + // if (guild) { + // await Config.set({ guild: { autoJoin: { guilds: [guild.id] } } }); + // } + // } // TODO: do no clear sessions for instance cluster await Session.delete({}); diff --git a/src/api/util/handlers/Message.ts b/src/api/util/handlers/Message.ts index 2371358f..42325681 100644 --- a/src/api/util/handlers/Message.ts +++ b/src/api/util/handlers/Message.ts @@ -51,7 +51,7 @@ const allow_empty = false; // TODO: embed gifs/videos/images const LINK_REGEX = - /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/g; + /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/g; export async function handleMessage(opts: MessageOptions): Promise<Message> { const channel = await Channel.findOneOrFail({ @@ -129,7 +129,6 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> { } /** Q: should be checked if the referenced message exists? ANSWER: NO otherwise backfilling won't work **/ - // @ts-ignore message.type = MessageType.REPLY; } @@ -144,29 +143,29 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> { throw new HTTPError("Empty messages are not allowed", 50006); } - var content = opts.content; - var mention_channel_ids = [] as string[]; - var mention_role_ids = [] as string[]; - var mention_user_ids = [] as string[]; - var mention_everyone = false; + let content = opts.content; + const mention_channel_ids = [] as string[]; + const mention_role_ids = [] as string[]; + const mention_user_ids = [] as string[]; + let mention_everyone = false; if (content) { // TODO: explicit-only mentions message.content = content.trim(); - content = content.replace(/ *\`[^)]*\` */g, ""); // remove codeblocks - for (const [_, mention] of content.matchAll(CHANNEL_MENTION)) { + content = content.replace(/ *`[^)]*` */g, ""); // remove codeblocks + for (const [, mention] of content.matchAll(CHANNEL_MENTION)) { if (!mention_channel_ids.includes(mention)) mention_channel_ids.push(mention); } - for (const [_, mention] of content.matchAll(USER_MENTION)) { + for (const [, mention] of content.matchAll(USER_MENTION)) { if (!mention_user_ids.includes(mention)) mention_user_ids.push(mention); } await Promise.all( Array.from(content.matchAll(ROLE_MENTION)).map( - async ([_, mention]) => { + async ([, mention]) => { const role = await Role.findOneOrFail({ where: { id: mention, guild_id: channel.guild_id }, }); @@ -198,8 +197,8 @@ export async function handleMessage(opts: MessageOptions): Promise<Message> { // TODO: cache link result in db export async function postHandleMessage(message: Message) { - const content = message.content?.replace(/ *\`[^)]*\` */g, ""); // remove markdown - var links = content?.match(LINK_REGEX); + const content = message.content?.replace(/ *`[^)]*` */g, ""); // remove markdown + let links = content?.match(LINK_REGEX); if (!links) return; const data = { ...message }; @@ -232,8 +231,8 @@ export async function postHandleMessage(message: Message) { // tried to use shorthand but types didn't like me L if (!Array.isArray(res)) res = [res]; - for (var embed of res) { - var cache = EmbedCache.create({ + for (const embed of res) { + const cache = EmbedCache.create({ url: link, embed: embed, }); @@ -279,7 +278,10 @@ export async function sendMessage(opts: MessageOptions) { } as MessageCreateEvent), ]); - postHandleMessage(message).catch((e) => {}); // no await as it should catch error non-blockingly + // no await as it should catch error non-blockingly + postHandleMessage(message).catch((e) => + console.error("[Message] post-message handler failed", e), + ); return message; } diff --git a/src/api/util/handlers/Voice.ts b/src/api/util/handlers/Voice.ts index d8d5c279..24bfa7b3 100644 --- a/src/api/util/handlers/Voice.ts +++ b/src/api/util/handlers/Voice.ts @@ -31,7 +31,7 @@ export async function getVoiceRegions(ipAddress: string, vip: boolean) { let min = Number.POSITIVE_INFINITY; - for (let ar of availableRegions) { + for (const ar of availableRegions) { //TODO the endpoint location should be saved in the database if not already present to prevent IPAnalysis call const dist = distanceBetweenLocations( clientIpAnalysis, diff --git a/src/api/util/handlers/route.ts b/src/api/util/handlers/route.ts index 6fcc6c73..cb160637 100644 --- a/src/api/util/handlers/route.ts +++ b/src/api/util/handlers/route.ts @@ -34,6 +34,8 @@ import { NextFunction, Request, Response } from "express"; import { AnyValidateFunction } from "ajv/dist/core"; declare global { + // TODO: fix this + // eslint-disable-next-line @typescript-eslint/no-namespace namespace Express { interface Request { permission?: Permissions; @@ -53,7 +55,7 @@ export interface RouteOptions { body?: `${string}Schema`; // typescript interface name test?: { response?: RouteResponse; - body?: any; + body?: unknown; path?: string; event?: EVENT | EVENT[]; headers?: Record<string, string>; @@ -61,7 +63,7 @@ export interface RouteOptions { } export function route(opts: RouteOptions) { - var validate: AnyValidateFunction<any> | undefined; + let validate: AnyValidateFunction | undefined; if (opts.body) { validate = ajv.getSchema(opts.body); if (!validate) throw new Error(`Body schema ${opts.body} not found`); diff --git a/src/api/util/utility/EmbedHandlers.ts b/src/api/util/utility/EmbedHandlers.ts index 522ff82b..8466a374 100644 --- a/src/api/util/utility/EmbedHandlers.ts +++ b/src/api/util/utility/EmbedHandlers.ts @@ -17,13 +17,13 @@ */ import { Config, Embed, EmbedType } from "@fosscord/util"; -import fetch, { Response } from "node-fetch"; +import fetch, { RequestInit } from "node-fetch"; import * as cheerio from "cheerio"; import probe from "probe-image-size"; import crypto from "crypto"; import { yellow } from "picocolors"; -export const DEFAULT_FETCH_OPTIONS: any = { +export const DEFAULT_FETCH_OPTIONS: RequestInit = { redirect: "follow", follow: 1, headers: { @@ -50,7 +50,7 @@ export const getProxyUrl = ( // Imagor if (imagorServerUrl) { - let path = `${width}x${height}/${url.host}${url.pathname}`; + const path = `${width}x${height}/${url.host}${url.pathname}`; const hash = crypto .createHmac("sha1", secret) @@ -92,8 +92,8 @@ export const getMetaDescriptions = (text: string) => { image: getMeta($, "og:image") || getMeta($, "twitter:image"), image_fallback: $(`image`).attr("src"), video_fallback: $(`video`).attr("src"), - width: parseInt(getMeta($, "og:image:width")!) || 0, - height: parseInt(getMeta($, "og:image:height")!) || 0, + width: parseInt(getMeta($, "og:image:width") || "0"), + height: parseInt(getMeta($, "og:image:height") || "0"), url: getMeta($, "og:url"), youtube_embed: getMeta($, "og:video:secure_url"), }; @@ -192,8 +192,8 @@ export const EmbedHandlers: { proxy_url: metas.image ? getProxyUrl( new URL(metas.image), - metas.width!, - metas.height!, + metas.width, + metas.height, ) : undefined, }, @@ -239,9 +239,9 @@ export const EmbedHandlers: { const text = json.data.text; const created_at = new Date(json.data.created_at); const metrics = json.data.public_metrics; - let media = json.includes.media?.filter( - (x: any) => x.type == "photo", - ) as any[]; // TODO: video + const media = json.includes.media?.filter( + (x: { type: string }) => x.type == "photo", + ); const embed: Embed = { type: EmbedType.rich, @@ -334,7 +334,7 @@ export const EmbedHandlers: { width: 640, height: 640, proxy_url: metas.image - ? getProxyUrl(new URL(metas.image!), 640, 640) + ? getProxyUrl(new URL(metas.image), 640, 640) : undefined, url: metas.image, }, @@ -365,9 +365,9 @@ export const EmbedHandlers: { url: url.href, proxy_url: metas.image ? getProxyUrl( - new URL(metas.image!), - metas.width!, - metas.height!, + new URL(metas.image), + metas.width, + metas.height, ) : undefined, }, @@ -395,7 +395,7 @@ export const EmbedHandlers: { height: 215, url: metas.image, proxy_url: metas.image - ? getProxyUrl(new URL(metas.image!), 460, 215) + ? getProxyUrl(new URL(metas.image), 460, 215) : undefined, }, provider: { @@ -436,7 +436,7 @@ export const EmbedHandlers: { // TODO: does this adjust with aspect ratio? width: metas.width, height: metas.height, - url: metas.youtube_embed!, + url: metas.youtube_embed, }, url: url.href, type: EmbedType.video, @@ -447,9 +447,9 @@ export const EmbedHandlers: { url: metas.image, proxy_url: metas.image ? getProxyUrl( - new URL(metas.image!), - metas.width!, - metas.height!, + new URL(metas.image), + metas.width, + metas.height, ) : undefined, }, diff --git a/src/api/util/utility/RandomInviteID.ts b/src/api/util/utility/RandomInviteID.ts index e95b4d1d..7ce54ad2 100644 --- a/src/api/util/utility/RandomInviteID.ts +++ b/src/api/util/utility/RandomInviteID.ts @@ -24,7 +24,7 @@ import crypto from "crypto"; export function random(length = 6) { // Declare all characters - let chars = + const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; // Pick characers randomly @@ -38,14 +38,14 @@ export function random(length = 6) { export function snowflakeBasedInvite() { // Declare all characters - let chars = + const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - let base = BigInt(chars.length); + const base = BigInt(chars.length); let snowflake = Snowflake.generateWorkerProcess(); // snowflakes hold ~10.75 characters worth of entropy; // safe to generate a 8-char invite out of them - let str = ""; + const str = ""; for (let i = 0; i < 10; i++) { str.concat(chars.charAt(Number(snowflake % base))); snowflake = snowflake / base; diff --git a/src/api/util/utility/captcha.ts b/src/api/util/utility/captcha.ts index 2d31f891..bd05582f 100644 --- a/src/api/util/utility/captcha.ts +++ b/src/api/util/utility/captcha.ts @@ -47,7 +47,10 @@ export async function verifyCaptcha(response: string, ip?: string) { const { security } = Config.get(); const { service, secret, sitekey } = security.captcha; - if (!service) throw new Error("Cannot verify captcha without service"); + if (!service || !secret || !sitekey) + throw new Error( + "CAPTCHA is not configured correctly. https://docs.fosscord.com/setup/server/security/captcha/", + ); const res = await fetch(verifyEndpoints[service], { method: "POST", @@ -56,9 +59,9 @@ export async function verifyCaptcha(response: string, ip?: string) { }, body: `response=${encodeURIComponent(response)}` + - `&secret=${encodeURIComponent(secret!)}` + - `&sitekey=${encodeURIComponent(sitekey!)}` + - (ip ? `&remoteip=${encodeURIComponent(ip!)}` : ""), + `&secret=${encodeURIComponent(secret)}` + + `&sitekey=${encodeURIComponent(sitekey)}` + + (ip ? `&remoteip=${encodeURIComponent(ip)}` : ""), }); return (await res.json()) as hcaptchaResponse | recaptchaResponse; diff --git a/src/api/util/utility/ipAddress.ts b/src/api/util/utility/ipAddress.ts index 785844ce..71a48682 100644 --- a/src/api/util/utility/ipAddress.ts +++ b/src/api/util/utility/ipAddress.ts @@ -85,7 +85,7 @@ export async function IPAnalysis(ip: string): Promise<typeof exampleData> { return ( await fetch(`https://api.ipdata.co/${ip}?api-key=${ipdataApiKey}`) - ).json() as any; // TODO: types + ).json(); } export function isProxy(data: typeof exampleData) { @@ -97,14 +97,21 @@ export function isProxy(data: typeof exampleData) { } export function getIpAdress(req: Request): string { + // TODO: express can do this (trustProxies: true)? + return ( + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore req.headers[Config.get().security.forwadedFor] || req.socket.remoteAddress ); } -export function distanceBetweenLocations(loc1: any, loc2: any): number { +type Location = { latitude: number; longitude: number }; +export function distanceBetweenLocations( + loc1: Location, + loc2: Location, +): number { return distanceBetweenCoords( loc1.latitude, loc1.longitude, diff --git a/src/api/util/utility/passwordStrength.ts b/src/api/util/utility/passwordStrength.ts index c4dcd509..b293b856 100644 --- a/src/api/util/utility/passwordStrength.ts +++ b/src/api/util/utility/passwordStrength.ts @@ -23,7 +23,7 @@ const reNUMBER = /[0-9]/g; const reUPPERCASELETTER = /[A-Z]/g; const reSYMBOLS = /[A-Z,a-z,0-9]/g; -const blocklist: string[] = []; // TODO: update ones passwordblocklist is stored in db +// const blocklist: string[] = []; // TODO: update ones passwordblocklist is stored in db /* * https://en.wikipedia.org/wiki/Password_policy * password must meet following criteria, to be perfect: @@ -38,7 +38,7 @@ const blocklist: string[] = []; // TODO: update ones passwordblocklist is stored export function checkPassword(password: string): number { const { minLength, minNumbers, minUpperCase, minSymbols } = Config.get().register.password; - var strength = 0; + let strength = 0; // checks for total password len if (password.length >= minLength - 1) { @@ -68,13 +68,13 @@ export function checkPassword(password: string): number { strength = 0; } - let entropyMap: { [key: string]: number } = {}; + const entropyMap: { [key: string]: number } = {}; for (let i = 0; i < password.length; i++) { if (entropyMap[password[i]]) entropyMap[password[i]]++; else entropyMap[password[i]] = 1; } - let entropies = Object.values(entropyMap); + const entropies = Object.values(entropyMap); entropies.map((x) => x / entropyMap.length); strength += |