diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/api/routes/applications/#id/bot/index.ts | 113 | ||||
-rw-r--r-- | src/api/routes/applications/#id/index.ts | 51 | ||||
-rw-r--r-- | src/api/routes/applications/index.ts | 24 | ||||
-rw-r--r-- | src/util/entities/Application.ts | 1 | ||||
-rw-r--r-- | src/util/schemas/ApplicationCreateSchema.ts | 4 | ||||
-rw-r--r-- | src/util/schemas/ApplicationModifySchema.ts | 14 | ||||
-rw-r--r-- | src/util/schemas/BotModifySchema.ts | 4 | ||||
-rw-r--r-- | src/util/schemas/Validator.ts | 1 | ||||
-rw-r--r-- | src/util/schemas/index.ts | 5 |
9 files changed, 132 insertions, 85 deletions
diff --git a/src/api/routes/applications/#id/bot/index.ts b/src/api/routes/applications/#id/bot/index.ts index ad2399b8..ed5d6a70 100644 --- a/src/api/routes/applications/#id/bot/index.ts +++ b/src/api/routes/applications/#id/bot/index.ts @@ -1,81 +1,78 @@ import { Request, Response, Router } from "express"; import { route } from "@fosscord/api"; -import { Application, Config, FieldErrors, generateToken, OrmUtils, Snowflake, trimSpecial, User } from "@fosscord/util"; +import { Application, generateToken, User, BotModifySchema, handleFile, DiscordApiErrors } from "@fosscord/util"; import { HTTPError } from "lambert-server"; import { verifyToken } from "node-2fa"; const router: Router = Router(); router.post("/", route({}), async (req: Request, res: Response) => { - const app = await Application.findOne({where: {id: req.params.id}}); - if(!app) return res.status(404); - const username = trimSpecial(app.name); - const discriminator = await User.generateDiscriminator(username); - if (!discriminator) { - // We've failed to generate a valid and unused discriminator - throw FieldErrors({ - username: { - code: "USERNAME_TOO_MANY_USERS", - message: req?.t("auth:register.USERNAME_TOO_MANY_USERS"), - }, - }); - } - - const user = OrmUtils.mergeDeep(new User(), { - created_at: new Date(), - username: username, - discriminator, - id: app.id, - bot: true, - system: false, - premium_since: new Date(), - desktop: false, - mobile: false, - premium: true, - premium_type: 2, - bio: app.description, - mfa_enabled: false, - totp_secret: "", - totp_backup_codes: [], - verified: true, - disabled: false, - deleted: false, - email: null, - rights: Config.get().security.defaultRights, - nsfw_allowed: true, - public_flags: "0", - flags: "0", - data: { - hash: null, - valid_tokens_since: new Date(), - }, - settings: {}, - extended_settings: {}, - fingerprints: [], - notes: {}, + const app = await Application.findOneOrFail({ where: { id: req.params.id }, relations: ["owner"] }); + + if (app.owner.id != req.user_id) + throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION; + + const user = await User.register({ + username: app.name, + password: undefined, + req, }); + + user.id = app.id; + user.premium_since = new Date(); + user.bot = true; + await user.save(); - app.bot = user; + + // flags is NaN here? + app.assign({ bot: user, flags: app.flags || 0 }); + await app.save(); - res.send().status(204) + + res.send().status(204); }); router.post("/reset", route({}), async (req: Request, res: Response) => { - let bot = await User.findOne({where: {id: req.params.id}}); - let owner = await User.findOne({where: {id: req.user_id}}); - if(!bot) return res.status(404); - if(owner?.totp_secret && (!req.body.code || verifyToken(owner.totp_secret, req.body.code))) { + let bot = await User.findOneOrFail({ where: { id: req.params.id } }); + let owner = await User.findOneOrFail({ where: { id: req.user_id } }); + + if (owner.id != req.user_id) + throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION; + + if (owner.totp_secret && (!req.body.code || verifyToken(owner.totp_secret, req.body.code))) throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008); - } + bot.data = { hash: undefined, valid_tokens_since: new Date() }; + await bot.save(); + let token = await generateToken(bot.id); - res.json({token}).status(200); + + res.json({ token }).status(200); }); -router.patch("/", route({}), async (req: Request, res: Response) => { - delete req.body.avatar; - let app = OrmUtils.mergeDeep(await User.findOne({where: {id: req.params.id}}), req.body); +router.patch("/", route({ body: "BotModifySchema" }), async (req: Request, res: Response) => { + const body = req.body as BotModifySchema; + if (!body.avatar?.trim()) delete body.avatar; + + const app = await Application.findOneOrFail({ where: { id: req.params.id }, relations: ["bot", "owner"] }); + + if (!app.bot) + throw DiscordApiErrors.BOT_ONLY_ENDPOINT; + + if (app.owner.id != req.user_id) + throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION; + + if (body.avatar) + body.avatar = await handleFile( + `/avatars/${app.id}`, + body.avatar as string, + ); + + app.bot.assign(body); + + app.bot.save(); + await app.save(); res.json(app).status(200); }); diff --git a/src/api/routes/applications/#id/index.ts b/src/api/routes/applications/#id/index.ts index 0aced582..79df256a 100644 --- a/src/api/routes/applications/#id/index.ts +++ b/src/api/routes/applications/#id/index.ts @@ -1,28 +1,55 @@ import { Request, Response, Router } from "express"; import { route } from "@fosscord/api"; -import { Application, OrmUtils, Team, trimSpecial, User } from "@fosscord/util"; +import { Application, OrmUtils, DiscordApiErrors, ApplicationModifySchema, User } from "@fosscord/util"; +import { verifyToken } from "node-2fa"; +import { HTTPError } from "lambert-server"; const router: Router = Router(); router.get("/", route({}), async (req: Request, res: Response) => { - let results = await Application.findOne({where: {id: req.params.id}, relations: ["owner", "bot"] }); - res.json(results).status(200); + const app = await Application.findOneOrFail({ where: { id: req.params.id }, relations: ["owner", "bot"] }); + if (app.owner.id != req.user_id) + throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION; + + return res.json(app); }); -router.patch("/", route({}), async (req: Request, res: Response) => { - delete req.body.icon; - let app = OrmUtils.mergeDeep(await Application.findOne({where: {id: req.params.id}, relations: ["owner", "bot"]}), req.body); - if(app.bot) { - app.bot.bio = req.body.description - app.bot?.save(); +router.patch("/", route({ body: "ApplicationModifySchema" }), async (req: Request, res: Response) => { + const body = req.body as ApplicationModifySchema; + + const app = await Application.findOneOrFail({ where: { id: req.params.id }, relations: ["owner", "bot"] }); + + if (app.owner.id != req.user_id) + throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION; + + if (app.owner.totp_secret && (!req.body.code || verifyToken(app.owner.totp_secret, req.body.code))) + throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008); + + if (app.bot) { + app.bot.assign({ bio: body.description }); + await app.bot.save(); } - if(req.body.tags) app.tags = req.body.tags; + + app.assign(body); + await app.save(); - res.json(app).status(200); + + return res.json(app); }); router.post("/delete", route({}), async (req: Request, res: Response) => { - await Application.delete(req.params.id); + const app = await Application.findOneOrFail({ where: { id: req.params.id }, relations: ["bot", "owner"] }); + if (app.owner.id != req.user_id) + throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION; + + if (app.owner.totp_secret && (!req.body.code || verifyToken(app.owner.totp_secret, req.body.code))) + throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008); + + if (app.bot) + await User.delete({ id: app.bot.id }); + + await Application.delete({ id: app.id }); + res.send().status(200); }); diff --git a/src/api/routes/applications/index.ts b/src/api/routes/applications/index.ts index 41ce35b5..70af84e6 100644 --- a/src/api/routes/applications/index.ts +++ b/src/api/routes/applications/index.ts @@ -1,35 +1,31 @@ import { Request, Response, Router } from "express"; import { route } from "@fosscord/api"; -import { Application, OrmUtils, Team, trimSpecial, User } from "@fosscord/util"; +import { Application, ApplicationCreateSchema, trimSpecial, User } from "@fosscord/util"; const router: Router = Router(); -export interface ApplicationCreateSchema { - name: string; - team_id?: string | number; -} - router.get("/", route({}), async (req: Request, res: Response) => { - //TODO - let results = await Application.find({where: {owner: {id: req.user_id}}, relations: ["owner", "bot"] }); + let results = await Application.find({ where: { owner: { id: req.user_id } }, relations: ["owner", "bot"] }); res.json(results).status(200); }); -router.post("/", route({}), async (req: Request, res: Response) => { +router.post("/", route({ body: "ApplicationCreateSchema" }), async (req: Request, res: Response) => { const body = req.body as ApplicationCreateSchema; - const user = await User.findOne({where: {id: req.user_id}}) - if(!user) res.status(420); - let app = OrmUtils.mergeDeep(new Application(), { + const user = await User.findOneOrFail({ where: { id: req.user_id } }); + + const app = Application.create({ name: trimSpecial(body.name), description: "", bot_public: true, bot_require_code_grant: false, owner: user, verify_key: "IMPLEMENTME", - flags: "" + flags: 0, }); + await app.save(); - res.json(app).status(200); + + res.json(app); }); export default router; \ No newline at end of file diff --git a/src/util/entities/Application.ts b/src/util/entities/Application.ts index 28381579..861c5bdd 100644 --- a/src/util/entities/Application.ts +++ b/src/util/entities/Application.ts @@ -37,6 +37,7 @@ export class Application extends BaseClass { @ManyToOne(() => User) owner: User; + // TODO: enum this? https://discord.com/developers/docs/resources/application#application-object-application-flags @Column() flags: number = 0; diff --git a/src/util/schemas/ApplicationCreateSchema.ts b/src/util/schemas/ApplicationCreateSchema.ts new file mode 100644 index 00000000..6a021b46 --- /dev/null +++ b/src/util/schemas/ApplicationCreateSchema.ts @@ -0,0 +1,4 @@ +export interface ApplicationCreateSchema { + name: string; + team_id?: string | number; +} \ No newline at end of file diff --git a/src/util/schemas/ApplicationModifySchema.ts b/src/util/schemas/ApplicationModifySchema.ts new file mode 100644 index 00000000..ab23d57e --- /dev/null +++ b/src/util/schemas/ApplicationModifySchema.ts @@ -0,0 +1,14 @@ +export interface ApplicationModifySchema { + description?: string; + icon?: string; + interactions_endpoint_url?: string; + max_participants?: number | null; + name?: string; + privacy_policy_url?: string; + role_connections_verification_url?: string; + tags?: string[]; + terms_of_service_url?: string; + bot_public?: boolean; + bot_require_code_grant?: boolean; + flags?: number; +} \ No newline at end of file diff --git a/src/util/schemas/BotModifySchema.ts b/src/util/schemas/BotModifySchema.ts new file mode 100644 index 00000000..b801ab27 --- /dev/null +++ b/src/util/schemas/BotModifySchema.ts @@ -0,0 +1,4 @@ +export interface BotModifySchema { + avatar?: string; + username?: string; +} \ No newline at end of file diff --git a/src/util/schemas/Validator.ts b/src/util/schemas/Validator.ts index e85cdf7b..9b7f0eca 100644 --- a/src/util/schemas/Validator.ts +++ b/src/util/schemas/Validator.ts @@ -22,6 +22,7 @@ export const ajv = new Ajv({ messages: true, strict: true, strictRequired: true, + allowUnionTypes: true, }); addFormats(ajv); diff --git a/src/util/schemas/index.ts b/src/util/schemas/index.ts index 780022c6..58565496 100644 --- a/src/util/schemas/index.ts +++ b/src/util/schemas/index.ts @@ -45,4 +45,7 @@ export * from "./UserGuildSettingsSchema"; export * from "./GatewayPayloadSchema"; export * from "./RolePositionUpdateSchema"; export * from "./ChannelReorderSchema"; -export * from "./UserSettingsSchema"; \ No newline at end of file +export * from "./UserSettingsSchema"; +export * from "./BotModifySchema"; +export * from "./ApplicationModifySchema"; +export * from "./ApplicationCreateSchema"; \ No newline at end of file |