omegga 1.5.4 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -1
- package/bin/omegga +1 -1
- package/dist/cli/terminal.js +46 -0
- package/dist/cli/terminal.js.map +1 -1
- package/dist/webserver/backend/database.js +309 -11
- package/dist/webserver/backend/database.js.map +1 -1
- package/dist/webserver/backend/events.js +1 -1
- package/dist/webserver/backend/events.js.map +1 -1
- package/dist/webserver/backend/index.js +120 -2
- package/dist/webserver/backend/index.js.map +1 -1
- package/dist/webserver/backend/permissions.js +133 -0
- package/dist/webserver/backend/permissions.js.map +1 -0
- package/dist/webserver/backend/roleHierarchy.js +108 -0
- package/dist/webserver/backend/roleHierarchy.js.map +1 -0
- package/dist/webserver/backend/router/chat.js +9 -7
- package/dist/webserver/backend/router/chat.js.map +1 -1
- package/dist/webserver/backend/router/index.js +3 -1
- package/dist/webserver/backend/router/index.js.map +1 -1
- package/dist/webserver/backend/router/mfa.js +162 -0
- package/dist/webserver/backend/router/mfa.js.map +1 -0
- package/dist/webserver/backend/router/player.js +16 -6
- package/dist/webserver/backend/router/player.js.map +1 -1
- package/dist/webserver/backend/router/plugin.js +14 -10
- package/dist/webserver/backend/router/plugin.js.map +1 -1
- package/dist/webserver/backend/router/role.js +201 -6
- package/dist/webserver/backend/router/role.js.map +1 -1
- package/dist/webserver/backend/router/server.js +85 -71
- package/dist/webserver/backend/router/server.js.map +1 -1
- package/dist/webserver/backend/router/session.js +11 -4
- package/dist/webserver/backend/router/session.js.map +1 -1
- package/dist/webserver/backend/router/user.js +230 -15
- package/dist/webserver/backend/router/user.js.map +1 -1
- package/dist/webserver/backend/router/world.js +10 -9
- package/dist/webserver/backend/router/world.js.map +1 -1
- package/dist/webserver/backend/scopes.js +332 -0
- package/dist/webserver/backend/scopes.js.map +1 -0
- package/dist/webserver/backend/totp.js +32 -0
- package/dist/webserver/backend/totp.js.map +1 -0
- package/dist/webserver/backend/trpc.js +47 -4
- package/dist/webserver/backend/trpc.js.map +1 -1
- package/doc/permissions.md +264 -0
- package/package.json +7 -1
- package/public/app.html +1012 -527
- package/public/assets/IconShieldCheck-Bjlm8mX2.js +2 -0
- package/public/assets/IconShieldCheck-Bjlm8mX2.js.map +1 -0
- package/public/assets/IconWorld-Bx3cKMms.js +2 -0
- package/public/assets/IconWorld-Bx3cKMms.js.map +1 -0
- package/public/assets/IconWorldPlus-BHSmzWsZ.js +2 -0
- package/public/assets/IconWorldPlus-BHSmzWsZ.js.map +1 -0
- package/public/assets/app-J90GEVdo.js +7 -0
- package/public/assets/app-J90GEVdo.js.map +1 -0
- package/public/assets/auth-nn5rDnJ9.js +2 -0
- package/public/assets/auth-nn5rDnJ9.js.map +1 -0
- package/public/assets/index-B2DCW1zi.js +2 -0
- package/public/assets/index-B2DCW1zi.js.map +1 -0
- package/public/assets/index-BDkarAkX.js +3 -0
- package/public/assets/index-BDkarAkX.js.map +1 -0
- package/public/assets/{index-2cgXLhrt.js → index-DEL-PD_8.js} +2 -2
- package/public/assets/{index-2cgXLhrt.js.map → index-DEL-PD_8.js.map} +1 -1
- package/public/assets/index-wYDkzaAO.js +12 -0
- package/public/assets/index-wYDkzaAO.js.map +1 -0
- package/public/assets/shared/@components-BWkdUJhC.js +2 -0
- package/public/assets/shared/@components-BWkdUJhC.js.map +1 -0
- package/public/assets/shared/@hooks-BuRTblPY.js +2 -0
- package/public/assets/shared/{@hooks-Ch_hJYh0.js.map → @hooks-BuRTblPY.js.map} +1 -1
- package/public/assets/shared/@tabler_icons-react-CdTxTJVq.js +3 -0
- package/public/assets/shared/{@tabler_icons-react-iQk11eD_.js.map → @tabler_icons-react-CdTxTJVq.js.map} +1 -1
- package/public/assets/shared/{wouter-CUC1caxu.js → wouter-CNISJ5i6.js} +2 -2
- package/public/assets/shared/wouter-CNISJ5i6.js.map +1 -0
- package/public/assets/useHasScope-DZPCXNQE.js +2 -0
- package/public/assets/useHasScope-DZPCXNQE.js.map +1 -0
- package/public/auth.html +153 -40
- package/public/assets/IconArrowRight-BuVxhqKX.js +0 -2
- package/public/assets/IconArrowRight-BuVxhqKX.js.map +0 -1
- package/public/assets/IconWorld-B6GK5qpx.js +0 -2
- package/public/assets/IconWorld-B6GK5qpx.js.map +0 -1
- package/public/assets/IconWorldPlus-Dkos72Ws.js +0 -2
- package/public/assets/IconWorldPlus-Dkos72Ws.js.map +0 -1
- package/public/assets/app-CLZ-5FIi.js +0 -6
- package/public/assets/app-CLZ-5FIi.js.map +0 -1
- package/public/assets/auth-6N37o421.js +0 -2
- package/public/assets/auth-6N37o421.js.map +0 -1
- package/public/assets/index-DLZ8-XzO.js +0 -4
- package/public/assets/index-DLZ8-XzO.js.map +0 -1
- package/public/assets/index-DY750sgZ.js +0 -2
- package/public/assets/index-DY750sgZ.js.map +0 -1
- package/public/assets/shared/@components-DPHARroA.js +0 -2
- package/public/assets/shared/@components-DPHARroA.js.map +0 -1
- package/public/assets/shared/@hooks-Ch_hJYh0.js +0 -2
- package/public/assets/shared/@tabler_icons-react-iQk11eD_.js +0 -3
- package/public/assets/shared/wouter-CUC1caxu.js.map +0 -1
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const ScopeDomain = {
|
|
4
|
+
Chat: "chat",
|
|
5
|
+
Player: "player",
|
|
6
|
+
Plugin: "plugin",
|
|
7
|
+
Server: "server",
|
|
8
|
+
User: "user",
|
|
9
|
+
World: "world",
|
|
10
|
+
Role: "role",
|
|
11
|
+
Session: "session"
|
|
12
|
+
};
|
|
13
|
+
const ScopeName = {
|
|
14
|
+
ChatSend: "chat.send",
|
|
15
|
+
ChatRecent: "chat.recent",
|
|
16
|
+
ChatHistory: "chat.history",
|
|
17
|
+
ChatCalendar: "chat.calendar",
|
|
18
|
+
PlayerList: "player.list",
|
|
19
|
+
PlayerGet: "player.get",
|
|
20
|
+
PlayerBan: "player.ban",
|
|
21
|
+
PlayerKick: "player.kick",
|
|
22
|
+
PlayerUnban: "player.unban",
|
|
23
|
+
PlayerClearBricks: "player.clearBricks",
|
|
24
|
+
PluginList: "plugin.list",
|
|
25
|
+
PluginGet: "plugin.get",
|
|
26
|
+
PluginConfig: "plugin.config",
|
|
27
|
+
PluginLoad: "plugin.load",
|
|
28
|
+
PluginUnload: "plugin.unload",
|
|
29
|
+
PluginToggle: "plugin.toggle",
|
|
30
|
+
PluginReloadAll: "plugin.reloadAll",
|
|
31
|
+
ServerStatus: "server.status",
|
|
32
|
+
ServerStart: "server.start",
|
|
33
|
+
ServerStop: "server.stop",
|
|
34
|
+
ServerRestart: "server.restart",
|
|
35
|
+
ServerUpdateCheck: "server.update.check",
|
|
36
|
+
ServerUpdateRun: "server.update.run",
|
|
37
|
+
ServerAutorestartGet: "server.autorestart.get",
|
|
38
|
+
ServerAutorestartSet: "server.autorestart.set",
|
|
39
|
+
ServerUtilization: "server.utilization",
|
|
40
|
+
UserList: "user.list",
|
|
41
|
+
UserCreate: "user.create",
|
|
42
|
+
UserPasswd: "user.passwd",
|
|
43
|
+
UserBan: "user.ban",
|
|
44
|
+
UserDelete: "user.delete",
|
|
45
|
+
UserPermissions: "user.permissions",
|
|
46
|
+
UserGrantRole: "user.grantRole",
|
|
47
|
+
UserReadMfa: "user.readMfa",
|
|
48
|
+
UserResetMfa: "user.resetMfa",
|
|
49
|
+
WorldList: "world.list",
|
|
50
|
+
WorldActive: "world.active",
|
|
51
|
+
WorldNext: "world.next",
|
|
52
|
+
WorldRevisions: "world.revisions",
|
|
53
|
+
WorldMeta: "world.meta",
|
|
54
|
+
WorldLoad: "world.load",
|
|
55
|
+
WorldUse: "world.use",
|
|
56
|
+
WorldSave: "world.save",
|
|
57
|
+
WorldCreate: "world.create",
|
|
58
|
+
RoleList: "role.list",
|
|
59
|
+
RoleEdit: "role.edit",
|
|
60
|
+
RoleDefaultPermissions: "role.defaultPermissions",
|
|
61
|
+
RoleGrantPermission: "role.grantPermission",
|
|
62
|
+
SessionInfo: "session.info"
|
|
63
|
+
};
|
|
64
|
+
const S = ScopeName;
|
|
65
|
+
const D = ScopeDomain;
|
|
66
|
+
const SCOPES = {
|
|
67
|
+
// Chat
|
|
68
|
+
[S.ChatSend]: {
|
|
69
|
+
description: "Send messages in the dashboard chat widget",
|
|
70
|
+
readOnly: false,
|
|
71
|
+
domain: D.Chat
|
|
72
|
+
},
|
|
73
|
+
[S.ChatRecent]: {
|
|
74
|
+
description: "View recent chat on the dashboard",
|
|
75
|
+
readOnly: true,
|
|
76
|
+
domain: D.Chat
|
|
77
|
+
},
|
|
78
|
+
[S.ChatHistory]: {
|
|
79
|
+
description: "Browse past chat logs in the history view",
|
|
80
|
+
readOnly: true,
|
|
81
|
+
domain: D.Chat
|
|
82
|
+
},
|
|
83
|
+
[S.ChatCalendar]: {
|
|
84
|
+
description: "Navigate chat by date in the history view",
|
|
85
|
+
readOnly: true,
|
|
86
|
+
domain: D.Chat
|
|
87
|
+
},
|
|
88
|
+
// Player
|
|
89
|
+
[S.PlayerList]: {
|
|
90
|
+
description: "View the player list in the players view",
|
|
91
|
+
readOnly: true,
|
|
92
|
+
domain: D.Player
|
|
93
|
+
},
|
|
94
|
+
[S.PlayerGet]: {
|
|
95
|
+
description: "Inspect player details and history",
|
|
96
|
+
readOnly: true,
|
|
97
|
+
domain: D.Player
|
|
98
|
+
},
|
|
99
|
+
[S.PlayerBan]: {
|
|
100
|
+
description: "Ban players from the player inspector",
|
|
101
|
+
readOnly: false,
|
|
102
|
+
domain: D.Player
|
|
103
|
+
},
|
|
104
|
+
[S.PlayerKick]: {
|
|
105
|
+
description: "Kick players from the player inspector",
|
|
106
|
+
readOnly: false,
|
|
107
|
+
domain: D.Player
|
|
108
|
+
},
|
|
109
|
+
[S.PlayerUnban]: {
|
|
110
|
+
description: "Unban players from the player inspector",
|
|
111
|
+
readOnly: false,
|
|
112
|
+
domain: D.Player
|
|
113
|
+
},
|
|
114
|
+
[S.PlayerClearBricks]: {
|
|
115
|
+
description: "Clear a player's bricks from the player inspector",
|
|
116
|
+
readOnly: false,
|
|
117
|
+
domain: D.Player
|
|
118
|
+
},
|
|
119
|
+
// Plugin
|
|
120
|
+
[S.PluginList]: {
|
|
121
|
+
description: "View installed plugins in the plugins view",
|
|
122
|
+
readOnly: true,
|
|
123
|
+
domain: D.Plugin
|
|
124
|
+
},
|
|
125
|
+
[S.PluginGet]: {
|
|
126
|
+
description: "Inspect plugin details and configuration",
|
|
127
|
+
readOnly: true,
|
|
128
|
+
domain: D.Plugin
|
|
129
|
+
},
|
|
130
|
+
[S.PluginConfig]: {
|
|
131
|
+
description: "Edit plugin settings in the plugin inspector",
|
|
132
|
+
readOnly: false,
|
|
133
|
+
domain: D.Plugin
|
|
134
|
+
},
|
|
135
|
+
[S.PluginLoad]: {
|
|
136
|
+
description: "Load plugins from the plugin inspector",
|
|
137
|
+
readOnly: false,
|
|
138
|
+
domain: D.Plugin
|
|
139
|
+
},
|
|
140
|
+
[S.PluginUnload]: {
|
|
141
|
+
description: "Unload plugins from the plugin inspector",
|
|
142
|
+
readOnly: false,
|
|
143
|
+
domain: D.Plugin
|
|
144
|
+
},
|
|
145
|
+
[S.PluginToggle]: {
|
|
146
|
+
description: "Enable or disable plugins in the plugins view",
|
|
147
|
+
readOnly: false,
|
|
148
|
+
domain: D.Plugin
|
|
149
|
+
},
|
|
150
|
+
[S.PluginReloadAll]: {
|
|
151
|
+
description: "Reload all plugins from the plugins view",
|
|
152
|
+
readOnly: false,
|
|
153
|
+
domain: D.Plugin
|
|
154
|
+
},
|
|
155
|
+
// Server
|
|
156
|
+
[S.ServerStatus]: {
|
|
157
|
+
description: "View server status on the dashboard and server view",
|
|
158
|
+
readOnly: true,
|
|
159
|
+
domain: D.Server
|
|
160
|
+
},
|
|
161
|
+
[S.ServerStart]: {
|
|
162
|
+
description: "Start the server from the server view",
|
|
163
|
+
readOnly: false,
|
|
164
|
+
domain: D.Server
|
|
165
|
+
},
|
|
166
|
+
[S.ServerStop]: {
|
|
167
|
+
description: "Stop the server from the server view",
|
|
168
|
+
readOnly: false,
|
|
169
|
+
domain: D.Server
|
|
170
|
+
},
|
|
171
|
+
[S.ServerRestart]: {
|
|
172
|
+
description: "Restart the server from the server view",
|
|
173
|
+
readOnly: false,
|
|
174
|
+
domain: D.Server
|
|
175
|
+
},
|
|
176
|
+
[S.ServerUpdateCheck]: {
|
|
177
|
+
description: "Check for server updates in the server view",
|
|
178
|
+
readOnly: false,
|
|
179
|
+
domain: D.Server
|
|
180
|
+
},
|
|
181
|
+
[S.ServerUpdateRun]: {
|
|
182
|
+
description: "Run server updates from the server view",
|
|
183
|
+
readOnly: false,
|
|
184
|
+
domain: D.Server
|
|
185
|
+
},
|
|
186
|
+
[S.ServerAutorestartGet]: {
|
|
187
|
+
description: "View auto-restart settings in the server view",
|
|
188
|
+
readOnly: true,
|
|
189
|
+
domain: D.Server
|
|
190
|
+
},
|
|
191
|
+
[S.ServerAutorestartSet]: {
|
|
192
|
+
description: "Change auto-restart settings in the server view",
|
|
193
|
+
readOnly: false,
|
|
194
|
+
domain: D.Server
|
|
195
|
+
},
|
|
196
|
+
[S.ServerUtilization]: {
|
|
197
|
+
description: "View CPU, memory, and disk usage on the dashboard",
|
|
198
|
+
readOnly: true,
|
|
199
|
+
domain: D.Server
|
|
200
|
+
},
|
|
201
|
+
// User
|
|
202
|
+
[S.UserList]: {
|
|
203
|
+
description: "View web UI user accounts in the users view",
|
|
204
|
+
readOnly: true,
|
|
205
|
+
domain: D.User
|
|
206
|
+
},
|
|
207
|
+
[S.UserCreate]: {
|
|
208
|
+
description: "Create new user accounts in the users view",
|
|
209
|
+
readOnly: false,
|
|
210
|
+
domain: D.User
|
|
211
|
+
},
|
|
212
|
+
[S.UserPasswd]: {
|
|
213
|
+
description: "Change user passwords in the users view",
|
|
214
|
+
readOnly: false,
|
|
215
|
+
domain: D.User
|
|
216
|
+
},
|
|
217
|
+
[S.UserBan]: {
|
|
218
|
+
description: "Disable or re-enable users in the user inspector",
|
|
219
|
+
readOnly: false,
|
|
220
|
+
domain: D.User
|
|
221
|
+
},
|
|
222
|
+
[S.UserDelete]: {
|
|
223
|
+
description: "Permanently delete user accounts",
|
|
224
|
+
readOnly: false,
|
|
225
|
+
domain: D.User
|
|
226
|
+
},
|
|
227
|
+
[S.UserPermissions]: {
|
|
228
|
+
description: "Edit user permissions in the users view",
|
|
229
|
+
readOnly: false,
|
|
230
|
+
domain: D.User
|
|
231
|
+
},
|
|
232
|
+
[S.UserGrantRole]: {
|
|
233
|
+
description: "Assign and revoke roles to/from users",
|
|
234
|
+
readOnly: false,
|
|
235
|
+
domain: D.User
|
|
236
|
+
},
|
|
237
|
+
[S.UserReadMfa]: {
|
|
238
|
+
description: "View MFA status of other users in the user inspector",
|
|
239
|
+
readOnly: true,
|
|
240
|
+
domain: D.User
|
|
241
|
+
},
|
|
242
|
+
[S.UserResetMfa]: {
|
|
243
|
+
description: "Reset MFA for other users in the user inspector",
|
|
244
|
+
readOnly: false,
|
|
245
|
+
domain: D.User
|
|
246
|
+
},
|
|
247
|
+
// World
|
|
248
|
+
[S.WorldList]: {
|
|
249
|
+
description: "View available worlds in the worlds view",
|
|
250
|
+
readOnly: true,
|
|
251
|
+
domain: D.World
|
|
252
|
+
},
|
|
253
|
+
[S.WorldActive]: {
|
|
254
|
+
description: "See which world is currently loaded",
|
|
255
|
+
readOnly: true,
|
|
256
|
+
domain: D.World
|
|
257
|
+
},
|
|
258
|
+
[S.WorldNext]: {
|
|
259
|
+
description: "See which world will load next",
|
|
260
|
+
readOnly: true,
|
|
261
|
+
domain: D.World
|
|
262
|
+
},
|
|
263
|
+
[S.WorldRevisions]: {
|
|
264
|
+
description: "View world save revisions in the world inspector",
|
|
265
|
+
readOnly: true,
|
|
266
|
+
domain: D.World
|
|
267
|
+
},
|
|
268
|
+
[S.WorldMeta]: {
|
|
269
|
+
description: "View world metadata in the world inspector",
|
|
270
|
+
readOnly: true,
|
|
271
|
+
domain: D.World
|
|
272
|
+
},
|
|
273
|
+
[S.WorldLoad]: {
|
|
274
|
+
description: "Load worlds from the world inspector",
|
|
275
|
+
readOnly: false,
|
|
276
|
+
domain: D.World
|
|
277
|
+
},
|
|
278
|
+
[S.WorldUse]: {
|
|
279
|
+
description: "Set the default world in the worlds view",
|
|
280
|
+
readOnly: false,
|
|
281
|
+
domain: D.World
|
|
282
|
+
},
|
|
283
|
+
[S.WorldSave]: {
|
|
284
|
+
description: "Save the current world from the worlds or server view",
|
|
285
|
+
readOnly: false,
|
|
286
|
+
domain: D.World
|
|
287
|
+
},
|
|
288
|
+
[S.WorldCreate]: {
|
|
289
|
+
description: "Create new worlds in the worlds view",
|
|
290
|
+
readOnly: false,
|
|
291
|
+
domain: D.World
|
|
292
|
+
},
|
|
293
|
+
// Role
|
|
294
|
+
[S.RoleList]: {
|
|
295
|
+
description: "View roles in the roles view",
|
|
296
|
+
readOnly: true,
|
|
297
|
+
domain: D.Role
|
|
298
|
+
},
|
|
299
|
+
[S.RoleEdit]: {
|
|
300
|
+
description: "Create, edit, delete, and reorder roles",
|
|
301
|
+
readOnly: false,
|
|
302
|
+
domain: D.Role
|
|
303
|
+
},
|
|
304
|
+
[S.RoleDefaultPermissions]: {
|
|
305
|
+
description: "Edit the default permissions that apply to all users",
|
|
306
|
+
readOnly: false,
|
|
307
|
+
domain: D.Role
|
|
308
|
+
},
|
|
309
|
+
[S.RoleGrantPermission]: {
|
|
310
|
+
description: "Add or remove permissions within roles",
|
|
311
|
+
readOnly: false,
|
|
312
|
+
domain: D.Role
|
|
313
|
+
},
|
|
314
|
+
// Session
|
|
315
|
+
[S.SessionInfo]: {
|
|
316
|
+
description: "View session info",
|
|
317
|
+
readOnly: true,
|
|
318
|
+
domain: D.Session
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
[
|
|
322
|
+
...new Set(Object.values(SCOPES).map((s) => s.domain))
|
|
323
|
+
];
|
|
324
|
+
const SCOPES_BY_DOMAIN = {};
|
|
325
|
+
for (const [scope, info] of Object.entries(SCOPES)) {
|
|
326
|
+
(SCOPES_BY_DOMAIN[info.domain] ??= []).push(scope);
|
|
327
|
+
}
|
|
328
|
+
exports.SCOPES = SCOPES;
|
|
329
|
+
exports.SCOPES_BY_DOMAIN = SCOPES_BY_DOMAIN;
|
|
330
|
+
exports.ScopeDomain = ScopeDomain;
|
|
331
|
+
exports.ScopeName = ScopeName;
|
|
332
|
+
//# sourceMappingURL=scopes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scopes.js","sources":["../../../src/webserver/backend/scopes.ts"],"sourcesContent":["export const ScopeDomain = {\n Chat: 'chat',\n Player: 'player',\n Plugin: 'plugin',\n Server: 'server',\n User: 'user',\n World: 'world',\n Role: 'role',\n Session: 'session',\n} as const;\n\nexport const ScopeName = {\n ChatSend: 'chat.send',\n ChatRecent: 'chat.recent',\n ChatHistory: 'chat.history',\n ChatCalendar: 'chat.calendar',\n\n PlayerList: 'player.list',\n PlayerGet: 'player.get',\n PlayerBan: 'player.ban',\n PlayerKick: 'player.kick',\n PlayerUnban: 'player.unban',\n PlayerClearBricks: 'player.clearBricks',\n\n PluginList: 'plugin.list',\n PluginGet: 'plugin.get',\n PluginConfig: 'plugin.config',\n PluginLoad: 'plugin.load',\n PluginUnload: 'plugin.unload',\n PluginToggle: 'plugin.toggle',\n PluginReloadAll: 'plugin.reloadAll',\n\n ServerStatus: 'server.status',\n ServerStart: 'server.start',\n ServerStop: 'server.stop',\n ServerRestart: 'server.restart',\n ServerUpdateCheck: 'server.update.check',\n ServerUpdateRun: 'server.update.run',\n ServerAutorestartGet: 'server.autorestart.get',\n ServerAutorestartSet: 'server.autorestart.set',\n ServerUtilization: 'server.utilization',\n\n UserList: 'user.list',\n UserCreate: 'user.create',\n UserPasswd: 'user.passwd',\n UserBan: 'user.ban',\n UserDelete: 'user.delete',\n UserPermissions: 'user.permissions',\n UserGrantRole: 'user.grantRole',\n UserReadMfa: 'user.readMfa',\n UserResetMfa: 'user.resetMfa',\n\n WorldList: 'world.list',\n WorldActive: 'world.active',\n WorldNext: 'world.next',\n WorldRevisions: 'world.revisions',\n WorldMeta: 'world.meta',\n WorldLoad: 'world.load',\n WorldUse: 'world.use',\n WorldSave: 'world.save',\n WorldCreate: 'world.create',\n\n RoleList: 'role.list',\n RoleEdit: 'role.edit',\n RoleDefaultPermissions: 'role.defaultPermissions',\n RoleGrantPermission: 'role.grantPermission',\n\n SessionInfo: 'session.info',\n} as const;\n\nconst S = ScopeName;\nconst D = ScopeDomain;\n\nexport const SCOPES = {\n // Chat\n [S.ChatSend]: {\n description: 'Send messages in the dashboard chat widget',\n readOnly: false,\n domain: D.Chat,\n },\n [S.ChatRecent]: {\n description: 'View recent chat on the dashboard',\n readOnly: true,\n domain: D.Chat,\n },\n [S.ChatHistory]: {\n description: 'Browse past chat logs in the history view',\n readOnly: true,\n domain: D.Chat,\n },\n [S.ChatCalendar]: {\n description: 'Navigate chat by date in the history view',\n readOnly: true,\n domain: D.Chat,\n },\n\n // Player\n [S.PlayerList]: {\n description: 'View the player list in the players view',\n readOnly: true,\n domain: D.Player,\n },\n [S.PlayerGet]: {\n description: 'Inspect player details and history',\n readOnly: true,\n domain: D.Player,\n },\n [S.PlayerBan]: {\n description: 'Ban players from the player inspector',\n readOnly: false,\n domain: D.Player,\n },\n [S.PlayerKick]: {\n description: 'Kick players from the player inspector',\n readOnly: false,\n domain: D.Player,\n },\n [S.PlayerUnban]: {\n description: 'Unban players from the player inspector',\n readOnly: false,\n domain: D.Player,\n },\n [S.PlayerClearBricks]: {\n description: \"Clear a player's bricks from the player inspector\",\n readOnly: false,\n domain: D.Player,\n },\n\n // Plugin\n [S.PluginList]: {\n description: 'View installed plugins in the plugins view',\n readOnly: true,\n domain: D.Plugin,\n },\n [S.PluginGet]: {\n description: 'Inspect plugin details and configuration',\n readOnly: true,\n domain: D.Plugin,\n },\n [S.PluginConfig]: {\n description: 'Edit plugin settings in the plugin inspector',\n readOnly: false,\n domain: D.Plugin,\n },\n [S.PluginLoad]: {\n description: 'Load plugins from the plugin inspector',\n readOnly: false,\n domain: D.Plugin,\n },\n [S.PluginUnload]: {\n description: 'Unload plugins from the plugin inspector',\n readOnly: false,\n domain: D.Plugin,\n },\n [S.PluginToggle]: {\n description: 'Enable or disable plugins in the plugins view',\n readOnly: false,\n domain: D.Plugin,\n },\n [S.PluginReloadAll]: {\n description: 'Reload all plugins from the plugins view',\n readOnly: false,\n domain: D.Plugin,\n },\n\n // Server\n [S.ServerStatus]: {\n description: 'View server status on the dashboard and server view',\n readOnly: true,\n domain: D.Server,\n },\n [S.ServerStart]: {\n description: 'Start the server from the server view',\n readOnly: false,\n domain: D.Server,\n },\n [S.ServerStop]: {\n description: 'Stop the server from the server view',\n readOnly: false,\n domain: D.Server,\n },\n [S.ServerRestart]: {\n description: 'Restart the server from the server view',\n readOnly: false,\n domain: D.Server,\n },\n [S.ServerUpdateCheck]: {\n description: 'Check for server updates in the server view',\n readOnly: false,\n domain: D.Server,\n },\n [S.ServerUpdateRun]: {\n description: 'Run server updates from the server view',\n readOnly: false,\n domain: D.Server,\n },\n [S.ServerAutorestartGet]: {\n description: 'View auto-restart settings in the server view',\n readOnly: true,\n domain: D.Server,\n },\n [S.ServerAutorestartSet]: {\n description: 'Change auto-restart settings in the server view',\n readOnly: false,\n domain: D.Server,\n },\n [S.ServerUtilization]: {\n description: 'View CPU, memory, and disk usage on the dashboard',\n readOnly: true,\n domain: D.Server,\n },\n\n // User\n [S.UserList]: {\n description: 'View web UI user accounts in the users view',\n readOnly: true,\n domain: D.User,\n },\n [S.UserCreate]: {\n description: 'Create new user accounts in the users view',\n readOnly: false,\n domain: D.User,\n },\n [S.UserPasswd]: {\n description: 'Change user passwords in the users view',\n readOnly: false,\n domain: D.User,\n },\n [S.UserBan]: {\n description: 'Disable or re-enable users in the user inspector',\n readOnly: false,\n domain: D.User,\n },\n [S.UserDelete]: {\n description: 'Permanently delete user accounts',\n readOnly: false,\n domain: D.User,\n },\n [S.UserPermissions]: {\n description: 'Edit user permissions in the users view',\n readOnly: false,\n domain: D.User,\n },\n [S.UserGrantRole]: {\n description: 'Assign and revoke roles to/from users',\n readOnly: false,\n domain: D.User,\n },\n [S.UserReadMfa]: {\n description: 'View MFA status of other users in the user inspector',\n readOnly: true,\n domain: D.User,\n },\n [S.UserResetMfa]: {\n description: 'Reset MFA for other users in the user inspector',\n readOnly: false,\n domain: D.User,\n },\n\n // World\n [S.WorldList]: {\n description: 'View available worlds in the worlds view',\n readOnly: true,\n domain: D.World,\n },\n [S.WorldActive]: {\n description: 'See which world is currently loaded',\n readOnly: true,\n domain: D.World,\n },\n [S.WorldNext]: {\n description: 'See which world will load next',\n readOnly: true,\n domain: D.World,\n },\n [S.WorldRevisions]: {\n description: 'View world save revisions in the world inspector',\n readOnly: true,\n domain: D.World,\n },\n [S.WorldMeta]: {\n description: 'View world metadata in the world inspector',\n readOnly: true,\n domain: D.World,\n },\n [S.WorldLoad]: {\n description: 'Load worlds from the world inspector',\n readOnly: false,\n domain: D.World,\n },\n [S.WorldUse]: {\n description: 'Set the default world in the worlds view',\n readOnly: false,\n domain: D.World,\n },\n [S.WorldSave]: {\n description: 'Save the current world from the worlds or server view',\n readOnly: false,\n domain: D.World,\n },\n [S.WorldCreate]: {\n description: 'Create new worlds in the worlds view',\n readOnly: false,\n domain: D.World,\n },\n\n // Role\n [S.RoleList]: {\n description: 'View roles in the roles view',\n readOnly: true,\n domain: D.Role,\n },\n [S.RoleEdit]: {\n description: 'Create, edit, delete, and reorder roles',\n readOnly: false,\n domain: D.Role,\n },\n [S.RoleDefaultPermissions]: {\n description: 'Edit the default permissions that apply to all users',\n readOnly: false,\n domain: D.Role,\n },\n [S.RoleGrantPermission]: {\n description: 'Add or remove permissions within roles',\n readOnly: false,\n domain: D.Role,\n },\n\n // Session\n [S.SessionInfo]: {\n description: 'View session info',\n readOnly: true,\n domain: D.Session,\n },\n} as const;\n\nexport type Scope = keyof typeof SCOPES;\n\nexport const DOMAIN_LABELS: Record<string, string> = {\n [D.Chat]: 'Chat',\n [D.Player]: 'Player',\n [D.Plugin]: 'Plugin',\n [D.Server]: 'Server',\n [D.User]: 'User',\n [D.World]: 'World',\n [D.Role]: 'Role',\n};\n\nexport const DOMAIN_ORDER = [\n D.Chat,\n D.Player,\n D.Plugin,\n D.Server,\n D.User,\n D.World,\n D.Role,\n] as const;\n\nexport const DOMAINS = [\n ...new Set(Object.values(SCOPES).map(s => s.domain)),\n] as const;\n\nexport type Domain = (typeof DOMAINS)[number];\n\nexport const SCOPES_BY_DOMAIN: Record<string, Scope[]> = {};\nfor (const [scope, info] of Object.entries(SCOPES)) {\n (SCOPES_BY_DOMAIN[info.domain] ??= []).push(scope as Scope);\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const otpauth = require("otpauth");
|
|
4
|
+
const ISSUER = "Omegga";
|
|
5
|
+
const DIGITS = 6;
|
|
6
|
+
const PERIOD = 30;
|
|
7
|
+
const ALGORITHM = "SHA1";
|
|
8
|
+
function makeTOTP(secret, label = "") {
|
|
9
|
+
return new otpauth.TOTP({
|
|
10
|
+
issuer: ISSUER,
|
|
11
|
+
label,
|
|
12
|
+
algorithm: ALGORITHM,
|
|
13
|
+
digits: DIGITS,
|
|
14
|
+
period: PERIOD,
|
|
15
|
+
secret: otpauth.Secret.fromBase32(secret)
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
function generateSecret() {
|
|
19
|
+
return new otpauth.Secret().base32;
|
|
20
|
+
}
|
|
21
|
+
function verifyToken(token, secret, window = 1) {
|
|
22
|
+
if (!/^\d{6}$/.test(token)) return false;
|
|
23
|
+
const delta = makeTOTP(secret).validate({ token, window });
|
|
24
|
+
return delta !== null;
|
|
25
|
+
}
|
|
26
|
+
function generateURI(secret, username) {
|
|
27
|
+
return makeTOTP(secret, username).toString();
|
|
28
|
+
}
|
|
29
|
+
exports.generateSecret = generateSecret;
|
|
30
|
+
exports.generateURI = generateURI;
|
|
31
|
+
exports.verifyToken = verifyToken;
|
|
32
|
+
//# sourceMappingURL=totp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"totp.js","sources":["../../../src/webserver/backend/totp.ts"],"sourcesContent":["import { TOTP, Secret } from 'otpauth';\n\nconst ISSUER = 'Omegga';\nconst DIGITS = 6;\nconst PERIOD = 30;\nconst ALGORITHM = 'SHA1';\n\nfunction makeTOTP(secret: string, label = ''): TOTP {\n return new TOTP({\n issuer: ISSUER,\n label,\n algorithm: ALGORITHM,\n digits: DIGITS,\n period: PERIOD,\n secret: Secret.fromBase32(secret),\n });\n}\n\nexport function generateSecret(): string {\n return new Secret().base32;\n}\n\nexport function generateToken(secret: string): string {\n return makeTOTP(secret).generate();\n}\n\nexport function verifyToken(\n token: string,\n secret: string,\n window = 1,\n): boolean {\n if (!/^\\d{6}$/.test(token)) return false;\n const delta = makeTOTP(secret).validate({ token, window });\n return delta !== null;\n}\n\nexport function generateURI(secret: string, username: string): string {\n return makeTOTP(secret, username).toString();\n}\n"],"names":["TOTP","Secret"],"mappings":";;;AAEA,MAAM,SAAS;AACf,MAAM,SAAS;AACf,MAAM,SAAS;AACf,MAAM,YAAY;AAElB,SAAS,SAAS,QAAgB,QAAQ,IAAU;AAClD,SAAO,IAAIA,QAAAA,KAAK;AAAA,IACd,QAAQ;AAAA,IACR;AAAA,IACA,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQC,QAAAA,OAAO,WAAW,MAAM;AAAA,EAAA,CACjC;AACH;AAEO,SAAS,iBAAyB;AACvC,SAAO,IAAIA,QAAAA,SAAS;AACtB;AAMO,SAAS,YACd,OACA,QACA,SAAS,GACA;AACT,MAAI,CAAC,UAAU,KAAK,KAAK,EAAG,QAAO;AACnC,QAAM,QAAQ,SAAS,MAAM,EAAE,SAAS,EAAE,OAAO,QAAQ;AACzD,SAAO,UAAU;AACnB;AAEO,SAAS,YAAY,QAAgB,UAA0B;AACpE,SAAO,SAAS,QAAQ,QAAQ,EAAE,SAAA;AACpC;;;;"}
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const logger = require("../../logger.js");
|
|
4
4
|
const server = require("@trpc/server");
|
|
5
|
+
const events = require("./events.js");
|
|
6
|
+
const permissions = require("./permissions.js");
|
|
5
7
|
let _deps = null;
|
|
6
8
|
function setContextDeps(deps) {
|
|
7
9
|
_deps = deps;
|
|
@@ -13,7 +15,11 @@ function getContextDeps() {
|
|
|
13
15
|
async function createContext(opts) {
|
|
14
16
|
const { database } = getContextDeps();
|
|
15
17
|
const req = opts.req;
|
|
16
|
-
const
|
|
18
|
+
const session = req.session;
|
|
19
|
+
if (session?.mfaPending) {
|
|
20
|
+
throw new server.TRPCError({ code: "UNAUTHORIZED" });
|
|
21
|
+
}
|
|
22
|
+
const userId = session?.userId;
|
|
17
23
|
const user = await database.findUserById(userId);
|
|
18
24
|
if (!user || user.isBanned) {
|
|
19
25
|
throw new server.TRPCError({ code: "UNAUTHORIZED" });
|
|
@@ -23,21 +29,58 @@ async function createContext(opts) {
|
|
|
23
29
|
{ $set: { lastOnline: Date.now() } }
|
|
24
30
|
);
|
|
25
31
|
const usernameText = `[${(user.username || "Admin").brightMagenta}]`;
|
|
32
|
+
let _userAbort = null;
|
|
33
|
+
const getUserAbort = () => {
|
|
34
|
+
if (!_userAbort) {
|
|
35
|
+
_userAbort = new AbortController();
|
|
36
|
+
const ac = _userAbort;
|
|
37
|
+
const onInvalidated = (name) => {
|
|
38
|
+
if (name === user.username) ac.abort();
|
|
39
|
+
};
|
|
40
|
+
events.serverEvents.on("userInvalidated", onInvalidated);
|
|
41
|
+
ac.signal.addEventListener("abort", () => {
|
|
42
|
+
events.serverEvents.off("userInvalidated", onInvalidated);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
return _userAbort;
|
|
46
|
+
};
|
|
26
47
|
return {
|
|
27
48
|
user,
|
|
49
|
+
req,
|
|
50
|
+
get userAbort() {
|
|
51
|
+
return getUserAbort();
|
|
52
|
+
},
|
|
28
53
|
log: (...args) => logger.default.logp(usernameText, ...args),
|
|
29
54
|
error: (...args) => logger.default.errorp(usernameText, ...args)
|
|
30
55
|
};
|
|
31
56
|
}
|
|
32
|
-
const t = server.initTRPC.context().create(
|
|
57
|
+
const t = server.initTRPC.context().create({
|
|
58
|
+
errorFormatter({ shape, error, path, ctx }) {
|
|
59
|
+
const user = ctx?.user?.username || "?";
|
|
60
|
+
logger.default.errorp(
|
|
61
|
+
`[${user.brightMagenta}]`,
|
|
62
|
+
`${error.code} ${path ?? "?"}: ${error.message}`
|
|
63
|
+
);
|
|
64
|
+
return shape;
|
|
65
|
+
}
|
|
66
|
+
});
|
|
33
67
|
const router = t.router;
|
|
34
68
|
t.procedure;
|
|
35
69
|
const mergeRouters = t.mergeRouters;
|
|
36
|
-
const requireScope = (scope) => t.middleware(({ ctx, next }) => {
|
|
70
|
+
const requireScope = (scope) => t.middleware(async ({ ctx, next }) => {
|
|
37
71
|
if (!ctx.user) throw new server.TRPCError({ code: "UNAUTHORIZED" });
|
|
72
|
+
if (ctx.user.isOwner) return next({ ctx });
|
|
73
|
+
const { database } = getContextDeps();
|
|
74
|
+
const rolePermissions = await database.getUserRolePermissions(ctx.user);
|
|
75
|
+
if (!permissions.userHasScope(ctx.user, scope, rolePermissions)) {
|
|
76
|
+
throw new server.TRPCError({
|
|
77
|
+
code: "FORBIDDEN",
|
|
78
|
+
message: `missing scope: ${scope}`
|
|
79
|
+
});
|
|
80
|
+
}
|
|
38
81
|
return next({ ctx });
|
|
39
82
|
});
|
|
40
|
-
const protectedProcedure = (scope) => t.procedure.use(requireScope());
|
|
83
|
+
const protectedProcedure = (scope) => t.procedure.use(requireScope(scope));
|
|
41
84
|
exports.createContext = createContext;
|
|
42
85
|
exports.getContextDeps = getContextDeps;
|
|
43
86
|
exports.mergeRouters = mergeRouters;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trpc.js","sources":["../../../src/webserver/backend/trpc.ts"],"sourcesContent":["import Logger from '@/logger';\nimport type Omegga from '@omegga/server';\nimport { initTRPC, TRPCError } from '@trpc/server';\nimport type { CreateExpressContextOptions } from '@trpc/server/adapters/express';\nimport type Database from './database';\nimport type { Scope } from './scopes';\nimport type { IStoreUser } from './types';\n\nexport type ContextDeps = {\n database: Database;\n omegga: Omegga;\n};\n\nlet _deps: ContextDeps | null = null;\n\nexport function setContextDeps(deps: ContextDeps) {\n _deps = deps;\n}\n\nexport function getContextDeps(): ContextDeps {\n if (!_deps) throw new Error('tRPC context deps not initialized');\n return _deps;\n}\n\nexport type Context = {\n user: IStoreUser & { _id: string };\n log: (...args: any[]) => void;\n error: (...args: any[]) => void;\n};\n\nexport async function createContext(\n opts: CreateExpressContextOptions,\n): Promise<Context> {\n const { database } = getContextDeps();\n const req = opts.req;\n\n const
|
|
1
|
+
{"version":3,"file":"trpc.js","sources":["../../../src/webserver/backend/trpc.ts"],"sourcesContent":["import Logger from '@/logger';\nimport type Omegga from '@omegga/server';\nimport { initTRPC, TRPCError } from '@trpc/server';\nimport type { CreateExpressContextOptions } from '@trpc/server/adapters/express';\nimport type Database from './database';\nimport { serverEvents } from './events';\nimport { userHasScope } from './permissions';\nimport type { Scope } from './scopes';\nimport type { IStoreUser } from './types';\n\nexport type ContextDeps = {\n database: Database;\n omegga: Omegga;\n};\n\nlet _deps: ContextDeps | null = null;\n\nexport function setContextDeps(deps: ContextDeps) {\n _deps = deps;\n}\n\nexport function getContextDeps(): ContextDeps {\n if (!_deps) throw new Error('tRPC context deps not initialized');\n return _deps;\n}\n\nexport type Context = {\n user: IStoreUser & { _id: string };\n req: import('express').Request;\n userAbort: AbortController;\n log: (...args: any[]) => void;\n error: (...args: any[]) => void;\n};\n\nexport async function createContext(\n opts: CreateExpressContextOptions,\n): Promise<Context> {\n const { database } = getContextDeps();\n const req = opts.req;\n\n const session = (req as any).session;\n if (session?.mfaPending) {\n throw new TRPCError({ code: 'UNAUTHORIZED' });\n }\n const userId = session?.userId;\n const user = await database.findUserById(userId);\n if (!user || user.isBanned) {\n throw new TRPCError({ code: 'UNAUTHORIZED' });\n }\n\n // Update lastOnline (migrated from Socket.IO connect handler)\n await database.stores.users.update<IStoreUser>(\n { _id: user._id },\n { $set: { lastOnline: Date.now() } },\n );\n\n const usernameText = `[${(user.username || 'Admin').brightMagenta}]`;\n\n let _userAbort: AbortController | null = null;\n const getUserAbort = () => {\n if (!_userAbort) {\n _userAbort = new AbortController();\n const ac = _userAbort;\n const onInvalidated = (name: string) => {\n if (name === user.username) ac.abort();\n };\n serverEvents.on('userInvalidated', onInvalidated);\n ac.signal.addEventListener('abort', () => {\n serverEvents.off('userInvalidated', onInvalidated);\n });\n }\n return _userAbort;\n };\n\n return {\n user,\n req,\n get userAbort() {\n return getUserAbort();\n },\n log: (...args: any[]) => Logger.logp(usernameText, ...args),\n error: (...args: any[]) => Logger.errorp(usernameText, ...args),\n };\n}\n\nconst t = initTRPC.context<Context>().create({\n errorFormatter({ shape, error, path, ctx }) {\n const user = (ctx as Context | undefined)?.user?.username || '?';\n Logger.errorp(\n `[${user.brightMagenta}]`,\n `${error.code} ${path ?? '?'}: ${error.message}`,\n );\n return shape;\n },\n});\n\nexport const router = t.router;\nexport const publicProcedure = t.procedure;\nexport const mergeRouters = t.mergeRouters;\n\nexport const requireScope = (scope: Scope) =>\n t.middleware(async ({ ctx, next }) => {\n if (!ctx.user) throw new TRPCError({ code: 'UNAUTHORIZED' });\n if (ctx.user.isOwner) return next({ ctx });\n const { database } = getContextDeps();\n const rolePermissions = await database.getUserRolePermissions(ctx.user);\n if (!userHasScope(ctx.user, scope, rolePermissions)) {\n throw new TRPCError({\n code: 'FORBIDDEN',\n message: `missing scope: ${scope}`,\n });\n }\n return next({ ctx });\n });\n\nexport const protectedProcedure = (scope: Scope) =>\n t.procedure.use(requireScope(scope));\n"],"names":["TRPCError","serverEvents","Logger","initTRPC","userHasScope"],"mappings":";;;;;;AAeA,IAAI,QAA4B;AAEzB,SAAS,eAAe,MAAmB;AAChD,UAAQ;AACV;AAEO,SAAS,iBAA8B;AAC5C,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,mCAAmC;AAC/D,SAAO;AACT;AAUA,eAAsB,cACpB,MACkB;AAClB,QAAM,EAAE,SAAA,IAAa,eAAA;AACrB,QAAM,MAAM,KAAK;AAEjB,QAAM,UAAW,IAAY;AAC7B,MAAI,SAAS,YAAY;AACvB,UAAM,IAAIA,OAAAA,UAAU,EAAE,MAAM,gBAAgB;AAAA,EAC9C;AACA,QAAM,SAAS,SAAS;AACxB,QAAM,OAAO,MAAM,SAAS,aAAa,MAAM;AAC/C,MAAI,CAAC,QAAQ,KAAK,UAAU;AAC1B,UAAM,IAAIA,OAAAA,UAAU,EAAE,MAAM,gBAAgB;AAAA,EAC9C;AAGA,QAAM,SAAS,OAAO,MAAM;AAAA,IAC1B,EAAE,KAAK,KAAK,IAAA;AAAA,IACZ,EAAE,MAAM,EAAE,YAAY,KAAK,IAAA,IAAM;AAAA,EAAE;AAGrC,QAAM,eAAe,KAAK,KAAK,YAAY,SAAS,aAAa;AAEjE,MAAI,aAAqC;AACzC,QAAM,eAAe,MAAM;AACzB,QAAI,CAAC,YAAY;AACf,mBAAa,IAAI,gBAAA;AACjB,YAAM,KAAK;AACX,YAAM,gBAAgB,CAAC,SAAiB;AACtC,YAAI,SAAS,KAAK,SAAU,IAAG,MAAA;AAAA,MACjC;AACAC,0BAAa,GAAG,mBAAmB,aAAa;AAChD,SAAG,OAAO,iBAAiB,SAAS,MAAM;AACxCA,4BAAa,IAAI,mBAAmB,aAAa;AAAA,MACnD,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,IAAI,YAAY;AACd,aAAO,aAAA;AAAA,IACT;AAAA,IACA,KAAK,IAAI,SAAgBC,OAAAA,QAAO,KAAK,cAAc,GAAG,IAAI;AAAA,IAC1D,OAAO,IAAI,SAAgBA,OAAAA,QAAO,OAAO,cAAc,GAAG,IAAI;AAAA,EAAA;AAElE;AAEA,MAAM,IAAIC,OAAAA,SAAS,QAAA,EAAmB,OAAO;AAAA,EAC3C,eAAe,EAAE,OAAO,OAAO,MAAM,OAAO;AAC1C,UAAM,OAAQ,KAA6B,MAAM,YAAY;AAC7DD,WAAAA,QAAO;AAAA,MACL,IAAI,KAAK,aAAa;AAAA,MACtB,GAAG,MAAM,IAAI,IAAI,QAAQ,GAAG,KAAK,MAAM,OAAO;AAAA,IAAA;AAEhD,WAAO;AAAA,EACT;AACF,CAAC;AAEM,MAAM,SAAS,EAAE;AACO,EAAE;AAC1B,MAAM,eAAe,EAAE;AAEvB,MAAM,eAAe,CAAC,UAC3B,EAAE,WAAW,OAAO,EAAE,KAAK,WAAW;AACpC,MAAI,CAAC,IAAI,KAAM,OAAM,IAAIF,OAAAA,UAAU,EAAE,MAAM,gBAAgB;AAC3D,MAAI,IAAI,KAAK,gBAAgB,KAAK,EAAE,KAAK;AACzC,QAAM,EAAE,SAAA,IAAa,eAAA;AACrB,QAAM,kBAAkB,MAAM,SAAS,uBAAuB,IAAI,IAAI;AACtE,MAAI,CAACI,YAAAA,aAAa,IAAI,MAAM,OAAO,eAAe,GAAG;AACnD,UAAM,IAAIJ,OAAAA,UAAU;AAAA,MAClB,MAAM;AAAA,MACN,SAAS,kBAAkB,KAAK;AAAA,IAAA,CACjC;AAAA,EACH;AACA,SAAO,KAAK,EAAE,KAAK;AACrB,CAAC;AAEI,MAAM,qBAAqB,CAAC,UACjC,EAAE,UAAU,IAAI,aAAa,KAAK,CAAC;;;;;;;;"}
|