mirror of
https://github.com/spacebarchat/server.git
synced 2024-11-26 04:03:03 +01:00
Refactor applications
This commit is contained in:
parent
b9bd5c5ac4
commit
970e67fe65
@ -18,7 +18,7 @@
|
|||||||
API_VERSION: 9,
|
API_VERSION: 9,
|
||||||
API_ENDPOINT: "/api",
|
API_ENDPOINT: "/api",
|
||||||
WEBAPP_ENDPOINT: "",
|
WEBAPP_ENDPOINT: "",
|
||||||
CDN_HOST: `${location.hostname}:3003`,
|
CDN_HOST: `${location.host}`, // TODO: make this file auto populate from config?
|
||||||
|
|
||||||
BRAINTREE_KEY: "production_5st77rrc_49pp2rp4phym7387",
|
BRAINTREE_KEY: "production_5st77rrc_49pp2rp4phym7387",
|
||||||
STRIPE_KEY: "pk_live_CUQtlpQUF0vufWpnpUmQvcdi",
|
STRIPE_KEY: "pk_live_CUQtlpQUF0vufWpnpUmQvcdi",
|
||||||
|
1569
assets/schemas.json
1569
assets/schemas.json
File diff suppressed because it is too large
Load Diff
@ -1,81 +1,78 @@
|
|||||||
import { Request, Response, Router } from "express";
|
import { Request, Response, Router } from "express";
|
||||||
import { route } from "@fosscord/api";
|
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 { HTTPError } from "lambert-server";
|
||||||
import { verifyToken } from "node-2fa";
|
import { verifyToken } from "node-2fa";
|
||||||
|
|
||||||
const router: Router = Router();
|
const router: Router = Router();
|
||||||
|
|
||||||
router.post("/", route({}), async (req: Request, res: Response) => {
|
router.post("/", route({}), async (req: Request, res: Response) => {
|
||||||
const app = await Application.findOne({where: {id: req.params.id}});
|
const app = await Application.findOneOrFail({ where: { id: req.params.id }, relations: ["owner"] });
|
||||||
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(), {
|
if (app.owner.id != req.user_id)
|
||||||
created_at: new Date(),
|
throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION;
|
||||||
username: username,
|
|
||||||
discriminator,
|
const user = await User.register({
|
||||||
id: app.id,
|
username: app.name,
|
||||||
bot: true,
|
password: undefined,
|
||||||
system: false,
|
req,
|
||||||
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: {},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
user.id = app.id;
|
||||||
|
user.premium_since = new Date();
|
||||||
|
user.bot = true;
|
||||||
|
|
||||||
await user.save();
|
await user.save();
|
||||||
app.bot = user;
|
|
||||||
|
// flags is NaN here?
|
||||||
|
app.assign({ bot: user, flags: app.flags || 0 });
|
||||||
|
|
||||||
await app.save();
|
await app.save();
|
||||||
res.send().status(204)
|
|
||||||
|
res.send().status(204);
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post("/reset", route({}), async (req: Request, res: Response) => {
|
router.post("/reset", route({}), async (req: Request, res: Response) => {
|
||||||
let bot = await User.findOne({where: {id: req.params.id}});
|
let bot = await User.findOneOrFail({ where: { id: req.params.id } });
|
||||||
let owner = await User.findOne({where: {id: req.user_id}});
|
let owner = await User.findOneOrFail({ 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))) {
|
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);
|
throw new HTTPError(req.t("auth:login.INVALID_TOTP_CODE"), 60008);
|
||||||
}
|
|
||||||
bot.data = { hash: undefined, valid_tokens_since: new Date() };
|
bot.data = { hash: undefined, valid_tokens_since: new Date() };
|
||||||
|
|
||||||
await bot.save();
|
await bot.save();
|
||||||
|
|
||||||
let token = await generateToken(bot.id);
|
let token = await generateToken(bot.id);
|
||||||
res.json({token}).status(200);
|
|
||||||
|
res.json({ token }).status(200);
|
||||||
});
|
});
|
||||||
|
|
||||||
router.patch("/", route({}), async (req: Request, res: Response) => {
|
router.patch("/", route({ body: "BotModifySchema" }), async (req: Request, res: Response) => {
|
||||||
delete req.body.avatar;
|
const body = req.body as BotModifySchema;
|
||||||
let app = OrmUtils.mergeDeep(await User.findOne({where: {id: req.params.id}}), req.body);
|
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();
|
await app.save();
|
||||||
res.json(app).status(200);
|
res.json(app).status(200);
|
||||||
});
|
});
|
||||||
|
@ -1,28 +1,55 @@
|
|||||||
import { Request, Response, Router } from "express";
|
import { Request, Response, Router } from "express";
|
||||||
import { route } from "@fosscord/api";
|
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();
|
const router: Router = Router();
|
||||||
|
|
||||||
router.get("/", route({}), async (req: Request, res: Response) => {
|
router.get("/", route({}), async (req: Request, res: Response) => {
|
||||||
let results = await Application.findOne({where: {id: req.params.id}, relations: ["owner", "bot"] });
|
const app = await Application.findOneOrFail({ where: { id: req.params.id }, relations: ["owner", "bot"] });
|
||||||
res.json(results).status(200);
|
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) => {
|
router.patch("/", route({ body: "ApplicationModifySchema" }), async (req: Request, res: Response) => {
|
||||||
delete req.body.icon;
|
const body = req.body as ApplicationModifySchema;
|
||||||
let app = OrmUtils.mergeDeep(await Application.findOne({where: {id: req.params.id}, relations: ["owner", "bot"]}), req.body);
|
|
||||||
if(app.bot) {
|
const app = await Application.findOneOrFail({ where: { id: req.params.id }, relations: ["owner", "bot"] });
|
||||||
app.bot.bio = req.body.description
|
|
||||||
app.bot?.save();
|
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();
|
await app.save();
|
||||||
res.json(app).status(200);
|
|
||||||
|
return res.json(app);
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post("/delete", route({}), async (req: Request, res: Response) => {
|
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);
|
res.send().status(200);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,35 +1,31 @@
|
|||||||
import { Request, Response, Router } from "express";
|
import { Request, Response, Router } from "express";
|
||||||
import { route } from "@fosscord/api";
|
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();
|
const router: Router = Router();
|
||||||
|
|
||||||
export interface ApplicationCreateSchema {
|
|
||||||
name: string;
|
|
||||||
team_id?: string | number;
|
|
||||||
}
|
|
||||||
|
|
||||||
router.get("/", route({}), async (req: Request, res: Response) => {
|
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);
|
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 body = req.body as ApplicationCreateSchema;
|
||||||
const user = await User.findOne({where: {id: req.user_id}})
|
const user = await User.findOneOrFail({ where: { id: req.user_id } });
|
||||||
if(!user) res.status(420);
|
|
||||||
let app = OrmUtils.mergeDeep(new Application(), {
|
const app = Application.create({
|
||||||
name: trimSpecial(body.name),
|
name: trimSpecial(body.name),
|
||||||
description: "",
|
description: "",
|
||||||
bot_public: true,
|
bot_public: true,
|
||||||
bot_require_code_grant: false,
|
bot_require_code_grant: false,
|
||||||
owner: user,
|
owner: user,
|
||||||
verify_key: "IMPLEMENTME",
|
verify_key: "IMPLEMENTME",
|
||||||
flags: ""
|
flags: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
await app.save();
|
await app.save();
|
||||||
res.json(app).status(200);
|
|
||||||
|
res.json(app);
|
||||||
});
|
});
|
||||||
|
|
||||||
export default router;
|
export default router;
|
@ -37,6 +37,7 @@ export class Application extends BaseClass {
|
|||||||
@ManyToOne(() => User)
|
@ManyToOne(() => User)
|
||||||
owner: User;
|
owner: User;
|
||||||
|
|
||||||
|
// TODO: enum this? https://discord.com/developers/docs/resources/application#application-object-application-flags
|
||||||
@Column()
|
@Column()
|
||||||
flags: number = 0;
|
flags: number = 0;
|
||||||
|
|
||||||
|
4
src/util/schemas/ApplicationCreateSchema.ts
Normal file
4
src/util/schemas/ApplicationCreateSchema.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export interface ApplicationCreateSchema {
|
||||||
|
name: string;
|
||||||
|
team_id?: string | number;
|
||||||
|
}
|
14
src/util/schemas/ApplicationModifySchema.ts
Normal file
14
src/util/schemas/ApplicationModifySchema.ts
Normal file
@ -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;
|
||||||
|
}
|
4
src/util/schemas/BotModifySchema.ts
Normal file
4
src/util/schemas/BotModifySchema.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export interface BotModifySchema {
|
||||||
|
avatar?: string;
|
||||||
|
username?: string;
|
||||||
|
}
|
@ -22,6 +22,7 @@ export const ajv = new Ajv({
|
|||||||
messages: true,
|
messages: true,
|
||||||
strict: true,
|
strict: true,
|
||||||
strictRequired: true,
|
strictRequired: true,
|
||||||
|
allowUnionTypes: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
addFormats(ajv);
|
addFormats(ajv);
|
||||||
|
@ -45,4 +45,7 @@ export * from "./UserGuildSettingsSchema";
|
|||||||
export * from "./GatewayPayloadSchema";
|
export * from "./GatewayPayloadSchema";
|
||||||
export * from "./RolePositionUpdateSchema";
|
export * from "./RolePositionUpdateSchema";
|
||||||
export * from "./ChannelReorderSchema";
|
export * from "./ChannelReorderSchema";
|
||||||
export * from "./UserSettingsSchema";
|
export * from "./UserSettingsSchema";
|
||||||
|
export * from "./BotModifySchema";
|
||||||
|
export * from "./ApplicationModifySchema";
|
||||||
|
export * from "./ApplicationCreateSchema";
|
Loading…
Reference in New Issue
Block a user