返回提交历史
Modified
config-vanilla.json
+1
-0
Modified
src/services/configService.ts
+1
-0
Modified
src/services/configWatcherService.ts
+13
-2
Modified
src/services/loginService.ts
+1
-1
Modified
src/services/webService.ts
+2
-0
Modified
src/services/wsService.ts
+42
-22
Modified
static/webui/script.js
+11
-1
Modified
static/webui/translations/de.js
+2
-0
Modified
static/webui/translations/en.js
+2
-0
Modified
static/webui/translations/es.js
+2
-0
Modified
static/webui/translations/fr.js
+2
-0
Modified
static/webui/translations/ru.js
+2
-0
Modified
static/webui/translations/uk.js
+2
-0
Modified
static/webui/translations/zh.js
+2
-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
代码差异
14 个文件
+85
-26
@@ -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": {
@@ -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?: {
@@ -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
});
@@ -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
@@ -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
}
@@ -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
};
@@ -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
}
@@ -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.`,
@@ -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.`,
@@ -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.`,
@@ -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.`,
@@ -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| уже занято.`,