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

chore: remove /custom/createAccount endpoint (#4107)

Not that it's an entirely useless endpoint, but way too much code for something no one was using. Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/4107 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>

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

代码差异

12 个文件 +40 -183
Modified src/controllers/api/loginController.ts +1 -1
@@ -7,6 +7,7 @@ import {
7 7 buildVersionToInt,
8 8 createAccount,
9 9 createNonce,
10 getGoogleAccountData,
10 11 getUsernameFromEmail,
11 12 isCorrectPassword
12 13 } from "../../services/loginService.ts";
@@ -25,7 +26,6 @@ import { fromStoreItem } from "../../services/itemDataService.ts";
25 26 import { getTokenForClient, getTunablesForClient } from "../../services/tunablesService.ts";
26 27 import type { AddressInfo } from "node:net";
27 28 import gameToBuildVersion from "../../constants/gameToBuildVersion.ts";
28 import { getGoogleAccountData } from "../../helpers/customHelpers/customHelpers.ts";
29 29 import { args } from "../../helpers/commandLineArguments.ts";
30 30
31 31 export const loginController: RequestHandler = async (request, response) => {
Modified src/controllers/api/setActiveShipController.ts +1 -4
@@ -1,15 +1,12 @@
1 1 import { getPersonalRooms } from "../../services/personalRoomsService.ts";
2 2 import { getAccountIdForRequest } from "../../services/loginService.ts";
3 import { parseString } from "../../helpers/general.ts";
4 3 import type { RequestHandler } from "express";
5 4 import { Types } from "mongoose";
6 5
7 6 export const setActiveShipController: RequestHandler = async (req, res) => {
8 7 const accountId = await getAccountIdForRequest(req);
9 const shipId = parseString(req.query.shipId);
10
11 8 const personalRooms = await getPersonalRooms(accountId);
12 personalRooms.activeShipId = new Types.ObjectId(shipId);
9 personalRooms.activeShipId = new Types.ObjectId(req.query.shipId as string);
13 10 await personalRooms.save();
14 11 res.status(200).end();
15 12 };
Modified src/controllers/api/signupAndroidController.ts +1 -1
@@ -1,6 +1,6 @@
1 1 import type { RequestHandler } from "express";
2 2 import { Account } from "../../models/loginModel.ts";
3 import { getGoogleAccountData } from "../../helpers/customHelpers/customHelpers.ts";
3 import { getGoogleAccountData } from "../../services/loginService.ts";
4 4
5 5 export const signupAndroidController: RequestHandler = async (request, res) => {
6 6 const googleTokenId = request.query.googleTokenId as string | undefined;
Deleted src/controllers/custom/createAccountController.ts +0 -16
@@ -1,16 +0,0 @@
1 import { toCreateAccount, toDatabaseAccount } from "../../helpers/customHelpers/customHelpers.ts";
2 import { createAccount, isNameTaken } from "../../services/loginService.ts";
3 import type { RequestHandler } from "express";
4
5 const createAccountController: RequestHandler = async (req, res) => {
6 const createAccountData = toCreateAccount(req.body);
7 if (await isNameTaken(createAccountData.DisplayName)) {
8 res.status(409).json("Name already in use");
9 } else {
10 const databaseAccount = toDatabaseAccount(createAccountData);
11 const account = await createAccount(databaseAccount);
12 res.json(account);
13 }
14 };
15
16 export { createAccountController };
Deleted src/helpers/customHelpers/customHelpers.ts +0 -74
@@ -1,74 +0,0 @@
1 import type { IAccountCreation, IAndroidAccount } from "../../types/customTypes.ts";
2 import type { IDatabaseAccountRequiredFields } from "../../types/loginTypes.ts";
3 import crypto from "crypto";
4 import { isString, parseEmail, parseString } from "../general.ts";
5 import { OAuth2Client } from "google-auth-library";
6
7 const getWhirlpoolHash = (rawPassword: string): string => {
8 const whirlpool = crypto.createHash("whirlpool");
9 const data = whirlpool.update(rawPassword, "utf8");
10 const hash = data.digest("hex");
11 return hash;
12 };
13
14 const getGoogleAccountData = async (googleTokenId: string | undefined): Promise<IAndroidAccount> => {
15 if (!googleTokenId) {
16 throw new Error("google token is missing");
17 }
18 const client = new OAuth2Client();
19 const ticket = await client.verifyIdToken({
20 idToken: googleTokenId
21 });
22
23 const payload = ticket.getPayload();
24 if (!payload) {
25 throw new Error("payload missing, perhaps invalid google token");
26 }
27
28 return { userId: payload["sub"], email: payload["email"] };
29 };
30
31 const parsePassword = (passwordCandidate: unknown): string => {
32 // a different function could be called that checks whether the password has a certain shape
33 if (!isString(passwordCandidate)) {
34 throw new Error("incorrect password format");
35 }
36 return passwordCandidate;
37 };
38
39 const toAccountCreation = (accountCreation: unknown): IAccountCreation => {
40 if (!accountCreation || typeof accountCreation !== "object") {
41 throw new Error("incorrect or missing account creation data");
42 }
43
44 if (
45 "email" in accountCreation &&
46 "password" in accountCreation &&
47 "DisplayName" in accountCreation &&
48 "CountryCode" in accountCreation
49 ) {
50 const rawPassword = parsePassword(accountCreation.password);
51 return {
52 email: parseEmail(accountCreation.email),
53 password: getWhirlpoolHash(rawPassword),
54 CountryCode: parseString(accountCreation.CountryCode),
55 DisplayName: parseString(accountCreation.DisplayName)
56 };
57 }
58 throw new Error("incorrect account creation data: incorrect properties");
59 };
60
61 const toDatabaseAccount = (createAccount: IAccountCreation): IDatabaseAccountRequiredFields => {
62 return {
63 ...createAccount,
64 ClientType: "",
65 ConsentNeeded: false,
66 CrossPlatformAllowed: true,
67 ForceLogoutVersion: 0,
68 TrackedSettings: [],
69 Nonce: 0,
70 LastLogin: new Date()
71 } satisfies IDatabaseAccountRequiredFields;
72 };
73
74 export { toDatabaseAccount, toAccountCreation as toCreateAccount, getGoogleAccountData };
Modified src/helpers/general.ts +1 -66
@@ -2,74 +2,9 @@ export const isEmptyObject = (obj: unknown): boolean => {
2 2 return Boolean(obj && Object.keys(obj).length === 0 && obj.constructor === Object);
3 3 };
4 4
5 /*
6 alternative to isEmptyObject
7 export const isEmptyObject = (obj: object): boolean => {
5 export const isObjectEmpty = (obj: object): boolean => {
8 6 return Object.keys(obj).length === 0;
9 7 };
10 */
11
12 export const isString = (text: unknown): text is string => {
13 return typeof text === "string" || text instanceof String;
14 };
15
16 export const parseString = (data: unknown): string => {
17 if (!isString(data)) {
18 throw new Error("data is not a string");
19 }
20
21 return data;
22 };
23
24 export const isNumber = (number: unknown): number is number => {
25 return typeof number === "number" && !isNaN(number);
26 };
27
28 export const parseNumber = (data: unknown): number => {
29 if (!isNumber(data)) {
30 throw new Error("data is not a number");
31 }
32
33 return Number(data);
34 };
35
36 export const isDate = (date: string): boolean => {
37 return Date.parse(date) != 0;
38 };
39
40 export const parseDateNumber = (date: unknown): string => {
41 if (!isString(date) || !isDate(date)) {
42 throw new Error("date could not be parsed");
43 }
44
45 return date;
46 };
47
48 export const parseEmail = (email: unknown): string => {
49 if (!isString(email)) {
50 throw new Error("incorrect email");
51 }
52 return email;
53 };
54
55 export const isBoolean = (booleanCandidate: unknown): booleanCandidate is boolean => {
56 return typeof booleanCandidate === "boolean";
57 };
58
59 export const parseBoolean = (booleanCandidate: unknown): boolean => {
60 if (!isBoolean(booleanCandidate)) {
61 throw new Error("argument was not a boolean");
62 }
63 return booleanCandidate;
64 };
65
66 export const isObject = (objectCandidate: unknown): objectCandidate is Record<string, unknown> => {
67 return (
68 (typeof objectCandidate === "object" || objectCandidate instanceof Object) &&
69 objectCandidate !== null &&
70 !Array.isArray(objectCandidate)
71 );
72 };
73 8
74 9 export const lerp = (v0: number, v1: number, t: number): number => {
75 10 return v0 + t * (v1 - v0);
Modified src/routes/custom.ts +0 -2
@@ -33,7 +33,6 @@ import { retroactivelyApplyGuildCheatController } from "../controllers/custom/re
33 33 import { getRegisteredLosersController } from "../controllers/custom/getRegisteredLosersController.ts";
34 34
35 35 import { abilityOverrideController } from "../controllers/custom/abilityOverrideController.ts";
36 import { createAccountController } from "../controllers/custom/createAccountController.ts";
37 36 import { createMessageController } from "../controllers/custom/createMessageController.ts";
38 37 import { addCurrencyController } from "../controllers/custom/addCurrencyController.ts";
39 38 import { addItemsController } from "../controllers/custom/addItemsController.ts";
@@ -92,7 +91,6 @@ customRouter.get("/retroactivelyApplyGuildCheat", retroactivelyApplyGuildCheatCo
92 91 customRouter.get("/getRegisteredLosers", getRegisteredLosersController);
93 92
94 93 customRouter.post("/abilityOverride", abilityOverrideController);
95 customRouter.post("/createAccount", createAccountController);
96 94 customRouter.post("/createMessage", createMessageController);
97 95 customRouter.post("/addCurrency", addCurrencyController);
98 96 customRouter.post("/addItems", addItemsController);
Modified src/services/loginService.ts +25 -2
@@ -1,6 +1,11 @@
1 1 import { Account } from "../models/loginModel.ts";
2 2 import { createInventory } from "./inventoryService.ts";
3 import { Platform, type IDatabaseAccountJson, type IDatabaseAccountRequiredFields } from "../types/loginTypes.ts";
3 import {
4 Platform,
5 type IAndroidAccount,
6 type IDatabaseAccountJson,
7 type IAccountCreationData
8 } from "../types/loginTypes.ts";
4 9 import { createShip } from "./shipService.ts";
5 10 import type { Document, Types } from "mongoose";
6 11 import { Loadout, type TLoadoutDatabaseDocument } from "../models/inventoryModels/loadoutModel.ts";
@@ -13,6 +18,7 @@ import crypto from "node:crypto";
13 18 import { logger } from "../utils/logger.ts";
14 19 import { version_compare } from "../helpers/inventoryHelpers.ts";
15 20 import gameToBuildVersion from "../constants/gameToBuildVersion.ts";
21 import { OAuth2Client } from "google-auth-library";
16 22
17 23 export const isCorrectPassword = (requestPassword: string, databasePassword: string): boolean => {
18 24 return requestPassword === databasePassword;
@@ -39,7 +45,7 @@ export const getUsernameFromEmail = async (email: string): Promise<string> => {
39 45 return name;
40 46 };
41 47
42 export const createAccount = async (accountData: IDatabaseAccountRequiredFields): Promise<IDatabaseAccountJson> => {
48 export const createAccount = async (accountData: IAccountCreationData): Promise<IDatabaseAccountJson> => {
43 49 if (accountData.DisplayName == "all") {
44 50 throw new Error(`"${accountData.DisplayName}" is reserved and may not be used as a username`);
45 51 }
@@ -170,6 +176,23 @@ export const hasPermission = (account: Pick<TAccountDocument, "DisplayName">, pe
170 176 return true;
171 177 };
172 178
179 export const getGoogleAccountData = async (googleTokenId: string | undefined): Promise<IAndroidAccount> => {
180 if (!googleTokenId) {
181 throw new Error("google token is missing");
182 }
183 const client = new OAuth2Client();
184 const ticket = await client.verifyIdToken({
185 idToken: googleTokenId
186 });
187
188 const payload = ticket.getPayload();
189 if (!payload) {
190 throw new Error("payload missing, perhaps invalid google token");
191 }
192
193 return { userId: payload["sub"], email: payload["email"] };
194 };
195
173 196 export const getOriginalPlatform = (account: TAccountDocument): number => {
174 197 return account.GoogleTokenId ? Platform.Android : Platform.Windows;
175 198 };
Modified src/services/questService.ts +2 -2
@@ -1,5 +1,5 @@
1 1 import type { IKeyChainRequest } from "../types/requestTypes.ts";
2 import { isEmptyObject } from "../helpers/general.ts";
2 import { isObjectEmpty } from "../helpers/general.ts";
3 3 import type { TInventoryDatabaseDocument } from "../models/inventoryModels/inventoryModel.ts";
4 4 import { createMessage } from "./inboxService.ts";
5 5 import {
@@ -371,7 +371,7 @@ export const giveKeyChainItem = async (
371 371 if (!questKey.Progress?.[keyChainInfo.ChainStage]?.i) {
372 372 inventoryChanges = await addKeyChainItems(inventory, keyChainInfo, buildLabel);
373 373
374 if (isEmptyObject(inventoryChanges)) {
374 if (isObjectEmpty(inventoryChanges)) {
375 375 logger.warn("inventory changes was empty after getting keychain items: should not happen");
376 376 }
377 377 // items were added: update quest stage's i (item was given)
Modified src/services/saveLoadoutService.ts +2 -2
@@ -11,7 +11,7 @@ import { Loadout } from "../models/inventoryModels/loadoutModel.ts";
11 11 import { addMods, getInventory } from "./inventoryService.ts";
12 12 import type { IOidWithLegacySupport } from "../types/commonTypes.ts";
13 13 import { Types } from "mongoose";
14 import { isEmptyObject } from "../helpers/general.ts";
14 import { isEmptyObject, isObjectEmpty } from "../helpers/general.ts";
15 15 import { convertLegacyColorsToIColor, fromOid, toObjectId, version_compare } from "../helpers/inventoryHelpers.ts";
16 16 import { logger } from "../utils/logger.ts";
17 17 import type { ISketch, TEquipmentKey } from "../types/inventoryTypes/inventoryTypes.ts";
@@ -99,7 +99,7 @@ export const handleInventoryItemConfigChange = async (
99 99 const newLoadout = _loadout as ILoadoutEntry;
100 100
101 101 // empty loadout slot like: "NORMAL": {}
102 if (isEmptyObject(newLoadout)) {
102 if (isObjectEmpty(newLoadout)) {
103 103 continue;
104 104 }
105 105
Deleted src/types/customTypes.ts +0 -11
@@ -1,11 +0,0 @@
1 export interface IAccountCreation {
2 email: string;
3 password: string;
4 DisplayName: string;
5 CountryCode: string;
6 }
7
8 export interface IAndroidAccount {
9 email?: string;
10 userId: string;
11 }
Modified src/types/loginTypes.ts +7 -2
@@ -21,7 +21,7 @@ export interface IAccountAndLoginResponseCommons {
21 21 Nonce: number;
22 22 }
23 23
24 export interface IDatabaseAccountRequiredFields extends IAccountAndLoginResponseCommons {
24 export interface IAccountCreationData extends IAccountAndLoginResponseCommons {
25 25 email: string;
26 26 password: string;
27 27 Language?: string;
@@ -29,7 +29,7 @@ export interface IDatabaseAccountRequiredFields extends IAccountAndLoginResponse
29 29 LastLogin: Date;
30 30 }
31 31
32 export interface IDatabaseAccount extends IDatabaseAccountRequiredFields {
32 export interface IDatabaseAccount extends IAccountCreationData {
33 33 LastPlatform?: Platform;
34 34 Dropped?: true;
35 35 LatestEventMessageDate: Date;
@@ -90,3 +90,8 @@ export interface IIgnore {
90 90 ignorer: Types.ObjectId;
91 91 ignoree: Types.ObjectId;
92 92 }
93
94 export interface IAndroidAccount {
95 email?: string;
96 userId: string;
97 }