applications

This commit is contained in:
Puyodead1 2023-03-23 11:01:38 -04:00
parent a567ca3f51
commit 3335f16ad1
No known key found for this signature in database
GPG Key ID: A4FA4FEC0DD353FC
13 changed files with 45342 additions and 98 deletions

File diff suppressed because it is too large Load Diff

View File

@ -16,78 +16,114 @@
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import { Request, Response, Router } from "express";
import { route } from "@spacebar/api"; import { route } from "@spacebar/api";
import { import {
Application, Application,
generateToken,
User,
BotModifySchema, BotModifySchema,
handleFile,
DiscordApiErrors, DiscordApiErrors,
User,
generateToken,
handleFile,
} from "@spacebar/util"; } from "@spacebar/util";
import { Request, Response, Router } from "express";
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(
const app = await Application.findOneOrFail({ "/",
where: { id: req.params.id }, route({
relations: ["owner"], responses: {
}); 200: {
body: "TokenResponse",
},
400: {
body: "APIErrorResponse",
},
},
}),
async (req: Request, res: Response) => {
const app = await Application.findOneOrFail({
where: { id: req.params.id },
relations: ["owner"],
});
if (app.owner.id != req.user_id) if (app.owner.id != req.user_id)
throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION; throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION;
const user = await User.register({ const user = await User.register({
username: app.name, username: app.name,
password: undefined, password: undefined,
id: app.id, id: app.id,
req, req,
}); });
user.id = app.id; user.id = app.id;
user.premium_since = new Date(); user.premium_since = new Date();
user.bot = true; user.bot = true;
await user.save(); await user.save();
// flags is NaN here? // flags is NaN here?
app.assign({ bot: user, flags: app.flags || 0 }); app.assign({ bot: user, flags: app.flags || 0 });
await app.save(); await app.save();
res.send({ res.send({
token: await generateToken(user.id), token: await generateToken(user.id),
}).status(204); }).status(204);
}); },
);
router.post("/reset", route({}), async (req: Request, res: Response) => { router.post(
const bot = await User.findOneOrFail({ where: { id: req.params.id } }); "/reset",
const owner = await User.findOneOrFail({ where: { id: req.user_id } }); route({
responses: {
200: {
body: "TokenResponse",
},
400: {
body: "APIErrorResponse",
},
},
}),
async (req: Request, res: Response) => {
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) if (owner.id != req.user_id)
throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION; throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION;
if ( if (
owner.totp_secret && owner.totp_secret &&
(!req.body.code || verifyToken(owner.totp_secret, req.body.code)) (!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();
const token = await generateToken(bot.id); const token = await generateToken(bot.id);
res.json({ token }).status(200); res.json({ token }).status(200);
}); },
);
router.patch( router.patch(
"/", "/",
route({ body: "BotModifySchema" }), route({
body: "BotModifySchema",
responses: {
200: {
body: "Application",
},
400: {
body: "APIErrorResponse",
},
},
}),
async (req: Request, res: Response) => { async (req: Request, res: Response) => {
const body = req.body as BotModifySchema; const body = req.body as BotModifySchema;
if (!body.avatar?.trim()) delete body.avatar; if (!body.avatar?.trim()) delete body.avatar;

View File

@ -16,15 +16,25 @@
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import { Router, Response, Request } from "express";
import { route } from "@spacebar/api"; import { route } from "@spacebar/api";
import { Request, Response, Router } from "express";
const router = Router(); const router = Router();
router.get("/", route({}), (req: Request, res: Response) => { router.get(
// TODO: "/",
//const { exclude_consumed } = req.query; route({
res.status(200).send([]); responses: {
}); 200: {
body: "ApplicationEntitlementsResponse",
},
},
}),
(req: Request, res: Response) => {
// TODO:
//const { exclude_consumed } = req.query;
res.status(200).send([]);
},
);
export default router; export default router;

View File

@ -16,32 +16,55 @@
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import { Request, Response, Router } from "express";
import { route } from "@spacebar/api"; import { route } from "@spacebar/api";
import { import {
Application, Application,
DiscordApiErrors,
ApplicationModifySchema, ApplicationModifySchema,
DiscordApiErrors,
} from "@spacebar/util"; } from "@spacebar/util";
import { verifyToken } from "node-2fa"; import { Request, Response, Router } from "express";
import { HTTPError } from "lambert-server"; import { HTTPError } from "lambert-server";
import { verifyToken } from "node-2fa";
const router: Router = Router(); const router: Router = Router();
router.get("/", route({}), async (req: Request, res: Response) => { router.get(
const app = await Application.findOneOrFail({ "/",
where: { id: req.params.id }, route({
relations: ["owner", "bot"], responses: {
}); 200: {
if (app.owner.id != req.user_id) body: "Application",
throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION; },
400: {
body: "APIErrorResponse",
},
},
}),
async (req: Request, res: Response) => {
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); return res.json(app);
}); },
);
router.patch( router.patch(
"/", "/",
route({ body: "ApplicationModifySchema" }), route({
body: "ApplicationModifySchema",
responses: {
200: {
body: "Application",
},
400: {
body: "APIErrorResponse",
},
},
}),
async (req: Request, res: Response) => { async (req: Request, res: Response) => {
const body = req.body as ApplicationModifySchema; const body = req.body as ApplicationModifySchema;
@ -73,23 +96,35 @@ router.patch(
}, },
); );
router.post("/delete", route({}), async (req: Request, res: Response) => { router.post(
const app = await Application.findOneOrFail({ "/delete",
where: { id: req.params.id }, route({
relations: ["bot", "owner"], responses: {
}); 200: {},
if (app.owner.id != req.user_id) 400: {
throw DiscordApiErrors.ACTION_NOT_AUTHORIZED_ON_APPLICATION; body: "APIErrorResponse",
},
},
}),
async (req: Request, res: Response) => {
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 ( if (
app.owner.totp_secret && app.owner.totp_secret &&
(!req.body.code || verifyToken(app.owner.totp_secret, req.body.code)) (!req.body.code ||
) verifyToken(app.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);
await Application.delete({ id: app.id }); await Application.delete({ id: app.id });
res.send().status(200); res.send().status(200);
}); },
);
export default router; export default router;

View File

@ -16,13 +16,23 @@
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import { Request, Response, Router } from "express";
import { route } from "@spacebar/api"; import { route } from "@spacebar/api";
import { Request, Response, Router } from "express";
const router: Router = Router(); const router: Router = Router();
router.get("/", route({}), async (req: Request, res: Response) => { router.get(
res.json([]).status(200); "/",
}); route({
responses: {
200: {
body: "ApplicationSkusResponse",
},
},
}),
async (req: Request, res: Response) => {
res.json([]).status(200);
},
);
export default router; export default router;

View File

@ -16,14 +16,24 @@
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import { Request, Response, Router } from "express";
import { route } from "@spacebar/api"; import { route } from "@spacebar/api";
import { Request, Response, Router } from "express";
const router: Router = Router(); const router: Router = Router();
router.get("/", route({}), async (req: Request, res: Response) => { router.get(
//TODO "/",
res.send([]).status(200); route({
}); responses: {
200: {
body: "ApplicationDetectableResponse",
},
},
}),
async (req: Request, res: Response) => {
//TODO
res.send([]).status(200);
},
);
export default router; export default router;

View File

@ -16,28 +16,45 @@
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import { Request, Response, Router } from "express";
import { route } from "@spacebar/api"; import { route } from "@spacebar/api";
import { import {
Application, Application,
ApplicationCreateSchema, ApplicationCreateSchema,
trimSpecial,
User, User,
trimSpecial,
} from "@spacebar/util"; } from "@spacebar/util";
import { Request, Response, Router } from "express";
const router: Router = Router(); const router: Router = Router();
router.get("/", route({}), async (req: Request, res: Response) => { router.get(
const results = await Application.find({ "/",
where: { owner: { id: req.user_id } }, route({
relations: ["owner", "bot"], responses: {
}); 200: {
res.json(results).status(200); body: "ApplicationsResponse",
}); },
},
}),
async (req: Request, res: Response) => {
const results = await Application.find({
where: { owner: { id: req.user_id } },
relations: ["owner", "bot"],
});
res.json(results).status(200);
},
);
router.post( router.post(
"/", "/",
route({ body: "ApplicationCreateSchema" }), route({
body: "ApplicationCreateSchema",
responses: {
200: {
body: "Application",
},
},
}),
async (req: Request, res: Response) => { async (req: Request, res: Response) => {
const body = req.body as ApplicationCreateSchema; const body = req.body as ApplicationCreateSchema;
const user = await User.findOneOrFail({ where: { id: req.user_id } }); const user = await User.findOneOrFail({ where: { id: req.user_id } });

View File

@ -55,7 +55,8 @@ export interface RouteOptions {
body?: `${string}Schema`; // typescript interface name body?: `${string}Schema`; // typescript interface name
responses?: { responses?: {
[status: number]: { [status: number]: {
body?: `${string}Response`; // body?: `${string}Response`;
body?: string;
}; };
}; };
test?: { test?: {

View File

@ -0,0 +1 @@
export type ApplicationDetectableResponse = unknown[];

View File

@ -0,0 +1 @@
export type ApplicationEntitlementsResponse = unknown[];

View File

@ -0,0 +1 @@
export type ApplicationSkusResponse = unknown[];

View File

@ -0,0 +1,3 @@
import { Application } from "../../entities";
export type ApplicationsResponse = Application[];

View File

@ -1,5 +1,9 @@
export * from "./APIErrorOrCaptchaResponse"; export * from "./APIErrorOrCaptchaResponse";
export * from "./APIErrorResponse"; export * from "./APIErrorResponse";
export * from "./ApplicationDetectableResponse";
export * from "./ApplicationEntitlementsResponse";
export * from "./ApplicationSkusResponse";
export * from "./ApplicationsResponse";
export * from "./BackupCodesChallengeResponse"; export * from "./BackupCodesChallengeResponse";
export * from "./CaptchaRequiredResponse"; export * from "./CaptchaRequiredResponse";
export * from "./GenerateRegistrationTokensResponse"; export * from "./GenerateRegistrationTokensResponse";