316 lines
9.6 KiB
TypeScript
316 lines
9.6 KiB
TypeScript
import "server-only";
|
|
|
|
import { z } from "zod";
|
|
import { PERMS } from "@/lib/permission-slugs";
|
|
import type { HousekeepingCommand } from "../../../foundation/commands/registry";
|
|
import { anyCapability } from "../../../foundation/contracts";
|
|
import {
|
|
type SystemMutationOperation,
|
|
type SystemMutationService,
|
|
systemMutationService,
|
|
} from "../services/mutations";
|
|
|
|
export const SYSTEM_COMMAND_IDS = [
|
|
"system.access.rank.create",
|
|
"system.access.rank.delete",
|
|
"system.access.rank.update",
|
|
"system.access.permissions.update",
|
|
"system.access.permissions.repair",
|
|
"system.configuration.settings.save",
|
|
"system.configuration.setting.create",
|
|
"system.configuration.setting.update",
|
|
"system.configuration.setting.delete",
|
|
"system.configuration.emulator-setting.update",
|
|
"system.configuration.emulator-text.update",
|
|
"system.operations.alerts.mark-read",
|
|
"system.operations.alert.broadcast",
|
|
"system.operations.rcon.update-catalog",
|
|
"system.operations.rcon.update-word-filter",
|
|
"system.operations.rcon.update-navigator",
|
|
"system.operations.rcon.hotel-alert",
|
|
"system.operations.rcon.disconnect-user",
|
|
"system.operations.rcon.alert-user",
|
|
"system.operations.rcon.forward-user",
|
|
"system.operations.rcon.give-credits",
|
|
"system.operations.rcon.give-duckets",
|
|
"system.operations.rcon.give-diamonds",
|
|
"system.operations.rcon.give-badge",
|
|
"system.operations.rcon.set-motto",
|
|
"system.operations.rcon.set-rank",
|
|
"system.operations.rcon.execute-command",
|
|
"system.operations.rcon.send-gift",
|
|
"system.operations.maintenance.update",
|
|
] as const;
|
|
|
|
interface CommandOptions<I> {
|
|
readonly id: (typeof SYSTEM_COMMAND_IDS)[number];
|
|
readonly operation: SystemMutationOperation;
|
|
readonly capability: string;
|
|
readonly input: z.ZodType<I>;
|
|
readonly requiresReason: boolean;
|
|
readonly attempts?: number;
|
|
}
|
|
|
|
function systemCommand<I>(
|
|
service: Pick<SystemMutationService, "execute">,
|
|
options: CommandOptions<I>,
|
|
): HousekeepingCommand<I, unknown> {
|
|
return {
|
|
id: options.id,
|
|
owner: "system",
|
|
risk: "sensitive",
|
|
capability: anyCapability(options.capability),
|
|
input: options.input,
|
|
requiresReason: options.requiresReason,
|
|
rateLimit: { attempts: options.attempts ?? 10, windowMs: 60_000 },
|
|
execute: (context, input) =>
|
|
service.execute(
|
|
{
|
|
capability: context.capability,
|
|
correlationId: context.correlationId,
|
|
},
|
|
options.operation,
|
|
input,
|
|
),
|
|
};
|
|
}
|
|
|
|
const empty = z.object({});
|
|
const positiveId = z.number().int().positive();
|
|
const requiredText = (max: number) => z.string().min(1).max(max).regex(/\S/u);
|
|
const settingInput = z.object({
|
|
key: requiredText(255),
|
|
value: z.string().max(65_535),
|
|
});
|
|
|
|
export function createSystemCommands(
|
|
service: Pick<SystemMutationService, "execute">,
|
|
) {
|
|
return [
|
|
systemCommand(service, {
|
|
id: "system.access.rank.create",
|
|
operation: "access.rank.create",
|
|
capability: PERMS.PERMISSIONS_MANAGE,
|
|
input: z.object({ name: requiredText(25), level: positiveId }),
|
|
requiresReason: true,
|
|
}),
|
|
systemCommand(service, {
|
|
id: "system.access.rank.delete",
|
|
operation: "access.rank.delete",
|
|
capability: PERMS.PERMISSIONS_MANAGE,
|
|
input: z.object({ id: positiveId }),
|
|
requiresReason: true,
|
|
}),
|
|
systemCommand(service, {
|
|
id: "system.access.rank.update",
|
|
operation: "access.rank.update",
|
|
capability: PERMS.PERMISSIONS_MANAGE,
|
|
input: z.object({
|
|
id: positiveId,
|
|
fields: z.record(z.string(), z.union([z.string(), z.number()])),
|
|
}),
|
|
requiresReason: true,
|
|
}),
|
|
systemCommand(service, {
|
|
id: "system.access.permissions.update",
|
|
operation: "access.permissions.update",
|
|
capability: PERMS.PERMISSIONS_MANAGE,
|
|
input: z.object({
|
|
roleId: positiveId,
|
|
permissionSlugs: z.array(requiredText(160)).max(500),
|
|
}),
|
|
requiresReason: true,
|
|
}),
|
|
systemCommand(service, {
|
|
id: "system.access.permissions.repair",
|
|
operation: "access.permissions.repair",
|
|
capability: PERMS.PERMISSIONS_MANAGE,
|
|
input: empty,
|
|
requiresReason: true,
|
|
}),
|
|
systemCommand(service, {
|
|
id: "system.configuration.settings.save",
|
|
operation: "configuration.settings.save",
|
|
capability: PERMS.SETTINGS_EDIT,
|
|
input: z.object({ settings: z.record(z.string(), z.string()) }),
|
|
requiresReason: true,
|
|
}),
|
|
systemCommand(service, {
|
|
id: "system.configuration.setting.create",
|
|
operation: "configuration.setting.create",
|
|
capability: PERMS.SETTINGS_EDIT,
|
|
input: settingInput.extend({ comment: z.string().max(255).optional() }),
|
|
requiresReason: true,
|
|
}),
|
|
systemCommand(service, {
|
|
id: "system.configuration.setting.update",
|
|
operation: "configuration.setting.update",
|
|
capability: PERMS.SETTINGS_EDIT,
|
|
input: settingInput,
|
|
requiresReason: true,
|
|
}),
|
|
systemCommand(service, {
|
|
id: "system.configuration.setting.delete",
|
|
operation: "configuration.setting.delete",
|
|
capability: PERMS.SETTINGS_EDIT,
|
|
input: z.object({ key: requiredText(255) }),
|
|
requiresReason: true,
|
|
}),
|
|
systemCommand(service, {
|
|
id: "system.configuration.emulator-setting.update",
|
|
operation: "configuration.emulator-setting.update",
|
|
capability: PERMS.SETTINGS_EDIT,
|
|
input: z.object({ key: requiredText(100), value: z.string().max(512) }),
|
|
requiresReason: false,
|
|
}),
|
|
systemCommand(service, {
|
|
id: "system.configuration.emulator-text.update",
|
|
operation: "configuration.emulator-text.update",
|
|
capability: PERMS.SETTINGS_EDIT,
|
|
input: z.object({ key: requiredText(100), value: z.string().max(4096) }),
|
|
requiresReason: false,
|
|
}),
|
|
systemCommand(service, {
|
|
id: "system.operations.alerts.mark-read",
|
|
operation: "operations.alerts.mark-read",
|
|
capability: PERMS.NOTIFICATIONS_VIEW,
|
|
input: empty,
|
|
requiresReason: false,
|
|
}),
|
|
systemCommand(service, {
|
|
id: "system.operations.alert.broadcast",
|
|
operation: "operations.alert.broadcast",
|
|
capability: PERMS.NOTIFICATIONS_EDIT,
|
|
input: z.object({ message: requiredText(1000) }),
|
|
requiresReason: true,
|
|
}),
|
|
systemCommand(service, {
|
|
id: "system.operations.rcon.update-catalog",
|
|
operation: "rcon.update-catalog",
|
|
capability: PERMS.RCON_EXECUTE,
|
|
input: empty,
|
|
requiresReason: true,
|
|
attempts: 5,
|
|
}),
|
|
systemCommand(service, {
|
|
id: "system.operations.rcon.update-word-filter",
|
|
operation: "rcon.update-word-filter",
|
|
capability: PERMS.RCON_EXECUTE,
|
|
input: empty,
|
|
requiresReason: true,
|
|
attempts: 5,
|
|
}),
|
|
systemCommand(service, {
|
|
id: "system.operations.rcon.update-navigator",
|
|
operation: "rcon.update-navigator",
|
|
capability: PERMS.RCON_EXECUTE,
|
|
input: empty,
|
|
requiresReason: true,
|
|
attempts: 5,
|
|
}),
|
|
systemCommand(service, {
|
|
id: "system.operations.rcon.hotel-alert",
|
|
operation: "rcon.hotel-alert",
|
|
capability: PERMS.RCON_EXECUTE,
|
|
input: z.object({ message: requiredText(512) }),
|
|
requiresReason: true,
|
|
attempts: 5,
|
|
}),
|
|
systemCommand(service, {
|
|
id: "system.operations.rcon.disconnect-user",
|
|
operation: "rcon.disconnect-user",
|
|
capability: PERMS.RCON_EXECUTE,
|
|
input: z.object({ userId: positiveId, username: requiredText(255) }),
|
|
requiresReason: true,
|
|
attempts: 5,
|
|
}),
|
|
systemCommand(service, {
|
|
id: "system.operations.rcon.alert-user",
|
|
operation: "rcon.alert-user",
|
|
capability: PERMS.RCON_EXECUTE,
|
|
input: z.object({ userId: positiveId, message: requiredText(512) }),
|
|
requiresReason: true,
|
|
attempts: 5,
|
|
}),
|
|
systemCommand(service, {
|
|
id: "system.operations.rcon.forward-user",
|
|
operation: "rcon.forward-user",
|
|
capability: PERMS.RCON_EXECUTE,
|
|
input: z.object({ userId: positiveId, roomId: positiveId }),
|
|
requiresReason: true,
|
|
attempts: 5,
|
|
}),
|
|
...[
|
|
["give-credits", "rcon.give-credits"],
|
|
["give-duckets", "rcon.give-duckets"],
|
|
["give-diamonds", "rcon.give-diamonds"],
|
|
].map(([suffix, operation]) =>
|
|
systemCommand(service, {
|
|
id: `system.operations.rcon.${suffix}` as (typeof SYSTEM_COMMAND_IDS)[number],
|
|
operation: operation as SystemMutationOperation,
|
|
capability: PERMS.RCON_EXECUTE,
|
|
input: z.object({ userId: positiveId, amount: positiveId }),
|
|
requiresReason: true,
|
|
attempts: 5,
|
|
}),
|
|
),
|
|
systemCommand(service, {
|
|
id: "system.operations.rcon.give-badge",
|
|
operation: "rcon.give-badge",
|
|
capability: PERMS.RCON_EXECUTE,
|
|
input: z.object({ userId: positiveId, badge: requiredText(32) }),
|
|
requiresReason: true,
|
|
attempts: 5,
|
|
}),
|
|
systemCommand(service, {
|
|
id: "system.operations.rcon.set-motto",
|
|
operation: "rcon.set-motto",
|
|
capability: PERMS.RCON_EXECUTE,
|
|
input: z.object({ userId: positiveId, motto: requiredText(127) }),
|
|
requiresReason: true,
|
|
attempts: 5,
|
|
}),
|
|
systemCommand(service, {
|
|
id: "system.operations.rcon.set-rank",
|
|
operation: "rcon.set-rank",
|
|
capability: PERMS.RCON_EXECUTE,
|
|
input: z.object({ userId: positiveId, rank: positiveId.max(9999) }),
|
|
requiresReason: true,
|
|
attempts: 5,
|
|
}),
|
|
systemCommand(service, {
|
|
id: "system.operations.rcon.execute-command",
|
|
operation: "rcon.execute-command",
|
|
capability: PERMS.RCON_EXECUTE,
|
|
input: z.object({ userId: positiveId, command: requiredText(100) }),
|
|
requiresReason: true,
|
|
attempts: 5,
|
|
}),
|
|
systemCommand(service, {
|
|
id: "system.operations.rcon.send-gift",
|
|
operation: "rcon.send-gift",
|
|
capability: PERMS.RCON_EXECUTE,
|
|
input: z.object({
|
|
userId: positiveId,
|
|
itemId: positiveId,
|
|
message: z.string().max(255).optional(),
|
|
}),
|
|
requiresReason: true,
|
|
attempts: 5,
|
|
}),
|
|
systemCommand(service, {
|
|
id: "system.operations.maintenance.update",
|
|
operation: "operations.maintenance.update",
|
|
capability: PERMS.SETTINGS_EDIT,
|
|
input: z.object({
|
|
enabled: z.boolean(),
|
|
message: z.string().max(65_535),
|
|
minimumLoginRank: z.number().int().min(0),
|
|
}),
|
|
requiresReason: true,
|
|
}),
|
|
] as const;
|
|
}
|
|
|
|
export const SYSTEM_COMMANDS = createSystemCommands(systemMutationService);
|