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): initial permission system (#3820)

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

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

代码差异

11 个文件 +224 -127
Modified config-vanilla.json +12 -0
@@ -31,6 +31,18 @@
31 31 "webui": {
32 32 "enabled": true,
33 33 "adminOnly": false,
34 "nonAdminPermissions": {
35 "*": true,
36 "addCredits": true,
37 "addPlatinum": true,
38 "addEndo": true,
39 "addRegalAya": true,
40 "import": true,
41 "toggleCheat": {
42 "*": true,
43 "skipAllDialogue": true
44 }
45 },
34 46 "defaultLanguage": "en"
35 47 },
36 48 "unfaithfulBugFixes": {
Modified src/controllers/custom/addCurrencyController.ts +14 -5
@@ -1,28 +1,30 @@
1 1 import type { RequestHandler } from "express";
2 import { getAccountIdForRequest } from "../../services/loginService.ts";
2 import { getAccountForRequest, hasPermission } from "../../services/loginService.ts";
3 3 import { addFusionPoints, getInventory } from "../../services/inventoryService.ts";
4 4 import { getGuildForRequestEx, hasGuildPermission } from "../../services/guildService.ts";
5 5 import { GuildPermission } from "../../types/guildTypes.ts";
6 6 import { broadcastInventoryUpdate } from "../../services/wsService.ts";
7 7
8 8 export const addCurrencyController: RequestHandler = async (req, res) => {
9 const accountId = await getAccountIdForRequest(req);
9 const account = await getAccountForRequest(req);
10 10 const request = req.body as IAddCurrencyRequest;
11 11 let projection = request.currency as string;
12 12 if (request.currency.startsWith("Vault")) projection = "GuildId";
13 const inventory = await getInventory(accountId, projection);
13 const inventory = await getInventory(account._id, projection);
14 14 if (request.currency == "FusionPoints") {
15 15 addFusionPoints(inventory, request.delta);
16 16 } else if (request.currency == "VaultRegularCredits" || request.currency == "VaultPremiumCredits") {
17 17 const guild = await getGuildForRequestEx(req, inventory);
18 if (await hasGuildPermission(guild, accountId, GuildPermission.Treasurer)) {
18 if (await hasGuildPermission(guild, account._id, GuildPermission.Treasurer)) {
19 19 guild[request.currency] ??= 0;
20 20 guild[request.currency]! += request.delta;
21 21 await guild.save();
22 22 res.json(guild[request.currency]);
23 23 }
24 24 } else {
25 inventory[request.currency] += request.delta;
25 if (hasPermission(account, currencyToPermission[request.currency])) {
26 inventory[request.currency] += request.delta;
27 }
26 28 }
27 29 if (!request.currency.startsWith("Vault")) {
28 30 await inventory.save();
@@ -41,3 +43,10 @@ interface IAddCurrencyRequest {
41 43 | "VaultPremiumCredits";
42 44 delta: number;
43 45 }
46
47 const currencyToPermission: Record<string, string> = {
48 RegularCredits: "addCredits",
49 PremiumCredits: "addPlatinum",
50 FusionPoints: "addEndo",
51 PrimeTokens: "addRegalAya"
52 };
Modified src/controllers/custom/addItemsController.ts +5 -1
@@ -1,4 +1,4 @@
1 import { getAccountForRequest } from "../../services/loginService.ts";
1 import { getAccountForRequest, hasPermission } from "../../services/loginService.ts";
2 2 import { getInventory, addItem } from "../../services/inventoryService.ts";
3 3 import type { RequestHandler } from "express";
4 4 import { broadcastInventoryUpdate } from "../../services/wsService.ts";
@@ -6,6 +6,10 @@ import { logger } from "../../utils/logger.ts";
6 6
7 7 export const addItemsController: RequestHandler = async (req, res) => {
8 8 const account = await getAccountForRequest(req);
9 if (!hasPermission(account, "addItems")) {
10 res.status(500).send(`Permission denied`).end();
11 return;
12 }
9 13 const requests = req.body as IAddItemRequest[];
10 14 const inventory = await getInventory(account._id);
11 15 for (const request of requests) {
Modified src/controllers/custom/configController.ts +1 -13
@@ -1,5 +1,5 @@
1 1 import type { RequestHandler } from "express";
2 import { config } from "../../services/configService.ts";
2 import { configIdToIndexable } from "../../services/configService.ts";
3 3 import { syncConfigWithDatabase } from "../../services/configWatcherService.ts";
4 4 import { getAccountForRequest, isAdministrator } from "../../services/loginService.ts";
5 5 import { saveConfig } from "../../services/configWriterService.ts";
@@ -37,15 +37,3 @@ export const setConfigController: RequestHandler = async (req, res) => {
37 37 res.status(401).end();
38 38 }
39 39 };
40
41 const configIdToIndexable = (id: string): [Record<string, boolean | string | number | undefined>, string] => {
42 let obj = config as unknown as Record<string, never>;
43 const arr = id.split(".");
44 while (arr.length > 1) {
45 // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
46 obj[arr[0]] ??= {} as never;
47 obj = obj[arr[0]];
48 arr.splice(0, 1);
49 }
50 return [obj, arr[0]];
51 };
Modified src/controllers/custom/importController.ts +9 -5
@@ -1,7 +1,7 @@
1 1 import { importInventory, importLoadOutPresets, importPersonalRooms } from "../../services/importService.ts";
2 2 import { ensureUserHasFounderHonoria, getInventory } from "../../services/inventoryService.ts";
3 3 import { getLoadout } from "../../services/loadoutService.ts";
4 import { getAccountIdForRequest } from "../../services/loginService.ts";
4 import { getAccountForRequest, hasPermission } from "../../services/loginService.ts";
5 5 import { getPersonalRooms } from "../../services/personalRoomsService.ts";
6 6 import { broadcastInventoryUpdate } from "../../services/wsService.ts";
7 7 import type { IInventoryClient } from "../../types/inventoryTypes/inventoryTypes.ts";
@@ -9,12 +9,16 @@ import type { IGetShipResponse } from "../../types/personalRoomsTypes.ts";
9 9 import type { RequestHandler } from "express";
10 10
11 11 export const importController: RequestHandler = async (req, res) => {
12 const accountId = await getAccountIdForRequest(req);
12 const account = await getAccountForRequest(req);
13 if (!hasPermission(account, "import")) {
14 res.status(500).send(`Permission denied`).end();
15 return;
16 }
13 17 const request = req.body as IImportRequest;
14 18
15 19 let anyKnownKey = false;
16 20 try {
17 const inventory = await getInventory(accountId);
21 const inventory = await getInventory(account._id);
18 22 importInventory(inventory, request.inventory);
19 23 if (inventory.isModified()) {
20 24 anyKnownKey = true;
@@ -25,7 +29,7 @@ export const importController: RequestHandler = async (req, res) => {
25 29 }
26 30
27 31 if ("LoadOutPresets" in request.inventory && request.inventory.LoadOutPresets) {
28 const loadout = await getLoadout(accountId);
32 const loadout = await getLoadout(account._id);
29 33 importLoadOutPresets(loadout, request.inventory.LoadOutPresets);
30 34 if (loadout.isModified()) {
31 35 anyKnownKey = true;
@@ -38,7 +42,7 @@ export const importController: RequestHandler = async (req, res) => {
38 42 "Apartment" in request.inventory ||
39 43 "TailorShop" in request.inventory
40 44 ) {
41 const personalRooms = await getPersonalRooms(accountId);
45 const personalRooms = await getPersonalRooms(account._id);
42 46 importPersonalRooms(personalRooms, request.inventory);
43 47 if (personalRooms.isModified()) {
44 48 anyKnownKey = true;
Modified src/controllers/custom/setAccountCheatController.ts +12 -10
@@ -1,5 +1,5 @@
1 1 import { getInventory } from "../../services/inventoryService.ts";
2 import { getAccountIdForRequest } from "../../services/loginService.ts";
2 import { getAccountForRequest, hasPermission } from "../../services/loginService.ts";
3 3 import { sendWsBroadcastEx, sendWsBroadcastTo } from "../../services/wsService.ts";
4 4 import {
5 5 accountCheatBooleans,
@@ -14,11 +14,14 @@ import { lockCheats } from "../../services/cheatsService.ts";
14 14 import { Inventory } from "../../models/inventoryModels/inventoryModel.ts";
15 15
16 16 export const setAccountCheatController: RequestHandler = async (req, res) => {
17 const account = await getAccountForRequest(req);
18
17 19 const payload = req.body as ISetAccountCheatRequest;
18 if (
19 accountCheatBooleans.indexOf(payload.key as TAccountCheatBooleanKey) == -1 &&
20 accountCheatNumbers.indexOf(payload.key as TAccountCheatNumberKey) == -1
21 ) {
20 if (accountCheatBooleans.indexOf(payload.key as TAccountCheatBooleanKey) != -1) {
21 if (!hasPermission(account, `toggleCheat.${payload.key}`)) {
22 throw new Error(`Permission denied`);
23 }
24 } else if (accountCheatNumbers.indexOf(payload.key as TAccountCheatNumberKey) == -1) {
22 25 throw new Error(`unexpected setAccountCheat key: ${payload.key}`);
23 26 }
24 27 if (payload.value == undefined) {
@@ -26,11 +29,10 @@ export const setAccountCheatController: RequestHandler = async (req, res) => {
26 29 return;
27 30 }
28 31
29 const accountId = await getAccountIdForRequest(req);
30 32 const meta = payload.value ? lockCheats[payload.key] : undefined;
31 33
32 34 if (meta) {
33 const inventory = await getInventory(accountId, `${payload.key} ${meta.projection}`);
35 const inventory = await getInventory(account._id, `${payload.key} ${meta.projection}`);
34 36 inventory[payload.key] = payload.value as never;
35 37 if (!meta.isInventoryInIdealState(inventory)) {
36 38 res.send("retroactivable");
@@ -39,7 +41,7 @@ export const setAccountCheatController: RequestHandler = async (req, res) => {
39 41 } else {
40 42 await Inventory.updateOne(
41 43 {
42 accountOwnerId: accountId
44 accountOwnerId: account._id
43 45 },
44 46 {
45 47 [payload.key]: payload.value
@@ -60,9 +62,9 @@ export const setAccountCheatController: RequestHandler = async (req, res) => {
60 62 "skipAllPopups"
61 63 ].indexOf(payload.key) != -1
62 64 ) {
63 sendWsBroadcastTo(accountId, { update_inventory: true, sync_inventory: true });
65 sendWsBroadcastTo(account._id.toString(), { update_inventory: true, sync_inventory: true });
64 66 } else {
65 sendWsBroadcastEx({ update_inventory: true }, accountId, parseInt(String(req.query.wsid)));
67 sendWsBroadcastEx({ update_inventory: true }, account._id.toString(), parseInt(String(req.query.wsid)));
66 68 }
67 69 };
68 70
Modified src/services/configService.ts +12 -0
@@ -248,6 +248,18 @@ export const getReflexiveAddress = (request: Request): { myAddress: string; myUr
248 248 return { myAddress, myUrlBase };
249 249 };
250 250
251 export const configIdToIndexable = (id: string): [Record<string, boolean | string | number | undefined>, string] => {
252 let obj = config as unknown as Record<string, never>;
253 const arr = id.split(".");
254 while (arr.length > 1) {
255 // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
256 obj[arr[0]] ??= {} as never;
257 obj = obj[arr[0]];
258 arr.splice(0, 1);
259 }
260 return [obj, arr[0]];
261 };
262
251 263 export interface IWebServerParams {
252 264 address: string;
253 265 httpPort: number;
Modified src/services/loginService.ts +31 -2
@@ -6,7 +6,7 @@ import type { Document, Types } from "mongoose";
6 6 import { Loadout, type TLoadoutDatabaseDocument } from "../models/inventoryModels/loadoutModel.ts";
7 7 import { PersonalRooms } from "../models/personalRoomsModel.ts";
8 8 import type { Request } from "express";
9 import { config } from "./configService.ts";
9 import { config, configIdToIndexable } from "./configService.ts";
10 10 import { createStats } from "./statsService.ts";
11 11 import { crc32 } from "node:zlib";
12 12 import crypto from "node:crypto";
@@ -135,7 +135,36 @@ export const getAccountIdForRequest = async (req: Request): Promise<string> => {
135 135 };
136 136
137 137 export const isAdministrator = (account: Pick<TAccountDocument, "DisplayName">): boolean => {
138 return config.administratorNames?.indexOf(account.DisplayName) != -1;
138 return (config.administratorNames?.indexOf(account.DisplayName) ?? -1) != -1;
139 };
140
141 export const hasPermission = (account: Pick<TAccountDocument, "DisplayName">, perm: string): boolean => {
142 if (!isAdministrator(account)) {
143 {
144 const [obj, idx] = configIdToIndexable(`webui.nonAdminPermissions.${perm}`);
145 if (typeof obj[idx] == "boolean") {
146 return obj[idx];
147 }
148 }
149
150 const arr = perm.split(".");
151 arr.pop();
152 while (arr.length > 1) {
153 const [obj, idx] = configIdToIndexable(`webui.nonAdminPermissions.${arr.join(".")}.*`);
154 if (typeof obj[idx] == "boolean") {
155 return obj[idx];
156 }
157 arr.pop();
158 }
159
160 {
161 const [obj, idx] = configIdToIndexable(`webui.nonAdminPermissions.*`);
162 if (typeof obj[idx] == "boolean") {
163 return obj[idx];
164 }
165 }
166 }
167 return true;
139 168 };
140 169
141 170 export const getOriginalPlatform = (account: TAccountDocument): number => {
Modified src/services/wsService.ts +19 -1
@@ -8,6 +8,7 @@ import {
8 8 createNonce,
9 9 getAccountForQuery,
10 10 getUsernameFromEmail,
11 hasPermission,
11 12 isAdministrator,
12 13 isCorrectPassword
13 14 } from "./loginService.ts";
@@ -72,6 +73,7 @@ interface IWsMsgFromClient {
72 73 password: string;
73 74 possessing?: string;
74 75 isRegister: boolean;
76 allPermissions: string[];
75 77 };
76 78 auth_game?:
77 79 | {
@@ -84,6 +86,7 @@ interface IWsMsgFromClient {
84 86 };
85 87 logout?: boolean;
86 88 sync_inventory?: boolean;
89 allPermissions?: string[];
87 90 }
88 91
89 92 export interface IWsMsgToClientCommon {
@@ -102,6 +105,7 @@ export interface IWsMsgToClientWebui extends IWsMsgToClientCommon {
102 105 DisplayName: string;
103 106 Nonce: number;
104 107 };
108 permissions?: string[];
105 109 auth_fail?: "bad login" | "bad register" | "admin only" | "registered but admin only";
106 110 nonce_updated?: boolean;
107 111 update_inventory?: boolean;
@@ -176,7 +180,10 @@ const wsOnConnect = (ws: WebSocket, req: http.IncomingMessage): void => {
176 180 DisplayName: accessedAccount.DisplayName,
177 181 Nonce: account.Nonce
178 182 },
179 have_game_ws: haveGameWs(accessedAccount.id)
183 have_game_ws: haveGameWs(accessedAccount.id),
184 permissions: data.auth.allPermissions.filter(perm =>
185 hasPermission(accessedAccount, perm)
186 )
180 187 } satisfies IWsMsgToClient)
181 188 );
182 189 } else {
@@ -233,6 +240,17 @@ const wsOnConnect = (ws: WebSocket, req: http.IncomingMessage): void => {
233 240 sendWsBroadcastToGame(accountId, { sync_inventory: true });
234 241 }
235 242 }
243 if (data.allPermissions) {
244 const accountId = (ws as IWsCustomData).accountId;
245 if (accountId && !(ws as IWsCustomData).isGame) {
246 const account = (await Account.findById(accountId))!;
247 ws.send(
248 JSON.stringify({
249 permissions: data.allPermissions.filter(perm => hasPermission(account, perm))
250 } satisfies IWsMsgToClient)
251 );
252 }
253 }
236 254 } catch (e) {
237 255 logError(e as Error, `processing websocket message`);
238 256 }
Modified static/webui/index.html +89 -89
@@ -113,7 +113,7 @@
113 113 <form class="card-body input-group" onsubmit="doAcquireCountItems('miscitems');return false;">
114 114 <input class="form-control" id="miscitems-count" type="number" value="1" />
115 115 <input class="form-control w-50" id="acquire-type-miscitems" list="datalist-miscitems" autocomplete="off" />
116 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
116 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
117 117 </form>
118 118 </div>
119 119 <div class="tab-pane" id="typeName-tab-content">
@@ -122,7 +122,7 @@
122 122 <div class="input-group">
123 123 <input class="form-control" id="typeName-count" type="number" value="1" />
124 124 <input class="form-control w-50" id="typeName-type" />
125 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
125 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
126 126 </div>
127 127 </form>
128 128 </div>
@@ -137,7 +137,7 @@
137 137 <p class="card-text" id="RegularCredits-owned"></p>
138 138 <form class="input-group" onsubmit="doAddCurrency('RegularCredits');return false;">
139 139 <input class="form-control" id="RegularCredits-delta" type="number" value="1000000" />
140 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
140 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addCredits"></button>
141 141 </form>
142 142 </div>
143 143 </div>
@@ -149,7 +149,7 @@
149 149 <p class="card-text" id="PremiumCredits-owned"></p>
150 150 <form class="input-group" onsubmit="doAddCurrency('PremiumCredits');return false;">
151 151 <input class="form-control" id="PremiumCredits-delta" type="number" value="100" />
152 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
152 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addPlatinum"></button>
153 153 </form>
154 154 </div>
155 155 </div>
@@ -161,7 +161,7 @@
161 161 <p class="card-text" id="FusionPoints-owned"></p>
162 162 <form class="input-group" onsubmit="doAddCurrency('FusionPoints');return false;">
163 163 <input class="form-control" id="FusionPoints-delta" type="number" value="1000" />
164 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
164 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addEndo"></button>
165 165 </form>
166 166 </div>
167 167 </div>
@@ -173,7 +173,7 @@
173 173 <p class="card-text" id="PrimeTokens-owned"></p>
174 174 <form class="input-group" onsubmit="doAddCurrency('PrimeTokens');return false;">
175 175 <input class="form-control" id="PrimeTokens-delta" type="number" value="1" />
176 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
176 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addRegalAya"></button>
177 177 </form>
178 178 </div>
179 179 </div>
@@ -186,7 +186,7 @@
186 186 <div class="card-body d-flex flex-column">
187 187 <form class="input-group mb-3" onsubmit="doAcquireEquipment('Suits');return false;">
188 188 <input class="form-control" id="acquire-type-Suits" list="datalist-Suits" autocomplete="off" />
189 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
189 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
190 190 </form>
191 191 <div class="overflow-auto">
192 192 <table class="table table-hover w-100">
@@ -202,7 +202,7 @@
202 202 <div class="card-body d-flex flex-column">
203 203 <form class="input-group mb-3" onsubmit="handleModularSelection('LongGuns');return false;">
204 204 <input class="form-control" id="acquire-type-LongGuns" list="datalist-LongGuns" autocomplete="off" />
205 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
205 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
206 206 </form>
207 207 <form class="input-group mb-3 d-none" id="modular-LongGuns">
208 208 <input class="form-control" id="acquire-type-LongGuns-GUN_BARREL" list="datalist-ModularParts-GUN_BARREL" autocomplete="off" />
@@ -225,7 +225,7 @@
225 225 <div class="card-body d-flex flex-column">
226 226 <form class="input-group mb-3" onsubmit="handleModularSelection('Pistols');return false;">
227 227 <input class="form-control" id="acquire-type-Pistols" list="datalist-Pistols" autocomplete="off" />
228 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
228 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
229 229 </form>
230 230 <form class="input-group mb-3 d-none" id="modular-Pistols">
231 231 <input class="form-control" id="acquire-type-Pistols-GUN_BARREL" list="datalist-ModularParts-GUN_BARREL" autocomplete="off" />
@@ -246,7 +246,7 @@
246 246 <div class="card-body d-flex flex-column">
247 247 <form class="input-group mb-3" onsubmit="handleModularSelection('Melee');return false;">
248 248 <input class="form-control" id="acquire-type-Melee" list="datalist-Melee" autocomplete="off" />
249 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
249 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
250 250 </form>
251 251 <form class="input-group mb-3 d-none" id="modular-Melee">
252 252 <input class="form-control" id="acquire-type-Melee-BLADE" list="datalist-ModularParts-BLADE" autocomplete="off" />
@@ -269,7 +269,7 @@
269 269 <div class="card-body d-flex flex-column">
270 270 <form class="input-group mb-3" onsubmit="doAcquireEquipment('SpaceSuits');return false;">
271 271 <input class="form-control" id="acquire-type-SpaceSuits" list="datalist-SpaceSuits" autocomplete="off" />
272 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
272 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
273 273 </form>
274 274 <div class="overflow-auto">
275 275 <table class="table table-hover w-100">
@@ -285,7 +285,7 @@
285 285 <div class="card-body d-flex flex-column">
286 286 <form class="input-group mb-3" onsubmit="doAcquireEquipment('SpaceGuns');return false;">
287 287 <input class="form-control" id="acquire-type-SpaceGuns" list="datalist-SpaceGuns" autocomplete="off" />
288 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
288 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
289 289 </form>
290 290 <div class="overflow-auto">
291 291 <table class="table table-hover w-100">
@@ -303,7 +303,7 @@
303 303 <div class="card-body d-flex flex-column">
304 304 <form class="input-group mb-3" onsubmit="doAcquireEquipment('SpaceMelee');return false;">
305 305 <input class="form-control" id="acquire-type-SpaceMelee" list="datalist-SpaceMelee" autocomplete="off" />
306 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
306 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
307 307 </form>
308 308 <div class="overflow-auto">
309 309 <table class="table table-hover w-100">
@@ -319,7 +319,7 @@
319 319 <div class="card-body d-flex flex-column">
320 320 <form class="input-group mb-3" onsubmit="doAcquireEquipment('MechSuits');return false;">
321 321 <input class="form-control" id="acquire-type-MechSuits" list="datalist-MechSuits" autocomplete="off" />
322 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
322 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
323 323 </form>
324 324 <div class="overflow-auto">
325 325 <table class="table table-hover w-100">
@@ -337,7 +337,7 @@
337 337 <div class="card-body d-flex flex-column">
338 338 <form class="input-group mb-3" onsubmit="doAcquireEquipment('Sentinels');return false;">
339 339 <input class="form-control" id="acquire-type-Sentinels" list="datalist-Sentinels" autocomplete="off" />
340 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
340 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
341 341 </form>
342 342 <div class="overflow-auto">
343 343 <table class="table table-hover w-100">
@@ -353,7 +353,7 @@
353 353 <div class="card-body d-flex flex-column">
354 354 <form class="input-group mb-3" onsubmit="handleModularSelection('MoaPets');return false;">
355 355 <input class="form-control" id="acquire-type-MoaPets" list="datalist-MoaPets" autocomplete="off" />
356 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
356 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
357 357 </form>
358 358 <form class="input-group mb-3 d-none" id="modular-MoaPets-Moa">
359 359 <input class="form-control" id="acquire-type-MoaPets-MOA_ENGINE" list="datalist-ModularParts-MOA_ENGINE" autocomplete="off" />
@@ -383,7 +383,7 @@
383 383 <div class="card-body d-flex flex-column">
384 384 <form class="input-group mb-3" onsubmit="handleModularSelection('KubrowPets');return false;">
385 385 <input class="form-control" id="acquire-type-KubrowPets" list="datalist-KubrowPets" autocomplete="off" />
386 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
386 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
387 387 </form>
388 388 <form class="input-group mb-3 d-none" id="modular-KubrowPets-Catbrow">
389 389 <input class="form-control" id="acquire-type-KubrowPets-CATBROW_ANTIGEN" list="datalist-ModularParts-CATBROW_ANTIGEN" autocomplete="off" />
@@ -407,7 +407,7 @@
407 407 <div class="card-body d-flex flex-column">
408 408 <form class="input-group mb-3" onsubmit="doAcquireEquipment('SentinelWeapons');return false;">
409 409 <input class="form-control" id="acquire-type-SentinelWeapons" list="datalist-SentinelWeapons" autocomplete="off" />
410 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
410 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
411 411 </form>
412 412 <div class="overflow-auto">
413 413 <table class="table table-hover w-100">
@@ -425,7 +425,7 @@
425 425 <div class="card-body d-flex flex-column">
426 426 <form class="input-group mb-3" onsubmit="handleModularSelection('OperatorAmps');return false;">
427 427 <input class="form-control" id="acquire-type-OperatorAmps" list="datalist-OperatorAmps" autocomplete="off" />
428 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
428 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
429 429 </form>
430 430 <form class="input-group mb-3 d-none" id="modular-OperatorAmps">
431 431 <input class="form-control" id="acquire-type-OperatorAmps-AMP_OCULUS" list="datalist-ModularParts-AMP_OCULUS" autocomplete="off" />
@@ -449,7 +449,7 @@
449 449 <input class="form-control" id="acquire-type-Hoverboards-HB_ENGINE" list="datalist-ModularParts-HB_ENGINE" autocomplete="off" />
450 450 <input class="form-control" id="acquire-type-Hoverboards-HB_FRONT" list="datalist-ModularParts-HB_FRONT" autocomplete="off" />
451 451 <input class="form-control" id="acquire-type-Hoverboards-HB_JET" list="datalist-ModularParts-HB_JET" autocomplete="off" />
452 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
452 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
453 453 </form>
454 454 <div class="overflow-auto">
455 455 <table class="table table-hover w-100">
@@ -467,7 +467,7 @@
467 467 <div class="card-body d-flex flex-column">
468 468 <form class="input-group mb-3" onsubmit="doAcquireEquipment('QuestKeys');return false;">
469 469 <input class="form-control" id="acquire-type-QuestKeys" list="datalist-QuestKeys" autocomplete="off" />
470 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
470 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
471 471 </form>
472 472 <div class="overflow-auto">
473 473 <table class="table table-hover w-100">
@@ -483,7 +483,7 @@
483 483 <div class="card-body d-flex flex-column">
484 484 <form class="input-group mb-3" onsubmit="doAcquireEvolution();return false;">
485 485 <input class="form-control" id="acquire-type-EvolutionProgress" list="datalist-EvolutionProgress" autocomplete="off" />
486 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
486 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
487 487 </form>
488 488 <div class="overflow-auto">
489 489 <table class="table table-hover w-100">
@@ -501,7 +501,7 @@
501 501 <div class="card-body d-flex flex-column">
502 502 <form class="input-group mb-3" onsubmit="doAcquireBooster();return false;">
503 503 <input class="form-control" id="acquire-type-Boosters" list="datalist-Boosters" autocomplete="off" />
504 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
504 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
505 505 </form>
506 506 <div class="overflow-auto">
507 507 <table class="table table-hover w-100">
@@ -517,7 +517,7 @@
517 517 <div class="card-body d-flex flex-column">
518 518 <form class="input-group mb-3" onsubmit="doAcquireEquipment('FlavourItems');return false;">
519 519 <input class="form-control" id="acquire-type-FlavourItems" list="datalist-FlavourItems" autocomplete="off" />
520 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
520 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
521 521 </form>
522 522 <div class="overflow-auto">
523 523 <table class="table table-hover w-100">
@@ -536,7 +536,7 @@
536 536 <form class="input-group mb-3" onsubmit="doAcquireCountItems('ShipDecorations');return false;">
537 537 <input class="form-control" id="ShipDecorations-count" type="number" value="1" />
538 538 <input class="form-control w-50" id="acquire-type-ShipDecorations" list="datalist-ShipDecorations" autocomplete="off" />
539 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
539 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
540 540 </form>
541 541 <div class="overflow-auto">
542 542 <table class="table table-hover w-100">
@@ -552,7 +552,7 @@
552 552 <div class="card-body d-flex flex-column">
553 553 <form class="input-group mb-3" onsubmit="doAcquireEquipment('WeaponSkins');return false;">
554 554 <input class="form-control" id="acquire-type-WeaponSkins" list="datalist-WeaponSkins" autocomplete="off" />
555 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
555 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
556 556 </form>
557 557 <div class="overflow-auto">
558 558 <table class="table table-hover w-100">
@@ -588,7 +588,7 @@
588 588 <p class="card-text" id="VaultRegularCredits-owned"></p>
589 589 <form id="vaultRegularCredits-form" class="input-group d-none" onsubmit="doAddCurrency('VaultRegularCredits');return false;">
590 590 <input class="form-control" id="VaultRegularCredits-delta" type="number" value="1000000" />
591 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
591 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
592 592 </form>
593 593 </div>
594 594 </div>
@@ -600,7 +600,7 @@
600 600 <p class="card-text" id="VaultPremiumCredits-owned"></p>
601 601 <form id="vaultPremiumCredits-form" class="input-group d-none" onsubmit="doAddCurrency('VaultPremiumCredits');return false;">
602 602 <input class="form-control" id="VaultPremiumCredits-delta" type="number" value="100" />
603 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
603 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
604 604 </form>
605 605 </div>
606 606 </div>
@@ -613,7 +613,7 @@
613 613 <div class="card-body d-flex flex-column">
614 614 <form id="techProjects-form" class="input-group mb-3 d-none" onsubmit="addGuildTechProject();return false;">
615 615 <input class="form-control" id="acquire-type-TechProjects" list="datalist-TechProjects" autocomplete="off" />
616 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
616 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
617 617 </form>
618 618 <div class="overflow-auto">
619 619 <table class="table table-hover w-100">
@@ -629,7 +629,7 @@
629 629 <div class="card-body d-flex flex-column">
630 630 <form id="vaultDecoRecipes-form" class="input-group mb-3 d-none" onsubmit="addVaultItem('VaultDecoRecipes');return false;">
631 631 <input class="form-control" id="acquire-type-VaultDecoRecipes" list="datalist-VaultDecoRecipes" autocomplete="off" />
632 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
632 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
633 633 </form>
634 634 <div class="overflow-auto">
635 635 <table class="table table-hover w-100">
@@ -648,7 +648,7 @@
648 648 <form id="vaultMiscItems-form" class="input-group mb-3 d-none" onsubmit="addVaultItem('VaultMiscItems');return false;">
649 649 <input class="form-control" id="VaultMiscItems-count" type="number" value="1" />
650 650 <input class="form-control w-50" id="acquire-type-VaultMiscItems" list="datalist-VaultMiscItems" autocomplete="off" />
651 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
651 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
652 652 </form>
653 653 <div class="overflow-auto">
654 654 <table class="table table-hover w-100">
@@ -665,7 +665,7 @@
665 665 <form id="vaultShipDecorations-form" class="input-group mb-3 d-none" onsubmit="addVaultItem('VaultShipDecorations');return false;">
666 666 <input class="form-control" id="VaultShipDecorations-count" type="number" value="1" />
667 667 <input class="form-control w-50" id="acquire-type-VaultShipDecorations" list="datalist-ShipDecorations" autocomplete="off" />
668 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
668 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
669 669 </form>
670 670 <div class="overflow-auto">
671 671 <table class="table table-hover w-100">
@@ -704,27 +704,27 @@
704 704 <h5 class="card-header" data-loc="guildView_cheats"></h5>
705 705 <div class="card-body" id="guild-cheats">
706 706 <div class="form-check">
707 <input class="form-check-input" type="checkbox" id="noDojoRoomBuildStage" />
707 <input class="form-check-input" type="checkbox" id="noDojoRoomBuildStage" data-enabling-permission="toggleCheat.noDojoRoomBuildStage" />
708 708 <label class="form-check-label" for="noDojoRoomBuildStage" data-loc="cheats_noDojoRoomBuildStage"></label>
709 709 </div>
710 710 <div class="form-check">
711 <input class="form-check-input" type="checkbox" id="fastDojoRoomDestruction" />
711 <input class="form-check-input" type="checkbox" id="fastDojoRoomDestruction" data-enabling-permission="toggleCheat.fastDojoRoomDestruction" />
712 712 <label class="form-check-label" for="fastDojoRoomDestruction" data-loc="cheats_fastDojoRoomDestruction"></label>
713 713 </div>
714 714 <div class="form-check">
715 <input class="form-check-input" type="checkbox" id="noDojoDecoBuildStage" />
715 <input class="form-check-input" type="checkbox" id="noDojoDecoBuildStage" data-enabling-permission="toggleCheat.noDojoDecoBuildStage" />
716 716 <label class="form-check-label" for="noDojoDecoBuildStage" data-loc="cheats_noDojoDecoBuildStage"></label>
717 717 </div>
718 718 <div class="form-check">
719 <input class="form-check-input" type="checkbox" id="noDojoResearchCosts" />
719 <input class="form-check-input" type="checkbox" id="noDojoResearchCosts" data-enabling-permission="toggleCheat.noDojoResearchCosts" />
720 720 <label class="form-check-label" for="noDojoResearchCosts" data-loc="cheats_noDojoResearchCosts"></label>
721 721 </div>
722 722 <div class="form-check">
723 <input class="form-check-input" type="checkbox" id="noDojoResearchTime" />
723 <input class="form-check-input" type="checkbox" id="noDojoResearchTime" data-enabling-permission="toggleCheat.noDojoResearchTime" />
724 724 <label class="form-check-label" for="noDojoResearchTime" data-loc="cheats_noDojoResearchTime"></label>
725 725 </div>
726 726 <div class="form-check">
727 <input class="form-check-input" type="checkbox" id="fastClanAscension" />
727 <input class="form-check-input" type="checkbox" id="fastClanAscension" data-enabling-permission="toggleCheat.fastClanAscension" />
728 728 <label class="form-check-label" for="fastClanAscension" data-loc="cheats_fastClanAscension"></label>
729 729 </div>
730 730 </div>
@@ -754,7 +754,7 @@
754 754 <input type="number" id="archon-crystal-add-count" min="1" max="10000" value="1" class="form-control" style="max-width:100px" />
755 755 <span class="input-group-text">x</span>
756 756 <input class="form-control" list="datalist-archonCrystalUpgrades" autocomplete="off" />
757 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
757 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
758 758 </form>
759 759 <table class="table table-hover w-100">
760 760 <tbody id="crystals-list"></tbody>
@@ -884,7 +884,7 @@
884 884 <option value="PlayerMeleeWeaponRandomModRare">PlayerMeleeWeaponRandomModRare</option>
885 885 </select>
886 886 <textarea id="addriven-fingerprint" class="form-control mb-3" data-loc-placeholder="mods_fingerprint"></textarea>
887 <button class="btn btn-primary" style="margin-right: 5px" type="submit" data-loc="general_addButton"></button>
887 <button class="btn btn-primary" style="margin-right: 5px" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
888 888 <a href="riven-tool/" target="_blank" data-loc="mods_fingerprintHelp"></a>
889 889 </form>
890 890 </div>
@@ -904,8 +904,8 @@
904 904 <form class="input-group mb-3" onsubmit="doAcquireMod();return false;">
905 905 <input class="form-control" id="mod-count" type="number" value="1"/>
906 906 <input class="form-control w-50" id="mod-to-acquire" list="datalist-mods" autocomplete="off" />
907 <button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
908 <button class="btn btn-success" onclick="window.maxed=true" data-loc="mods_addMax"></button>
907 <button class="btn btn-primary" type="submit" data-loc="general_addButton" data-enabling-permission="addItems"></button>
908 <button class="btn btn-success" onclick="window.maxed=true" data-loc="mods_addMax" data-enabling-permission="addItems"></button>
909 909 </form>
910 910 <table class="table table-hover w-100">
911 911 <tbody id="mods-list"></tbody>
@@ -915,9 +915,9 @@
915 915 <div class="card">
916 916 <h5 class="card-header" data-loc="general_bulkActions"></h5>
917 917 <div class="card-body d-flex flex-wrap gap-2">
918 <button class="btn btn-primary" onclick="doAddAllMods();" data-loc="mods_addMissingUnrankedMods"></button>
918 <button class="btn btn-primary" onclick="doAddAllMods();" data-loc="mods_addMissingUnrankedMods" data-enabling-permission="addItems"></button>
919 919 <button class="btn btn-danger" onclick="doRemoveUnrankedMods();" data-loc="mods_removeUnranked"></button>
920 <button class="btn btn-primary" onclick="doAddMissingMaxRankMods();" data-loc="mods_addMissingMaxRankMods"></button>
920 <button class="btn btn-primary" onclick="doAddMissingMaxRankMods();" data-loc="mods_addMissingMaxRankMods" data-enabling-permission="addItems"></button>
921 921 </div>
922 922 </div>
923 923 </div>
@@ -930,179 +930,179 @@
930 930 <h5 class="card-header" data-loc="cheats_account"></h5>
931 931 <div class="card-body" id="account-cheats">
932 932 <div class="form-check">
933 <input class="form-check-input" type="checkbox" id="skipAllDialogue" />
933 <input class="form-check-input" type="checkbox" id="skipAllDialogue" data-enabling-permission="toggleCheat.skipAllDialogue" />
934 934 <label class="form-check-label" for="skipAllDialogue" data-loc="cheats_skipAllDialogue"></label>
935 935 </div>
936 936 <div class="form-check">
937 <input class="form-check-input" type="checkbox" id="skipAllPopups" />
937 <input class="form-check-input" type="checkbox" id="skipAllPopups" data-enabling-permission="toggleCheat.skipAllPopups" />
938 938 <label class="form-check-label" for="skipAllPopups" data-loc="cheats_skipAllPopups"></label>
939 939 </div>
940 940 <div class="form-check">
941 <input class="form-check-input" type="checkbox" id="dontSubtractPurchaseCreditCost" />
941 <input class="form-check-input" type="checkbox" id="dontSubtractPurchaseCreditCost" data-enabling-permission="toggleCheat.dontSubtractPurchaseCreditCost" />
942 942 <label class="form-check-label" for="dontSubtractPurchaseCreditCost" data-loc="cheats_dontSubtractPurchaseCreditCost"></label>
943 943 </div>
944 944 <div class="form-check">
945 <input class="form-check-input" type="checkbox" id="dontSubtractPurchasePlatinumCost" />
945 <input class="form-check-input" type="checkbox" id="dontSubtractPurchasePlatinumCost" data-enabling-permission="toggleCheat.dontSubtractPurchasePlatinumCost" />
946 946 <label class="form-check-label" for="dontSubtractPurchasePlatinumCost" data-loc="cheats_dontSubtractPurchasePlatinumCost"></label>
947 947 </div>
948 948 <div class="form-check">
949 <input class="form-check-input" type="checkbox" id="dontSubtractPurchaseItemCost" />
949 <input class="form-check-input" type="checkbox" id="dontSubtractPurchaseItemCost" data-enabling-permission="toggleCheat.dontSubtractPurchaseItemCost" />
950 950 <label class="form-check-label" for="dontSubtractPurchaseItemCost" data-loc="cheats_dontSubtractPurchaseItemCost"></label>
951 951 </div>
952 952 <div class="form-check">
953 <input class="form-check-input" type="checkbox" id="dontSubtractPurchaseStandingCost" />
953 <input class="form-check-input" type="checkbox" id="dontSubtractPurchaseStandingCost" data-enabling-permission="toggleCheat.dontSubtractPurchaseStandingCost" />
954 954 <label class="form-check-label" for="dontSubtractPurchaseStandingCost" data-loc="cheats_dontSubtractPurchaseStandingCost"></label>
955 955 </div>
956 956 <div class="form-check">
957 <input class="form-check-input" type="checkbox" id="dontSubtractKuvaForRivens" />
957 <input class="form-check-input" type="checkbox" id="dontSubtractKuvaForRivens" data-enabling-permission="toggleCheat.dontSubtractKuvaForRivens" />
958 958 <label class="form-check-label" for="dontSubtractKuvaForRivens" data-loc="cheats_dontSubtractKuvaForRivens"></label>
959 959 </div>
960 960 <div class="form-check">
961 <input class="form-check-input" type="checkbox" id="dontSubtractVoidTraces" />
961 <input class="form-check-input" type="checkbox" id="dontSubtractVoidTraces" data-enabling-permission="toggleCheat.dontSubtractVoidTraces" />
962 962 <label class="form-check-label" for="dontSubtractVoidTraces" data-loc="cheats_dontSubtractVoidTraces"></label>
963 963 </div>
964 964 <div class="form-check">
965 <input class="form-check-input" type="checkbox" id="dontSubtractConsumables" />
965 <input class="form-check-input" type="checkbox" id="dontSubtractConsumables" data-enabling-permission="toggleCheat.dontSubtractConsumables" />
966 966 <label class="form-check-label" for="dontSubtractConsumables" data-loc="cheats_dontSubtractConsumables"></label>
967 967 </div>
968 968 <div class="form-check">
969 <input class="form-check-input" type="checkbox" id="dontSubtractKeys" />
969 <input class="form-check-input" type="checkbox" id="dontSubtractKeys" data-enabling-permission="toggleCheat.dontSubtractKeys" />
970 970 <label class="form-check-label" for="dontSubtractKeys" data-loc="cheats_dontSubtractKeys"></label>
971 971 </div>
972 972 <div class="form-check">
973 <input class="form-check-input" type="checkbox" id="infiniteCredits" />
973 <input class="form-check-input" type="checkbox" id="infiniteCredits" data-enabling-permission="toggleCheat.infiniteCredits" />
974 974 <label class="form-check-label" for="infiniteCredits" data-loc="cheats_infiniteCredits"></label>
975 975 </div>
976 976 <div class="form-check">
977 <input class="form-check-input" type="checkbox" id="infinitePlatinum" />
977 <input class="form-check-input" type="checkbox" id="infinitePlatinum" data-enabling-permission="toggleCheat.infinitePlatinum" />
978 978 <label class="form-check-label" for="infinitePlatinum" data-loc="cheats_infinitePlatinum"></label>
979 979 </div>
980 980 <div class="form-check">
981 <input class="form-check-input" type="checkbox" id="infiniteEndo" />
981 <input class="form-check-input" type="checkbox" id="infiniteEndo" data-enabling-permission="toggleCheat.infiniteEndo" />
982 982 <label class="form-check-label" for="infiniteEndo" data-loc="cheats_infiniteEndo"></label>
983 983 </div>
984 984 <div class="form-check">
985 <input class="form-check-input" type="checkbox" id="infiniteRegalAya" />
985 <input class="form-check-input" type="checkbox" id="infiniteRegalAya" data-enabling-permission="toggleCheat.infiniteRegalAya" />
986 986 <label class="form-check-label" for="infiniteRegalAya" data-loc="cheats_infiniteRegalAya"></label>
987 987 </div>
988 988 <div class="form-check">
989 <input class="form-check-input" type="checkbox" id="infiniteTrades" />
989 <input class="form-check-input" type="checkbox" id="infiniteTrades" data-enabling-permission="toggleCheat.infiniteTrades" />
990 990 <label class="form-check-label" for="infiniteTrades" data-loc="cheats_infiniteTrades"></label>
991 991 </div>
992 992 <div class="form-check">
993 <input class="form-check-input" type="checkbox" id="infiniteGifts" />
993 <input class="form-check-input" type="checkbox" id="infiniteGifts" data-enabling-permission="toggleCheat.infiniteGifts" />
994 994 <label class="form-check-label" for="infiniteGifts" data-loc="cheats_infiniteGifts"></label>
995 995 </div>
996 996 <div class="form-check">
997 <input class="form-check-input" type="checkbox" id="infiniteHelminthMaterials" />
997 <input class="form-check-input" type="checkbox" id="infiniteHelminthMaterials" data-enabling-permission="toggleCheat.infiniteHelminthMaterials" />
998 998 <label class="form-check-label" for="infiniteHelminthMaterials" data-loc="cheats_infiniteHelminthMaterials"></label>
999 999 </div>
1000 1000 <div class="form-check">
1001 <input class="form-check-input" type="checkbox" id="universalPolarityEverywhere" />
1001 <input class="form-check-input" type="checkbox" id="universalPolarityEverywhere" data-enabling-permission="toggleCheat.universalPolarityEverywhere" />
1002 1002 <label class="form-check-label" for="universalPolarityEverywhere" data-loc="cheats_universalPolarityEverywhere"></label>
1003 1003 </div>
1004 1004 <div class="form-check">
1005 <input class="form-check-input" type="checkbox" id="unlockDoubleCapacityPotatoesEverywhere" />
1005 <input class="form-check-input" type="checkbox" id="unlockDoubleCapacityPotatoesEverywhere" data-enabling-permission="toggleCheat.unlockDoubleCapacityPotatoesEverywhere" />
1006 1006 <label class="form-check-label" for="unlockDoubleCapacityPotatoesEverywhere" data-loc="cheats_unlockDoubleCapacityPotatoesEverywhere"></label>
1007 1007 </div>
1008 1008 <div class="form-check">
1009 <input class="form-check-input" type="checkbox" id="unlockExilusEverywhere" />
1009 <input class="form-check-input" type="checkbox" id="unlockExilusEverywhere" data-enabling-permission="toggleCheat.unlockExilusEverywhere" />
1010 1010 <label class="form-check-label" for="unlockExilusEverywhere" data-loc="cheats_unlockExilusEverywhere"></label>
1011 1011 </div>
1012 1012 <div class="form-check">
1013 <input class="form-check-input" type="checkbox" id="unlockArcanesEverywhere" />
1013 <input class="form-check-input" type="checkbox" id="unlockArcanesEverywhere" data-enabling-permission="toggleCheat.unlockArcanesEverywhere" />
1014 1014 <label class="form-check-label" for="unlockArcanesEverywhere" data-loc="cheats_unlockArcanesEverywhere"></label>
1015 1015 </div>
1016 1016 <div class="form-check">
1017 <input class="form-check-input" type="checkbox" id="alertsRepeatable" />
1017 <input class="form-check-input" type="checkbox" id="alertsRepeatable" data-enabling-permission="toggleCheat.alertsRepeatable" />
1018 1018 <label class="form-check-label" for="alertsRepeatable" data-loc="cheats_alertsRepeatable"></label>
1019 1019 </div>
1020 1020 <div class="form-check">
1021 <input class="form-check-input" type="checkbox" id="syndicateMissionsRepeatable" />
1021 <input class="form-check-input" type="checkbox" id="syndicateMissionsRepeatable" data-enabling-permission="toggleCheat.syndicateMissionsRepeatable" />
1022 1022 <label class="form-check-label" for="syndicateMissionsRepeatable" data-loc="cheats_syndicateMissionsRepeatable"></label>
1023 1023 </div>
1024 1024 <div class="form-check">
1025 <input class="form-check-input" type="checkbox" id="instantFinishRivenChallenge" />
1025 <input class="form-check-input" type="checkbox" id="instantFinishRivenChallenge" data-enabling-permission="toggleCheat.instantFinishRivenChallenge" />
1026 1026 <label class="form-check-label" for="instantFinishRivenChallenge" data-loc="cheats_instantFinishRivenChallenge"></label>
1027 1027 </div>
1028 1028 <div class="form-check">
1029 <input class="form-check-input" type="checkbox" id="noDailyStandingLimits" />
1029 <input class="form-check-input" type="checkbox" id="noDailyStandingLimits" data-enabling-permission="toggleCheat.noDailyStandingLimits" />
1030 1030 <label class="form-check-label" for="noDailyStandingLimits" data-loc="cheats_noDailyStandingLimits"></label>
1031 1031 </div>
1032 1032 <div class="form-check">
1033 <input class="form-check-input" type="checkbox" id="noDailyFocusLimit" />
1033 <input class="form-check-input" type="checkbox" id="noDailyFocusLimit" data-enabling-permission="toggleCheat.noDailyFocusLimit" />
1034 1034 <label class="form-check-label" for="noDailyFocusLimit" data-loc="cheats_noDailyFocusLimit"></label>
1035 1035 </div>
1036 1036 <div class="form-check">
1037 <input class="form-check-input" type="checkbox" id="noArgonCrystalDecay" />
1037 <input class="form-check-input" type="checkbox" id="noArgonCrystalDecay" data-enabling-permission="toggleCheat.noArgonCrystalDecay" />
1038 1038 <label class="form-check-label" for="noArgonCrystalDecay" data-loc="cheats_noArgonCrystalDecay"></label>
1039 1039 </div>
1040 1040 <div class="form-check">
1041 <input class="form-check-input" type="checkbox" id="noMasteryRankUpCooldown" />
1041 <input class="form-check-input" type="checkbox" id="noMasteryRankUpCooldown" data-enabling-permission="toggleCheat.noMasteryRankUpCooldown" />
1042 1042 <label class="form-check-label" for="noMasteryRankUpCooldown" data-loc="cheats_noMasteryRankUpCooldown"></label>
1043 1043 </div>
1044 1044 <div class="form-check">
1045 <input class="form-check-input" type="checkbox" id="noVendorPurchaseLimits" />
1045 <input class="form-check-input" type="checkbox" id="noVendorPurchaseLimits" data-enabling-permission="toggleCheat.noVendorPurchaseLimits" />
1046 1046 <label class="form-check-label" for="noVendorPurchaseLimits" data-loc="cheats_noVendorPurchaseLimits"></label>
1047 1047 </div>
1048 1048 <div class="form-check">
1049 <input class="form-check-input" type="checkbox" id="noNodeEntryFees" />
1049 <input class="form-check-input" type="checkbox" id="noNodeEntryFees" data-enabling-permission="toggleCheat.noNodeEntryFees" />
1050 1050 <label class="form-check-label" for="noNodeEntryFees" data-loc="cheats_noNodeEntryFees"></label>
1051 1051 </div>
1052 1052 <div class="form-check">
1053 <input class="form-check-input" type="checkbox" id="noDeathMarks" />
1053 <input class="form-check-input" type="checkbox" id="noDeathMarks" data-enabling-permission="toggleCheat.noDeathMarks" />
1054 1054 <label class="form-check-label" for="noDeathMarks" data-loc="cheats_noDeathMarks"></label>
1055 1055 </div>
1056 1056 <div class="form-check">
1057 <input class="form-check-input" type="checkbox" id="noNemesis" />
1057 <input class="form-check-input" type="checkbox" id="noNemesis" data-enabling-permission="toggleCheat.noNemesis" />
1058 1058 <label class="form-check-label" for="noNemesis" data-loc="cheats_noNemesis"></label>
1059 1059 </div>
1060 1060 <div class="form-check">
1061 <input class="form-check-input" type="checkbox" id="noKimCooldowns" />
1061 <input class="form-check-input" type="checkbox" id="noKimCooldowns" data-enabling-permission="toggleCheat.noKimCooldowns" />
1062 1062 <label class="form-check-label" for="noKimCooldowns" data-loc="cheats_noKimCooldowns"></label>
1063 1063 </div>
1064 1064 <div class="form-check">
1065 <input class="form-check-input" type="checkbox" id="noBlessingCooldown" />
1065 <input class="form-check-input" type="checkbox" id="noBlessingCooldown" data-enabling-permission="toggleCheat.noBlessingCooldown" />
1066 1066 <label class="form-check-label" for="noBlessingCooldown" data-loc="cheats_noBlessingCooldown"></label>
1067 1067 </div>
1068 1068 <div class="form-check">
1069 <input class="form-check-input" type="checkbox" id="noResourceExtractorDronesDamage" />
1069 <input class="form-check-input" type="checkbox" id="noResourceExtractorDronesDamage" data-enabling-permission="toggleCheat.noResourceExtractorDronesDamage" />
1070 1070 <label class="form-check-label" for="noResourceExtractorDronesDamage" data-loc="cheats_noResourceExtractorDronesDamage"></label>
1071 1071 </div>
1072 1072 <div class="form-check">
1073 <input class="form-check-input" type="checkbox" id="instantResourceExtractorDrones" />
1073 <input class="form-check-input" type="checkbox" id="instantResourceExtractorDrones" data-enabling-permission="toggleCheat.instantResourceExtractorDrones" />
1074 1074 <label class="form-check-label" for="instantResourceExtractorDrones" data-loc="cheats_instantResourceExtractorDrones"></label>
1075 1075 </div>
1076 1076 <div class="form-check">
1077 <input class="form-check-input" type="checkbox" id="claimingBlueprintRefundsIngredients" />
1077 <input class="form-check-input" type="checkbox" id="claimingBlueprintRefundsIngredients" data-enabling-permission="toggleCheat.claimingBlueprintRefundsIngredients" />
1078 1078 <label class="form-check-label" for="claimingBlueprintRefundsIngredients" data-loc="cheats_claimingBlueprintRefundsIngredients"></label>
1079 1079 </div>
1080 1080 <div class="form-check">
1081 <input class="form-check-input" type="checkbox" id="missionsCanGiveAllRelics" />
1081 <input class="form-check-input" type="checkbox" id="missionsCanGiveAllRelics" data-enabling-permission="toggleCheat.missionsCanGiveAllRelics" />
1082 1082 <label class="form-check-label" for="missionsCanGiveAllRelics" data-loc="cheats_missionsCanGiveAllRelics"></label>
1083 1083 </div>
1084 1084 <div class="form-check">
1085 <input class="form-check-input" type="checkbox" id="exceptionalRelicsAlwaysGiveBronzeReward" />
1085 <input class="form-check-input" type="checkbox" id="exceptionalRelicsAlwaysGiveBronzeReward" data-enabling-permission="toggleCheat.exceptionalRelicsAlwaysGiveBronzeReward" />
1086 1086 <label class="form-check-label" for="exceptionalRelicsAlwaysGiveBronzeReward" data-loc="cheats_exceptionalRelicsAlwaysGiveBronzeReward"></label>
1087 1087 </div>
1088 1088 <div class="form-check">
1089 <input class="form-check-input" type="checkbox" id="flawlessRelicsAlwaysGiveSilverReward" />
1089 <input class="form-check-input" type="checkbox" id="flawlessRelicsAlwaysGiveSilverReward" data-enabling-permission="toggleCheat.flawlessRelicsAlwaysGiveSilverReward" />
1090 1090 <label class="form-check-label" for="flawlessRelicsAlwaysGiveSilverReward" data-loc="cheats_flawlessRelicsAlwaysGiveSilverReward"></label>
1091 1091 </div>
1092 1092 <div class="form-check">
1093 <input class="form-check-input" type="checkbox" id="radiantRelicsAlwaysGiveGoldReward" />
1093 <input class="form-check-input" type="checkbox" id="radiantRelicsAlwaysGiveGoldReward" data-enabling-permission="toggleCheat.radiantRelicsAlwaysGiveGoldReward" />
1094 1094 <label class="form-check-label" for="radiantRelicsAlwaysGiveGoldReward" data-loc="cheats_radiantRelicsAlwaysGiveGoldReward"></label>
1095 1095 </div>
1096 1096 <div class="form-check">
1097 <input class="form-check-input" type="checkbox" id="disableDailyTribute" />
1097 <input class="form-check-input" type="checkbox" id="disableDailyTribute" data-enabling-permission="toggleCheat.disableDailyTribute" />
1098 1098 <label class="form-check-label" for="disableDailyTribute" data-loc="cheats_disableDailyTribute"></label>
1099 1099 </div>
1100 1100 <div class="form-check">
1101 <input class="form-check-input" type="checkbox" id="incrementDailyTributeBy50" />
1101 <input class="form-check-input" type="checkbox" id="incrementDailyTributeBy50" data-enabling-permission="toggleCheat.incrementDailyTributeBy50" />
1102 1102 <label class="form-check-label" for="incrementDailyTributeBy50" data-loc="cheats_incrementDailyTributeBy50"></label>
1103 1103 </div>
1104 1104 <div class="form-check">
1105 <input class="form-check-input" type="checkbox" id="finishInvasionsInOneMission" />
1105 <input class="form-check-input" type="checkbox" id="finishInvasionsInOneMission" data-enabling-permission="toggleCheat.finishInvasionsInOneMission" />
1106 1106 <label class="form-check-label" for="finishInvasionsInOneMission" data-loc="cheats_finishInvasionsInOneMission"></label>
1107 1107 </div>
1108 1108 <form class="form-group mt-2" onsubmit="doChangeSupportedSyndicate(); return false;">
@@ -1699,7 +1699,7 @@
1699 1699 <span data-loc="import_importNote2"></span>
1700 1700 </p>
1701 1701 <textarea class="form-control" id="import-inventory" style="height: calc(100vh - 300px)"></textarea>
1702 <button class="btn btn-primary mt-3" onclick="doImport();" data-loc="import_submit"></button>
1702 <button class="btn btn-primary mt-3" onclick="doImport();" data-loc="import_submit" data-enabling-permission="import"></button>
1703 1703 <p class="mt-3 mb-1" data-loc="import_samples"></p>
1704 1704 <ul>
1705 1705 <li><a href="#" onclick="event.preventDefault();setImportSample('maxFocus');" data-loc="import_samples_maxFocus"></a></li>
Modified static/webui/script.js +20 -1
@@ -8,6 +8,14 @@
8 8 /* eslint-disable @typescript-eslint/no-unsafe-member-access */
9 9 /* eslint-disable @typescript-eslint/explicit-function-return-type */
10 10
11 const allPermissions = [];
12 document.querySelectorAll("[data-enabling-permission]").forEach(elm => {
13 const perm = elm.getAttribute("data-enabling-permission");
14 if (allPermissions.indexOf(perm) == -1) {
15 allPermissions.push(perm);
16 }
17 });
18
11 19 let auth_pending = false,
12 20 ws_is_open = false,
13 21 wsid = 0,
@@ -21,7 +29,8 @@ const sendAuth = isRegister => {
21 29 email: localStorage.getItem("email").toLowerCase(),
22 30 password: wp.encSync(localStorage.getItem("password")),
23 31 possessing: localStorage.getItem("possessing"),
24 isRegister
32 isRegister,
33 allPermissions
25 34 }
26 35 })
27 36 );
@@ -85,6 +94,15 @@ function openWebSocket() {
85 94 refreshServerConfig();
86 95 }
87 96 }
97 if ("permissions" in msg) {
98 for (const perm of allPermissions) {
99 const granted = msg.permissions.indexOf(perm) != -1;
100 //console.log(`Permission ${perm} was ${granted ? 'granted' : 'denied'}`);
101 document.querySelectorAll(`[data-enabling-permission='${perm}']`).forEach(elm => {
102 elm.disabled = !granted;
103 });
104 }
105 }
88 106 if ("auth_fail" in msg) {
89 107 auth_pending = false;
90 108 if (localStorage.getItem("possessing")) {
@@ -148,6 +166,7 @@ function refreshServerConfig() {
148 166 if (single.getCurrentPath() == "/webui/cheats" || single.getCurrentPath() == "/webui/admin") {
149 167 single.loadRoute(single.getCurrentPath());
150 168 }
169 ws.send(JSON.stringify({ allPermissions }));
151 170 }
152 171
153 172 function doAccountSwitch(to_route) {