All checks were successful
Galvanic Corrosion Cross-Compile / build (push) Successful in 57s
The Rewrite™️
- Discord bot removed, will return *eventually*
- Watchdog kills the server with a knife when it does not shut down in (default) 60 seconds
- New event system that works.. better.. and callbacks have types
- Removed a metric ton of circular dependencies that previously would not let the server start up
* This included splitting up some classes
- Other. internal stuff. I forgot.
158 lines
4.3 KiB
TypeScript
158 lines
4.3 KiB
TypeScript
/* Galvanic Corrosion - Rec Room custom server for communities.
|
|
<https://gitea.proxnet.dev/zombieb/galvanic-corrosion>
|
|
Copyright (C) 2025 @zombieb (Discord / proxnet Gitea)
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero General Public License as published
|
|
by the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|
|
|
import { APIUtils, NoBody } from "../../apiutils.ts";
|
|
import express from "express";
|
|
import { Profile } from "../../data/profile/base/profiles.ts";
|
|
import { z } from "zod";
|
|
import { AuthType } from "../../data/UserTypes.ts";
|
|
import Server from "../../data/server/server.ts";
|
|
|
|
export const route = APIUtils.createRouter("/account");
|
|
|
|
const CreateAccountRequestBodySchema = z.object({
|
|
platform: z.string(),
|
|
platformId: z.string(),
|
|
deviceId: z.string()
|
|
});
|
|
|
|
const rateLimit = new APIUtils.RateLimiter();
|
|
|
|
route.router.post("/create",
|
|
|
|
rateLimit.middle(),
|
|
APIUtils.Authentication,
|
|
express.urlencoded({ extended: true }),
|
|
APIUtils.validateRequestBody(CreateAccountRequestBodySchema),
|
|
|
|
async (_rq, rs) => {
|
|
const newAcc = await Profile.init();
|
|
if (newAcc == null) {
|
|
rs.json({
|
|
success: false
|
|
});
|
|
return;
|
|
}
|
|
|
|
rs.locals.user.addAssociatedProfile(newAcc.getId());
|
|
|
|
rs.json({
|
|
success: true,
|
|
value: await newAcc.export(),
|
|
});
|
|
},
|
|
|
|
);
|
|
|
|
route.router.get("/bulk",
|
|
|
|
rateLimit.middle(),
|
|
|
|
async (rq: express.Request, rs: express.Response) => {
|
|
|
|
if (typeof rq.query.id == "object") {
|
|
|
|
const ids = Object.values(rq.query.id).filter((val) => typeof val == "string").map((val) => parseInt(val, 10)).filter((val) => !isNaN(val));
|
|
rs.json([...await Profile.getExportAccountsBulk(ids)]);
|
|
|
|
} else if (typeof rq.query.id == "string") {
|
|
|
|
const id = parseInt(rq.query.id);
|
|
if (isNaN(id)) {
|
|
rs.json(APIUtils.genericResponseFormat(true, "Query data error"));
|
|
return;
|
|
} else {
|
|
rs.json([await Profile.getExportAccount(id)].filter((val) => val !== null));
|
|
return;
|
|
}
|
|
|
|
} else {
|
|
rs.json([]);
|
|
return;
|
|
}
|
|
|
|
},
|
|
);
|
|
|
|
route.router.get("/me",
|
|
|
|
APIUtils.Authentication,
|
|
|
|
async (_rq, rs) => {
|
|
|
|
const exportAccount = await rs.locals.profile.export();
|
|
if (exportAccount == null) rs.sendStatus(500);
|
|
else rs.json(exportAccount);
|
|
|
|
},
|
|
|
|
);
|
|
|
|
interface DisplayNameUpdate {
|
|
displayName: string
|
|
}
|
|
const DisplayNameUpdateSchema = z.object({
|
|
displayName: z.string().max(24, "DisplayName too long!")
|
|
})
|
|
route.router.put("/me/displayname",
|
|
|
|
APIUtils.Authentication,
|
|
APIUtils.AuthenticationType(AuthType.Game),
|
|
express.urlencoded({ extended: true }),
|
|
APIUtils.validateRequestBody(DisplayNameUpdateSchema),
|
|
|
|
(rq: express.Request<NoBody, NoBody, DisplayNameUpdate>, rs: express.Response, nxt: express.NextFunction) => {
|
|
rs.locals.profile.setDisplayName(rq.body.displayName);
|
|
nxt();
|
|
},
|
|
|
|
APIUtils.RecNetResponse(true, "Updated DisplayName.")
|
|
|
|
);
|
|
|
|
interface BioFetchParams {
|
|
id?: string
|
|
}
|
|
route.router.get('/:id/bio',
|
|
|
|
APIUtils.Authentication,
|
|
|
|
async (rq: express.Request<BioFetchParams>, rs: express.Response) => {
|
|
|
|
const unparsedId = rq.params.id;
|
|
if (!unparsedId) {
|
|
rs.sendStatus(500);
|
|
return;
|
|
}
|
|
const parsedId = parseInt(unparsedId);
|
|
if (isNaN(parsedId)) {
|
|
rs.sendStatus(400);
|
|
return;
|
|
}
|
|
const player = Server.UnifiedProfile.get(parsedId);
|
|
if (!player) {
|
|
rs.status(404).json(APIUtils.genericResponseFormat(true, "Profile not found"));
|
|
return;
|
|
}
|
|
|
|
rs.json({
|
|
accountId: parsedId,
|
|
bio: await player.getBio(),
|
|
});
|
|
}
|
|
|
|
); |