XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

SpaceNinjaServer

A simple server for a small space ninja game

公开
关注 0 Fork 1 Star 0
返回提交历史

XFEstudio/SpaceNinjaServer

feat: irc tokens (#3302)

Because the IRC connection is generally not secure (even over TLS), we don't wanna send the nonce over it, so... a token proves ownership of the accountId-nonce pair while being limited to 2 harmless endpoints. Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/3302 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>

b7d752f3
Sainan <63328889+Sainan@users.noreply.github.com>
提交于

代码差异

4 个文件 +26 -23
Modified src/controllers/custom/getAccountInfoController.ts +1 -1
@@ -4,7 +4,7 @@ import { getAccountForRequest, isAdministrator } from "../../services/loginServi
4 4 import type { RequestHandler } from "express";
5 5
6 6 export const getAccountInfoController: RequestHandler = async (req, res) => {
7 const account = await getAccountForRequest(req);
7 const account = await getAccountForRequest(req, true);
8 8 const inventory = await getInventory(account._id.toString(), "QuestKeys");
9 9 const info: IAccountInfo = {
10 10 DisplayName: account.DisplayName,
Modified src/controllers/custom/ircDroppedController.ts +4 -19
@@ -1,24 +1,9 @@
1 import { Account } from "../../models/loginModel.ts";
2 1 import type { RequestHandler } from "express";
2 import { getAccountForRequest } from "../../services/loginService.ts";
3 3
4 4 export const ircDroppedController: RequestHandler = async (req, res) => {
5 if (!req.query.accountId) {
6 throw new Error("Request is missing accountId parameter");
7 }
8 const nonce: number = parseInt(req.query.nonce as string);
9 if (!nonce) {
10 throw new Error("Request is missing nonce parameter");
11 }
12
13 await Account.updateOne(
14 {
15 _id: req.query.accountId,
16 Nonce: nonce
17 },
18 {
19 Dropped: true
20 }
21 );
22
5 const account = await getAccountForRequest(req, true);
6 account.Dropped = true;
7 await account.save();
23 8 res.end();
24 9 };
Modified src/middleware/errorHandler.ts +1 -1
@@ -2,7 +2,7 @@ import type { NextFunction, Request, Response } from "express";
2 2 import { logError } from "../utils/logger.ts";
3 3
4 4 export const errorHandler = (err: Error, req: Request, res: Response, _next: NextFunction): void => {
5 if (err.message == "Invalid accountId-nonce pair") {
5 if (err.message == "Invalid accountId-nonce pair" || err.message == "Invalid accountId-token pair") {
6 6 res.status(400).send("Log-in expired");
7 7 } else {
8 8 logError(err, `processing ${req.path} request`);
Modified src/services/loginService.ts +20 -2
@@ -9,6 +9,7 @@ import type { Request } from "express";
9 9 import { config } from "./configService.ts";
10 10 import { createStats } from "./statsService.ts";
11 11 import crc32 from "crc-32";
12 import crypto from "node:crypto";
12 13
13 14 export const isCorrectPassword = (requestPassword: string, databasePassword: string): boolean => {
14 15 return requestPassword === databasePassword;
@@ -71,15 +72,32 @@ export const createPersonalRooms = async (accountId: Types.ObjectId, shipId: Typ
71 72 export type TAccountDocument = Document<unknown, {}, IDatabaseAccountJson> &
72 73 IDatabaseAccountJson & { _id: Types.ObjectId; __v: number };
73 74
74 export const getAccountForRequest = async (req: Request): Promise<TAccountDocument> => {
75 export const getAccountForRequest = async (req: Request, acceptToken?: true): Promise<TAccountDocument> => {
75 76 if (!req.query.accountId) {
76 77 throw new Error("Request is missing accountId parameter");
77 78 }
79
80 // Tokens are specific to OpenWF to avoid sending the nonce (which gives full account access) over insecure transports.
81 if (acceptToken && req.query.token) {
82 const account = await Account.findById(req.query.accountId as string);
83 if (!account || !account.Nonce) {
84 throw new Error("Invalid accountId-token pair");
85 }
86 const token = crypto
87 .createHmac("sha256", account.Nonce.toString())
88 .update(`accountId=${req.query.accountId as string}&ct=${(req.query.ct as string | undefined) ?? ""}`)
89 .digest("hex");
90 //console.log(`expected token: ${token}`);
91 if ((req.query.token as string).toLowerCase() != token) {
92 throw new Error("Invalid accountId-token pair");
93 }
94 return account;
95 }
96
78 97 const nonce: number = parseInt(req.query.nonce as string);
79 98 if (!nonce) {
80 99 throw new Error("Request is missing nonce parameter");
81 100 }
82
83 101 const account = await Account.findById(req.query.accountId as string);
84 102 if (!account || account.Nonce != nonce) {
85 103 throw new Error("Invalid accountId-nonce pair");