* Reverted shutdown mechanism
* Socket authentication fix for Cloudflare users
- Cloudflare formats headers
* Steam auth verbose
* Upload artifacts to CDN and send Discord webhook link in #dev
This commit is contained in:
@@ -37,7 +37,7 @@ try {
|
||||
const data = Deno.readTextFileSync(`${RootPath}/res/words.json`);
|
||||
charades = JSON.parse(data);
|
||||
} catch (err) {
|
||||
log.e(`Could not read charades words config from disk!`);
|
||||
log.e(`Could not read charades words config from disk: ${(err as Error).message}`);
|
||||
}
|
||||
|
||||
export function getWords() {
|
||||
|
||||
@@ -15,7 +15,7 @@ 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/>. */
|
||||
|
||||
enum AvatarItemType {
|
||||
enum _AvatarItemType {
|
||||
None = -1,
|
||||
Hat,
|
||||
BackHead,
|
||||
|
||||
@@ -49,18 +49,29 @@ export async function AuthenticateUserTicket(ticket: string, userid: string) {
|
||||
params.append('appid', "471710");
|
||||
params.append('ticket', ticket);
|
||||
|
||||
const res = await fetch(`https://api.steampowered.com/ISteamUserAuth/AuthenticateUserTicket/v1?${params}`);
|
||||
const resjson = (await res.json()) as SteamRes;
|
||||
|
||||
if (resjson.response.error) {
|
||||
log.w(`Steam Authentication failed: (${resjson.response.error.errorcode}) ${resjson.response.error.errordesc}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
log.d(JSON.stringify(resjson.response));
|
||||
if (resjson.response.params) return resjson.response.params.steamid === userid && resjson.response.params.ownersteamid === userid;
|
||||
else {
|
||||
log.w("Steam Authentication failed: Steam response did not contain params or error! This should never be logged!");
|
||||
try {
|
||||
const res = await fetch(`https://api.steampowered.com/ISteamUserAuth/AuthenticateUserTicket/v1?${params}`);
|
||||
const resjson = (await res.json()) as SteamRes;
|
||||
|
||||
if (resjson.response.error) {
|
||||
log.w(`Steam Authentication failed: (${resjson.response.error.errorcode}) ${resjson.response.error.errordesc}`);
|
||||
|
||||
// add more error codes later if needed
|
||||
const conditions = [
|
||||
resjson.response.error.errorcode == 100
|
||||
].includes(true);
|
||||
if (conditions) log.w('This error indicates a client problem.');
|
||||
return false;
|
||||
}
|
||||
|
||||
log.d(JSON.stringify(resjson.response));
|
||||
if (resjson.response.params) return resjson.response.params.steamid === userid && resjson.response.params.ownersteamid === userid;
|
||||
else {
|
||||
log.w("Steam Authentication failed: Steam response did not contain params or error! This should never be logged!");
|
||||
return false;
|
||||
}
|
||||
} catch (err) {
|
||||
log.w(`Steam Authentication failed: ${(err as Error).message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
41
src/main.ts
41
src/main.ts
@@ -130,20 +130,32 @@ try {
|
||||
valid: false
|
||||
}
|
||||
type AuthResult = FailedAuth | SuccessfulAuth;
|
||||
// Please rewrite this for the love of God
|
||||
const authenticate = async (req: Request) => {
|
||||
const authHeader = req.headers.get('authorization');
|
||||
if (!authHeader) return { valid: false } as AuthResult;
|
||||
|
||||
//log.d(authHeader);
|
||||
const token = authHeader.split(", ")[1]; // Why is the header formatted like this?
|
||||
if (!token) return { valid: false } as AuthResult;
|
||||
const splitToken = token.split(' ')[1];
|
||||
if (!splitToken) return { valid: false } as AuthResult;
|
||||
let token: string | undefined;
|
||||
if (authHeader.substring(0, 6) === 'Bearer') {
|
||||
const splitToken = authHeader.split(' ');
|
||||
if (splitToken[1]) token = splitToken[1];
|
||||
}
|
||||
if (authHeader.includes(', ')) {
|
||||
const splitToken = authHeader.split(', ');
|
||||
if (splitToken[1]) token = splitToken[1];
|
||||
}
|
||||
|
||||
const decodedToken = await decode<ProfileTokenFormat>(splitToken, config.auth.secret, {algorithm: 'HS512'});
|
||||
const schemaResult = ProfileTokenSchema.safeParse(decodedToken);
|
||||
if (!schemaResult.success) return { valid: false } as AuthResult;
|
||||
else return { token: decodedToken, valid: true } as AuthResult;
|
||||
try {
|
||||
if (!token) throw new Error("No token provided");
|
||||
const decodedToken = await decode<ProfileTokenFormat>(token, config.auth.secret, {algorithm: 'HS512'});
|
||||
const schemaResult = ProfileTokenSchema.safeParse(decodedToken);
|
||||
if (!schemaResult.success) return { valid: false } as AuthResult;
|
||||
else return { token: decodedToken, valid: true } as AuthResult;
|
||||
} catch (err) {
|
||||
log.w(`Authentication failed`);
|
||||
log.w((err as Error).message);
|
||||
return { valid: false } as AuthResult;
|
||||
}
|
||||
}
|
||||
|
||||
const port = config.web.api.port;
|
||||
@@ -187,7 +199,7 @@ try {
|
||||
return response;
|
||||
|
||||
} else {
|
||||
log.e(`401 ${info.remoteAddr} ${req.method} ${req.url}`);
|
||||
log.e(`401 ${info.remoteAddr.hostname}:${info.remoteAddr.port} ${req.method} ${req.url}`);
|
||||
return new Response(null, { status: 401 });
|
||||
}
|
||||
|
||||
@@ -200,20 +212,19 @@ try {
|
||||
Deno.addSignalListener("SIGINT", () => {
|
||||
if (shuttingDown) return;
|
||||
shuttingDown = true;
|
||||
for (const handoff of SocketHandoff.all()) handoff.complete();
|
||||
for (const sock of UnifiedProfile.getAllSockets()) sock.sendNotification(PushNotificationId.ModerationQuitGame);
|
||||
});
|
||||
Deno.addSignalListener("SIGINT", () => {
|
||||
if (shuttingDown) return;
|
||||
log.i(`Shutting down`);
|
||||
|
||||
abort.abort(); // websockets
|
||||
http.close();
|
||||
http.closeAllConnections();
|
||||
});
|
||||
Deno.addSignalListener("SIGINT", () => {
|
||||
for (const socket of UnifiedProfile.getAllSockets()) socket.sendNotification(PushNotificationId.ModerationQuitGame); // untested
|
||||
});
|
||||
|
||||
if (!(await UnifiedProfile.existsByName("Coach"))) UnifiedProfile.create({ username: "Coach", id: 1 }); // create Coach id 1 if they do not exist
|
||||
if (!(await UnifiedProfile.existsByName("Server"))) UnifiedProfile.create({ username: "Server", id: 2 }); // create Server id 2 if they do not exist
|
||||
// use these later in development
|
||||
|
||||
if (!(await GameConfigs.getGameConfig('splitTestSoftOverrides'))) GameConfigs.setGameConfig('splitTestSoftOverrides', '');
|
||||
if (!(await GameConfigs.getGameConfig('splitTestHardOverrides'))) GameConfigs.setGameConfig('splitTestHardOverrides', '');
|
||||
|
||||
@@ -20,12 +20,9 @@ import express from "express";
|
||||
import UnifiedProfile, { Profile } from "../../data/profiles.ts";
|
||||
import { z } from "zod";
|
||||
import { AuthType } from "../../data/users.ts";
|
||||
import Logging from "@proxnet/undead-logging";
|
||||
|
||||
export const route = APIUtils.createRouter("/account");
|
||||
|
||||
const log = new Logging("AccountRoute");
|
||||
|
||||
const CreateAccountRequestBodySchema = z.object({
|
||||
platform: z.string(),
|
||||
platformId: z.string(),
|
||||
|
||||
@@ -58,7 +58,6 @@ route.router.post('/v1/cleargroup',
|
||||
APIUtils.Authentication,
|
||||
APIUtils.AuthenticationType(AuthType.Game),
|
||||
express.json(),
|
||||
APIUtils.logBody,
|
||||
APIUtils.validateRequestBody(ClearGroupRequestSchema),
|
||||
|
||||
(rq: express.Request<NoBody, NoBody, ClearGroupRequestBody>, rs: express.Response) => {
|
||||
|
||||
@@ -33,7 +33,6 @@ route.router.get('/v2',
|
||||
async (_rq, rs) => {
|
||||
|
||||
const settings = await rs.locals.profile.Settings.getSettings();
|
||||
log.d(`settings res: ${JSON.stringify(settings)}`);
|
||||
rs.json(settings);
|
||||
|
||||
}
|
||||
|
||||
@@ -108,7 +108,6 @@ route.router.post("/token",
|
||||
APIUtils.Authentication,
|
||||
APIUtils.AuthenticationType(AuthType.Web),
|
||||
express.urlencoded({ extended: true }),
|
||||
APIUtils.logBody,
|
||||
APIUtils.validateRequestBody<AuthBodyBase>(TokenRequestBodySchema),
|
||||
|
||||
async (
|
||||
|
||||
@@ -21,13 +21,10 @@ import express from "express";
|
||||
import Matchmaking from "../../data/live/base.ts";
|
||||
import Presence, { PresenceExport } from "../../data/live/presence.ts";
|
||||
import { AuthType } from "../../data/users.ts";
|
||||
import Logging from "@proxnet/undead-logging";
|
||||
import UnifiedProfile from "../../data/profiles.ts";
|
||||
import { PlayerStatusVisibility, VRMovementMode } from "../../data/live/types.ts";
|
||||
import { SettingKey } from "../../data/content/settings.ts";
|
||||
|
||||
const log = new Logging("MatchPlayerRoute");
|
||||
|
||||
export const route = APIUtils.createRouter('/player');
|
||||
|
||||
interface BaseLoginLock {
|
||||
@@ -57,7 +54,6 @@ route.router.get('/',
|
||||
}
|
||||
|
||||
rs.json(presExport);
|
||||
log.d(JSON.stringify(presExport));
|
||||
}
|
||||
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user