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

XFESpaceNinjaServer

A simple server for a small space ninja game

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

XFEstudio/XFESpaceNinjaServer

feat: webui.adminOnly (#3727)

Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/3727 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>

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

代码差异

14 个文件 +85 -26
Modified config-vanilla.json +1 -0
@@ -30,6 +30,7 @@
30 30 "skipClanKeyCrafting": false,
31 31 "webui": {
32 32 "enabled": true,
33 "adminOnly": false,
33 34 "defaultLanguage": "en"
34 35 },
35 36 "unfaithfulBugFixes": {
Modified src/services/configService.ts +1 -0
@@ -41,6 +41,7 @@ export interface IConfig {
41 41 skipClanKeyCrafting?: boolean;
42 42 webui?: {
43 43 enabled?: boolean;
44 adminOnly?: boolean;
44 45 defaultLanguage?: string;
45 46 };
46 47 unfaithfulBugFixes?: {
Modified src/services/configWatcherService.ts +13 -2
@@ -12,7 +12,13 @@ import {
12 12 } from "./configService.ts";
13 13 import { saveConfig, shouldReloadConfig } from "./configWriterService.ts";
14 14 import { startWebServer, stopWebServer } from "./webService.ts";
15 import { forEachWsClient, sendWsBroadcast, type IWsMsgToClient } from "./wsService.ts";
15 import {
16 bootNonAdminsFromWebui,
17 forEachWsClient,
18 sendWsBroadcast,
19 sendWsBroadcastToWebui,
20 type IWsMsgToClient
21 } from "./wsService.ts";
16 22 import varzia from "../constants/varzia.ts";
17 23 import { getTunablesForClient } from "./tunablesService.ts";
18 24
@@ -58,7 +64,12 @@ chokidar.watch(configPath).on("change", () => {
58 64 }
59 65 });
60 66 } else {
61 sendWsBroadcast({ config_reloaded: true });
67 sendWsBroadcastToWebui({ config_reloaded: true });
68 }
69
70 // Handle change to adminOnly or administratorNames
71 if (config.webui?.adminOnly) {
72 bootNonAdminsFromWebui();
62 73 }
63 74 }
64 75 });
Modified src/services/loginService.ts +1 -1
@@ -124,7 +124,7 @@ export const getAccountIdForRequest = async (req: Request): Promise<string> => {
124 124 return (await getAccountForRequest(req))._id.toString();
125 125 };
126 126
127 export const isAdministrator = (account: TAccountDocument): boolean => {
127 export const isAdministrator = (account: Pick<TAccountDocument, "DisplayName">): boolean => {
128 128 return config.administratorNames?.indexOf(account.DisplayName) != -1;
129 129 };
130 130
Modified src/services/webService.ts +2 -0
@@ -87,6 +87,7 @@ export const stopWebServer = async (): Promise<void> => {
87 87 httpServer!.close(() => {
88 88 resolve();
89 89 });
90 httpServer!.emit("close");
90 91 })
91 92 );
92 93 }
@@ -96,6 +97,7 @@ export const stopWebServer = async (): Promise<void> => {
96 97 httpsServer!.close(() => {
97 98 resolve();
98 99 });
100 httpsServer!.emit("close");
99 101 })
100 102 );
101 103 }
Modified src/services/wsService.ts +42 -22
@@ -8,6 +8,7 @@ import {
8 8 createNonce,
9 9 getAccountForQuery,
10 10 getUsernameFromEmail,
11 isAdministrator,
11 12 isCorrectPassword
12 13 } from "./loginService.ts";
13 14 import type { IDatabaseAccountJson } from "../types/loginTypes.ts";
@@ -38,6 +39,7 @@ export const stopWsServers = (promises: Promise<void>[]): void => {
38 39 wsServer!.close(() => {
39 40 resolve();
40 41 });
42 wsServer!.emit("close");
41 43 })
42 44 );
43 45 }
@@ -47,6 +49,7 @@ export const stopWsServers = (promises: Promise<void>[]): void => {
47 49 wssServer!.close(() => {
48 50 resolve();
49 51 });
52 wssServer!.emit("close");
50 53 })
51 54 );
52 55 }
@@ -83,23 +86,21 @@ interface IWsMsgFromClient {
83 86
84 87 export interface IWsMsgToClientCommon {
85 88 wsid?: number;
86 }
87
88 export interface IWsMsgToClientWebui {
89 reload?: boolean;
90 89 ports?: {
91 90 http: number | undefined;
92 91 https: number | undefined;
93 92 };
93 }
94
95 export interface IWsMsgToClientWebui extends IWsMsgToClientCommon {
96 reload?: boolean;
94 97 config_reloaded?: boolean;
95 98 auth_succ?: {
96 99 id: string;
97 100 DisplayName: string;
98 101 Nonce: number;
99 102 };
100 auth_fail?: {
101 isRegister: boolean;
102 };
103 auth_fail?: "bad login" | "bad register" | "admin only" | "registered but admin only";
103 104 nonce_updated?: boolean;
104 105 update_inventory?: boolean;
105 106 logged_out?: boolean;
@@ -107,13 +108,13 @@ export interface IWsMsgToClientWebui {
107 108 }
108 109
109 110 // specific to the bootstrapper (https://openwf.io/bootstrapper-manual)
110 export interface IWsMsgToClientGame {
111 export interface IWsMsgToClientGame extends IWsMsgToClientCommon {
111 112 sync_inventory?: boolean;
112 113 sync_world_state?: boolean;
113 114 tunables?: ITunables;
114 115 }
115 116
116 export type IWsMsgToClient = IWsMsgToClientCommon | IWsMsgToClientWebui | IWsMsgToClientGame;
117 export type IWsMsgToClient = IWsMsgToClientWebui | IWsMsgToClientGame;
117 118
118 119 const wsOnConnect = (ws: WebSocket, req: http.IncomingMessage): void => {
119 120 if (req.url == "/custom/selftest") {
@@ -157,22 +158,28 @@ const wsOnConnect = (ws: WebSocket, req: http.IncomingMessage): void => {
157 158 }
158 159 if (account) {
159 160 (ws as IWsCustomData).accountId = account.id;
160 ws.send(
161 JSON.stringify({
162 auth_succ: {
163 id: account.id,
164 DisplayName: account.DisplayName,
165 Nonce: account.Nonce
166 },
167 have_game_ws: haveGameWs(account.id)
168 } satisfies IWsMsgToClient)
169 );
161 if (!config.webui?.adminOnly || isAdministrator(account)) {
162 ws.send(
163 JSON.stringify({
164 auth_succ: {
165 id: account.id,
166 DisplayName: account.DisplayName,
167 Nonce: account.Nonce
168 },
169 have_game_ws: haveGameWs(account.id)
170 } satisfies IWsMsgToClient)
171 );
172 } else {
173 ws.send(
174 JSON.stringify({
175 auth_fail: data.auth.isRegister ? "registered but admin only" : "admin only"
176 } satisfies IWsMsgToClient)
177 );
178 }
170 179 } else {
171 180 ws.send(
172 181 JSON.stringify({
173 auth_fail: {
174 isRegister: data.auth.isRegister
175 }
182 auth_fail: data.auth.isRegister ? "bad register" : "bad login"
176 183 } satisfies IWsMsgToClient)
177 184 );
178 185 }
@@ -328,3 +335,16 @@ export const handleNonceInvalidation = (accountId: string): void => {
328 335 }
329 336 });
330 337 };
338
339 export const bootNonAdminsFromWebui = (): void => {
340 forEachWsClient(client => {
341 if (client.accountId && !client.isGame) {
342 void Account.findById(client.accountId).then(account => {
343 if (!account || !isAdministrator(account)) {
344 client.send(JSON.stringify({ logged_out: true } satisfies IWsMsgToClientWebui));
345 client.close();
346 }
347 });
348 }
349 });
350 };
Modified static/webui/script.js +11 -1
@@ -83,7 +83,17 @@ function openWebSocket() {
83 83 auth_pending = false;
84 84 logout();
85 85 if (single.getCurrentPath() == "/webui/") {
86 alert(loc(msg.auth_fail.isRegister ? "code_regFail" : "code_loginFail"));
86 if (msg.auth_fail == "bad login") {
87 alert(loc("code_loginFail"));
88 } else if (msg.auth_fail == "bad register") {
89 alert(loc("code_regFail"));
90 } else if (msg.auth_fail == "admin only") {
91 alert(loc("code_adminOnlyLogin"));
92 } else if (msg.auth_fail == "registered but admin only") {
93 alert(loc("code_adminOnlyRegister"));
94 } else {
95 alert(msg.auth_fail);
96 }
87 97 } else {
88 98 single.loadRoute("/webui/");
89 99 }
Modified static/webui/translations/de.js +2 -0
@@ -10,6 +10,8 @@ dict = {
10 10
11 11 code_loginFail: `Anmeldung fehlgeschlagen. Bitte überprüfe deine Angaben.`,
12 12 code_regFail: `Registrierung fehlgeschlagen. Account existiert bereits?`,
13 code_adminOnlyLogin: `[UNTRANSLATED] You are not allowed to login because the WebUI is admin-only on this instance.`,
14 code_adminOnlyRegister: `[UNTRANSLATED] Your account has successfully been created, but the WebUI is admin-only on this instance.`,
13 15 code_genFail: `Der Name darf nicht länger als 24 Zeichen sein.`,
14 16 code_changeNameConfirm: `In welchen Namen möchtest du deinen Account umbenennen?`,
15 17 code_changeNameRetry: `|NAME| ist bereits vergeben.`,
Modified static/webui/translations/en.js +2 -0
@@ -9,6 +9,8 @@ dict = {
9 9
10 10 code_loginFail: `Login failed. Double-check the email and password.`,
11 11 code_regFail: `Registration failed. Account already exists?`,
12 code_adminOnlyLogin: `You are not allowed to login because the WebUI is admin-only on this instance.`,
13 code_adminOnlyRegister: `Your account has successfully been created, but the WebUI is admin-only on this instance.`,
12 14 code_genFail: `Name cannot be longer than 24 characters.`,
13 15 code_changeNameConfirm: `What would you like to change your account name to?`,
14 16 code_changeNameRetry: `|NAME| is already taken.`,
Modified static/webui/translations/es.js +2 -0
@@ -10,6 +10,8 @@ dict = {
10 10
11 11 code_loginFail: `Error al iniciar sesión. Verifica el correo electrónico y la contraseña.`,
12 12 code_regFail: `Error al registrar la cuenta. ¿Ya existe una cuenta con este correo?`,
13 code_adminOnlyLogin: `[UNTRANSLATED] You are not allowed to login because the WebUI is admin-only on this instance.`,
14 code_adminOnlyRegister: `[UNTRANSLATED] Your account has successfully been created, but the WebUI is admin-only on this instance.`,
13 15 code_genFail: `[UNTRANSLATED] Name cannot be longer than 24 characters.`,
14 16 code_changeNameConfirm: `¿Qué nombre te gustaría ponerle a tu cuenta?`,
15 17 code_changeNameRetry: `|NAME| Ya está en uso.`,
Modified static/webui/translations/fr.js +2 -0
@@ -10,6 +10,8 @@ dict = {
10 10
11 11 code_loginFail: `Connexion échouée. Vérifiez le mot de passe.`,
12 12 code_regFail: `Enregistrement impossible. Compte existant?`,
13 code_adminOnlyLogin: `[UNTRANSLATED] You are not allowed to login because the WebUI is admin-only on this instance.`,
14 code_adminOnlyRegister: `[UNTRANSLATED] Your account has successfully been created, but the WebUI is admin-only on this instance.`,
13 15 code_genFail: `Le nom ne peut pas dépasser 24 caractères.`,
14 16 code_changeNameConfirm: `Nouveau nom du compte :`,
15 17 code_changeNameRetry: `|NAME| est déjà pris.`,
Modified static/webui/translations/ru.js +2 -0
@@ -10,6 +10,8 @@ dict = {
10 10
11 11 code_loginFail: `Не удалось войти. Проверьте адрес электронной почты и пароль.`,
12 12 code_regFail: `Не удалось зарегистрироваться. Учетная запись уже существует?`,
13 code_adminOnlyLogin: `[UNTRANSLATED] You are not allowed to login because the WebUI is admin-only on this instance.`,
14 code_adminOnlyRegister: `[UNTRANSLATED] Your account has successfully been created, but the WebUI is admin-only on this instance.`,
13 15 code_genFail: `Имя не может быть длиннее 24 символов.`,
14 16 code_changeNameConfirm: `Какое имя вы хотите установить для своей учетной записи?`,
15 17 code_changeNameRetry: `|NAME| уже занято.`,
Modified static/webui/translations/uk.js +2 -0
Modified static/webui/translations/zh.js +2 -0