diff options
author | ChrisChrome <christophercookman@gmail.com> | 2022-08-10 02:53:29 -0600 |
---|---|---|
committer | Madeline <46743919+MaddyUnderStars@users.noreply.github.com> | 2022-12-18 22:40:25 +1100 |
commit | 245127f65129455c7ec3d3860150c42160cc0e8d (patch) | |
tree | 0ebe91d0cad9383b3a2e47cb1bee148332ffcdf6 | |
parent | Remove some old test logs that expose info to console (diff) | |
download | server-245127f65129455c7ec3d3860150c42160cc0e8d.tar.xz |
Add basic developer panel functionality - doesn't work yet
> > > Co-authored-by: TheArcaneBrony <myrainbowdash949@gmail.com>
-rw-r--r-- | .gitignore | 7 | ||||
-rw-r--r-- | assets/client_test/developers.html | 12 | ||||
-rw-r--r-- | src/api/routes/applications/#id/bot/index.ts | 83 | ||||
-rw-r--r-- | src/api/routes/applications/#id/index.ts | 27 | ||||
-rw-r--r-- | src/api/routes/applications/#id/skus.ts | 11 | ||||
-rw-r--r-- | src/api/routes/applications/index.ts | 28 | ||||
-rw-r--r-- | src/gateway/opcodes/Identify.ts | 2 | ||||
-rw-r--r-- | src/util/entities/Application.ts | 114 | ||||
-rw-r--r-- | src/util/entities/User.ts | 4 | ||||
-rw-r--r-- | src/util/interfaces/Event.ts | 2 |
10 files changed, 242 insertions, 48 deletions
diff --git a/.gitignore b/.gitignore index c7f0d81b..4d1a7a01 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,9 @@ config.json .vscode/settings.json -build \ No newline at end of file +build + +*.log +*.log.ansi +*.tmp +tmp/ diff --git a/assets/client_test/developers.html b/assets/client_test/developers.html index 85bbba05..fbe0193c 100644 --- a/assets/client_test/developers.html +++ b/assets/client_test/developers.html @@ -7,7 +7,7 @@ <link rel="stylesheet" href="/assets/532.03aaeef88460fae60534.css" integrity="" /> <link rel="icon" href="/assets/07dca80a102d4149e9736d4b162cff6f.ico" /> - <title>Developer Portal | Fosscord</title> + <title>Discord Test Client Developer Portal</title> <meta charset="utf-8" data-react-helmet="true" /> </head> @@ -29,15 +29,15 @@ GLOBAL_ENV.MEDIA_PROXY_ENDPOINT = location.protocol + "//" + GLOBAL_ENV.CDN_HOST; // TODO: remote auth // window.GLOBAL_ENV.REMOTE_AUTH_ENDPOINT = window.GLOBAL_ENV.GATEWAY_ENDPOINT.replace(/wss?:/, ""); - window.localStorage.setItem("gatewayURL", window.GLOBAL_ENV.GATEWAY_ENDPOINT); - window.localStorage.setItem( + localStorage.setItem("gatewayURL", window.GLOBAL_ENV.GATEWAY_ENDPOINT); + localStorage.setItem( "DeveloperOptionsStore", `{"trace":false,"canary":false,"logGatewayEvents":true,"logOverlayEvents":true,"logAnalyticsEvents":true,"sourceMapsEnabled":false,"axeEnabled":false}` ); </script> - <script src="/assets/41fde19fdf180f3d4315.js" integrity=""></script> - <script src="/assets/7b04a3ab10e05dd9054e.js" integrity=""></script> - <script src="/assets/d1f811da193e5648048b.js" integrity=""></script> + <script src="/assets/38f40c32d3c8a2fdf73b.js" integrity=""></script> + <script src="/assets/aa190934324e05fcc35c.js" integrity=""></script> + <script src="/assets/45664a0209e828a528b4.js" integrity=""></script> </body> </html> \ No newline at end of file diff --git a/src/api/routes/applications/#id/bot/index.ts b/src/api/routes/applications/#id/bot/index.ts new file mode 100644 index 00000000..80907940 --- /dev/null +++ b/src/api/routes/applications/#id/bot/index.ts @@ -0,0 +1,83 @@ +import { Request, Response, Router } from "express"; +import { route } from "@fosscord/api"; +import { Application, Config, FieldErrors, generateToken, OrmUtils, Snowflake, trimSpecial, User } 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: {}, + }); + await user.save(); + app.bot = user; + await app.save(); + 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))) { + 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); +}); + +router.patch("/", route({}), async (req: Request, res: Response) => { + delete req.body.icon; + let app = OrmUtils.mergeDeep(await User.findOne({where: {id: req.params.id}}), req.body); + await app.save(); + res.json(app).status(200); +}); + +export default router; \ No newline at end of file diff --git a/src/api/routes/applications/#id/index.ts b/src/api/routes/applications/#id/index.ts new file mode 100644 index 00000000..be8c3ba4 --- /dev/null +++ b/src/api/routes/applications/#id/index.ts @@ -0,0 +1,27 @@ +import { Request, Response, Router } from "express"; +import { route } from "@fosscord/api"; +import { Application, OrmUtils, Team, trimSpecial, User } from "@fosscord/util"; + +const router: Router = Router(); + +router.get("/", route({}), async (req: Request, res: Response) => { + //TODO + let results = await Application.findOne({where: {id: req.params.id}, relations: ["owner", "bot"] }); + //debugger; + res.json(results).status(200); +}); + +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(); + } + if(req.body.tags) app.tags = req.body.tags; + await app.save(); + debugger; + res.json(app).status(200); +}); + +export default router; \ No newline at end of file diff --git a/src/api/routes/applications/#id/skus.ts b/src/api/routes/applications/#id/skus.ts new file mode 100644 index 00000000..5b667f36 --- /dev/null +++ b/src/api/routes/applications/#id/skus.ts @@ -0,0 +1,11 @@ +import { Request, Response, Router } from "express"; +import { route } from "@fosscord/api"; +import { Application, OrmUtils, Team, trimSpecial, User } from "@fosscord/util"; + +const router: Router = Router(); + +router.get("/", route({}), async (req: Request, res: Response) => { + res.json([]).status(200); +}); + +export default router; \ No newline at end of file diff --git a/src/api/routes/applications/index.ts b/src/api/routes/applications/index.ts index 28ce42da..c9be1131 100644 --- a/src/api/routes/applications/index.ts +++ b/src/api/routes/applications/index.ts @@ -1,11 +1,35 @@ import { Request, Response, Router } from "express"; import { route } from "@fosscord/api"; +import { Application, OrmUtils, Team, 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 - res.send([]).status(200); + let results = await Application.find({where: {owner: {id: req.user_id}}, relations: ["owner"] }); + res.json(results).status(200); +}); + +router.post("/", route({}), 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(), { + name: trimSpecial(body.name), + description: "", + bot_public: true, + bot_require_code_grant: false, + owner: user, + verify_key: "IMPLEMENTME", + flags: "" + }); + await app.save(); + res.json(app).status(200); }); -export default router; +export default router; \ No newline at end of file diff --git a/src/gateway/opcodes/Identify.ts b/src/gateway/opcodes/Identify.ts index fab4e375..fc183286 100644 --- a/src/gateway/opcodes/Identify.ts +++ b/src/gateway/opcodes/Identify.ts @@ -251,7 +251,7 @@ export async function onIdentify(this: WebSocket, data: Payload) { const d: ReadyEventData = { v: 8, - application: application ?? undefined, + application: { id: application?.id ?? '', flags: application?.flags ?? 0 }, //TODO: check this code! user: privateUser, user_settings: user.settings, // @ts-ignore diff --git a/src/util/entities/Application.ts b/src/util/entities/Application.ts index fab3d93f..28381579 100644 --- a/src/util/entities/Application.ts +++ b/src/util/entities/Application.ts @@ -1,4 +1,4 @@ -import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; +import { Column, Entity, JoinColumn, ManyToOne, OneToOne, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; import { Team } from "./Team"; @@ -8,21 +8,77 @@ import { User } from "./User"; export class Application extends BaseClass { @Column() name: string; - + @Column({ nullable: true }) icon?: string; - - @Column() + + @Column({ nullable: true }) description: string; - - @Column({ type: "simple-array", nullable: true }) - rpc_origins?: string[]; - + + @Column({ nullable: true }) + summary: string = ""; + + @Column({ type: "simple-json", nullable: true }) + type?: any; + @Column() - bot_public: boolean; - + hook: boolean = true; + + @Column() + bot_public?: boolean = true; + + @Column() + bot_require_code_grant?: boolean = false; + @Column() - bot_require_code_grant: boolean; + verify_key: string; + + @JoinColumn({ name: "owner_id" }) + @ManyToOne(() => User) + owner: User; + + @Column() + flags: number = 0; + + @Column({ type: "simple-array", nullable: true }) + redirect_uris: string[] = []; + + @Column({ nullable: true }) + rpc_application_state: number = 0; + + @Column({ nullable: true }) + store_application_state: number = 1; + + @Column({ nullable: true }) + verification_state: number = 1; + + @Column({ nullable: true }) + interactions_endpoint_url?: string; + + @Column({ nullable: true }) + integration_public: boolean = true; + + @Column({ nullable: true }) + integration_require_code_grant: boolean = false; + + @Column({ nullable: true }) + discoverability_state: number = 1; + + @Column({ nullable: true }) + discovery_eligibility_flags: number = 2240; + + @JoinColumn({ name: "bot_user_id" }) + @OneToOne(() => User) + bot?: User; + + @Column({ type: "simple-array", nullable: true }) + tags?: string[]; + + @Column({ nullable: true }) + cover_image?: string; // the application's default rich presence invite cover image hash + + @Column({ type: "simple-json", nullable: true }) + install_params?: {scopes: string[], permissions: string}; @Column({ nullable: true }) terms_of_service_url?: string; @@ -30,15 +86,20 @@ export class Application extends BaseClass { @Column({ nullable: true }) privacy_policy_url?: string; - @JoinColumn({ name: "owner_id" }) - @ManyToOne(() => User) - owner?: User; + //just for us - @Column({ nullable: true }) - summary?: string; + //@Column({ type: "simple-array", nullable: true }) + //rpc_origins?: string[]; + + //@JoinColumn({ name: "guild_id" }) + //@ManyToOne(() => Guild) + //guild?: Guild; // if this application is a game sold, this field will be the guild to which it has been linked - @Column() - verify_key: string; + //@Column({ nullable: true }) + //primary_sku_id?: string; // if this application is a game sold, this field will be the id of the "Game SKU" that is created, + + //@Column({ nullable: true }) + //slug?: string; // if this application is a game sold, this field will be the URL slug that links to the store page @JoinColumn({ name: "team_id" }) @ManyToOne(() => Team, { @@ -46,22 +107,7 @@ export class Application extends BaseClass { }) team?: Team; - @JoinColumn({ name: "guild_id" }) - @ManyToOne(() => Guild) - guild: Guild; // if this application is a game sold, this field will be the guild to which it has been linked - - @Column({ nullable: true }) - primary_sku_id?: string; // if this application is a game sold, this field will be the id of the "Game SKU" that is created, - - @Column({ nullable: true }) - slug?: string; // if this application is a game sold, this field will be the URL slug that links to the store page - - @Column({ nullable: true }) - cover_image?: string; // the application's default rich presence invite cover image hash - - @Column() - flags: string; // the application's public flags -} + } export interface ApplicationCommand { id: string; diff --git a/src/util/entities/User.ts b/src/util/entities/User.ts index 138d94a1..577e13f7 100644 --- a/src/util/entities/User.ts +++ b/src/util/entities/User.ts @@ -253,9 +253,7 @@ export class User extends BaseClass { }); } - private static async generateDiscriminator( - username: string, - ): Promise<string | undefined> { + public static async generateDiscriminator(username: string): Promise<string | undefined> { if (Config.get().register.incrementingDiscriminators) { // discriminator will be incrementally generated diff --git a/src/util/interfaces/Event.ts b/src/util/interfaces/Event.ts index 5e474d9e..36eedbfc 100644 --- a/src/util/interfaces/Event.ts +++ b/src/util/interfaces/Event.ts @@ -100,7 +100,7 @@ export interface ReadyEventData { }; application?: { id: string; - flags: string; + flags: number; }; merged_members?: PublicMember[][]; // probably all users who the user is in contact with |