mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-14 07:24:52 +09:00
The list of waiting hosts opens the approval dialog instead of having its own name input and buttons, so hosts are approved in one place. Removes the limit on requests per minute, the limits on pending requests already cap what an address can do. Also updates text that still said the installer makes the requests.
616 lines
17 KiB
TypeScript
616 lines
17 KiB
TypeScript
/**
|
|
* User and permissions library
|
|
*
|
|
* Defines data types for users, roles and permissions.
|
|
*
|
|
* @author Hornwitser
|
|
* @module lib/users
|
|
*/
|
|
import type { PluginNodeEnvInfo, PluginWebEnvInfo } from "./plugin.js";
|
|
import { Permission } from "./data/index.js";
|
|
|
|
export const permissions = new Map<string, Permission>();
|
|
|
|
/**
|
|
* Registry of known permission names.
|
|
*
|
|
* Plugins add their permissions with module augmentation:
|
|
*
|
|
* ```ts
|
|
* declare module "@clusterio/lib" {
|
|
* export interface Permissions {
|
|
* "foo_frobber.frobnicate": never;
|
|
* }
|
|
* }
|
|
* ```
|
|
*
|
|
* Only the keys matter, the values are always never.
|
|
*/
|
|
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
export interface Permissions extends Record<(typeof corePermissions)[number]["name"], never> {}
|
|
|
|
/** Name of a permission known at compile time, see {@link Permissions}. */
|
|
export type PermissionName = keyof Permissions;
|
|
|
|
/** Definition of a permission, see {@link definePermission}. */
|
|
export type PermissionDefinition = {
|
|
/** The internal name for the permission. */
|
|
name: PermissionName,
|
|
/** User facing name for the permission. */
|
|
title: string,
|
|
/** User facing description. */
|
|
description: string,
|
|
/** If true this permission is granted by the generated Player role by default. */
|
|
grantByDefault?: boolean,
|
|
};
|
|
|
|
/**
|
|
* Define a new user permission for Clusterio
|
|
*
|
|
* Defines a permission for use in Clusterio. Defined permissions can be
|
|
* granted to roles, and checked on users. Name should be `lower_case`
|
|
* style and start with the plugin name followed by a dot.
|
|
*
|
|
* Plugins should prefer declaring permissions in the `permissions` array
|
|
* of their {@link PluginDeclaration}, which is registered by
|
|
* {@link registerPluginPermissions}.
|
|
*
|
|
* @param def - The definition for the permission.
|
|
*/
|
|
export function definePermission({
|
|
name,
|
|
title,
|
|
description,
|
|
grantByDefault = false,
|
|
}: PermissionDefinition) {
|
|
if (typeof name !== "string" || !name.length) {
|
|
throw new Error("Expected name to be a non-empty string");
|
|
}
|
|
if (typeof title !== "string" || !title.length) {
|
|
throw new Error("Expected title to be a non-empty string");
|
|
}
|
|
if (typeof description !== "string" || !description.length) {
|
|
throw new Error("Expected description to be a non-empty string");
|
|
}
|
|
if (typeof grantByDefault !== "boolean") {
|
|
throw new Error("Expected grantByDefault to be a boolean");
|
|
}
|
|
|
|
if (permissions.has(name)) {
|
|
throw new Error(`Permission '${name}' is already defined`);
|
|
}
|
|
|
|
permissions.set(name, new Permission(name, title, description, grantByDefault));
|
|
}
|
|
|
|
/**
|
|
* Define all permissions declared by the provided plugin infos
|
|
*
|
|
* @param pluginInfos - Array of plugin info objects.
|
|
*/
|
|
export function registerPluginPermissions(pluginInfos: PluginNodeEnvInfo[] | PluginWebEnvInfo[]) {
|
|
for (const pluginInfo of pluginInfos) {
|
|
for (const permission of pluginInfo.permissions ?? []) {
|
|
if (typeof permission.name !== "string" || !permission.name.startsWith(`${pluginInfo.name}.`)) {
|
|
throw new Error(
|
|
`Expected name of permission '${permission.name}' for ${pluginInfo.name} ` +
|
|
`to start with '${pluginInfo.name}.'`
|
|
);
|
|
}
|
|
definePermission(permission);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Definitions for the built in permissions used in Clusterio.
|
|
// description should answer "this permission allows you to ___"
|
|
export const corePermissions = [
|
|
{
|
|
name: "core.admin",
|
|
title: "Administrator",
|
|
description: "Bypass all permission checks.",
|
|
},
|
|
{
|
|
name: "core.control.connect",
|
|
title: "Connect to WebSocket",
|
|
description: "Connect to the controller's WebSocket control interface.",
|
|
grantByDefault: true,
|
|
},
|
|
|
|
{
|
|
name: "core.controller.stop",
|
|
title: "Stop controller",
|
|
description:
|
|
"Stop the Node.js controller process making the cluster inoperable until someone with access to the " +
|
|
"system it runs on manually starts it again.",
|
|
},
|
|
{
|
|
name: "core.controller.restart",
|
|
title: "Restart controller",
|
|
description: "Restart the Node.js controller process if the system is set up for restarting.",
|
|
},
|
|
{
|
|
name: "core.controller.update",
|
|
title: "Update controller",
|
|
description: "Remotely update the controller if the controller allows for remote updates.",
|
|
},
|
|
{
|
|
name: "core.controller.get_config",
|
|
title: "Get controller config",
|
|
description: "Get the config of controller.",
|
|
},
|
|
{
|
|
name: "core.controller.update_config",
|
|
title: "Modify controller config",
|
|
description: "Modify the controller config or entries of the controller config.",
|
|
},
|
|
{
|
|
name: "core.controller.metrics",
|
|
title: "Scrape metrics",
|
|
description: "Fetch the Prometheus metrics for the cluster from the controller's /metrics endpoint.",
|
|
},
|
|
{
|
|
name: "core.system.subscribe",
|
|
title: "Subscribe to system updates",
|
|
description:
|
|
"Subscribe to be notified when the system info detailing system specific information along with metrics " +
|
|
"such as cpu, memory and disk usage for the controller and hosts are updated.",
|
|
},
|
|
{
|
|
name: "core.host.stop",
|
|
title: "Stop Hosts",
|
|
description:
|
|
"Stop Node.js host processes making the host inaccessible until someone with access to the system " +
|
|
"it runs on manually starts it again.",
|
|
},
|
|
{
|
|
name: "core.host.restart",
|
|
title: "Restart Hosts",
|
|
description: "Restart Node.js host processes if the system they run on are set up for restarting.",
|
|
},
|
|
{
|
|
name: "core.host.update",
|
|
title: "Update Hosts",
|
|
description: "Remotely update a host if the host allows for remote updates.",
|
|
},
|
|
{
|
|
name: "core.host.get_config",
|
|
title: "Get host configs",
|
|
description: "Get the config of hosts.",
|
|
},
|
|
{
|
|
name: "core.host.update_config",
|
|
title: "Modify host configs",
|
|
description: "Modify the host config or entries of the host config.",
|
|
},
|
|
{
|
|
name: "core.host.list",
|
|
title: "List hosts",
|
|
description: "Get the full list of hosts in the cluster.",
|
|
grantByDefault: true,
|
|
},
|
|
{
|
|
name: "core.host.subscribe",
|
|
title: "Subscribe to host updates",
|
|
description: "Subscribe to be notified on updates on the details of hosts.",
|
|
grantByDefault: true,
|
|
},
|
|
{
|
|
name: "core.host.approve",
|
|
title: "Approve hosts",
|
|
description:
|
|
"List, approve and reject requests from hosts to join the cluster, and approve hosts " +
|
|
"directly by starting them with a user token. Approving gives the new host full access to the cluster.",
|
|
},
|
|
{
|
|
name: "core.host.revoke",
|
|
title: "Revoke hosts",
|
|
description: "Remove hosts from the cluster, disconnecting them and making their access tokens invalid.",
|
|
},
|
|
|
|
{
|
|
name: "core.instance.get",
|
|
title: "Get instance",
|
|
description: "Get the details of an instance in the cluster.",
|
|
grantByDefault: true,
|
|
},
|
|
{
|
|
name: "core.instance.list",
|
|
title: "List instances",
|
|
description: "Get the full list of instances in the cluster.",
|
|
grantByDefault: true,
|
|
},
|
|
{
|
|
name: "core.instance.subscribe",
|
|
title: "Subscribe to instance updates",
|
|
description: "Subscribe to be notified on updates on the details and status of instances.",
|
|
grantByDefault: true,
|
|
},
|
|
{
|
|
name: "core.instance.create",
|
|
title: "Create instance",
|
|
description: "Create new instances on the controller.",
|
|
},
|
|
{
|
|
name: "core.instance.get_config",
|
|
title: "Get instance config",
|
|
description: "Get the config of instances.",
|
|
},
|
|
{
|
|
name: "core.instance.update_config",
|
|
title: "Modify instance config",
|
|
description: "Modify the config or entries of the config for instances.",
|
|
},
|
|
{
|
|
name: "core.instance.assign",
|
|
title: "Assign instance",
|
|
description: "Assign or reassign instances to a host.",
|
|
},
|
|
{
|
|
name: "core.instance.save.list",
|
|
title: "List saves",
|
|
description: "List the saves currently on instances.",
|
|
},
|
|
{
|
|
name: "core.instance.save.subscribe",
|
|
title: "Subscribe to save updates",
|
|
description: "Subscribe to be notifed on updates to the list of saves of instances.",
|
|
},
|
|
{
|
|
name: "core.instance.save.create",
|
|
title: "Create new save",
|
|
description: "Create new savegames on instances.",
|
|
},
|
|
{
|
|
name: "core.instance.save.rename",
|
|
title: "Rename save",
|
|
description: "Rename savegames on instances.",
|
|
},
|
|
{
|
|
name: "core.instance.save.copy",
|
|
title: "Copy save",
|
|
description: "Create copies of savegames on instances.",
|
|
},
|
|
{
|
|
name: "core.instance.save.delete",
|
|
title: "Delete save",
|
|
description: "Delete savegames on instances.",
|
|
},
|
|
{
|
|
name: "core.instance.save.upload",
|
|
title: "Upload save",
|
|
description: "Upload savegames to instances.",
|
|
},
|
|
{
|
|
name: "core.instance.save.transfer",
|
|
title: "Transfer save",
|
|
description: "Transfer savegames between instances.",
|
|
},
|
|
{
|
|
name: "core.instance.save.download",
|
|
title: "Download save",
|
|
description: "Download savegames from instances.",
|
|
},
|
|
{
|
|
name: "core.instance.export_data",
|
|
title: "Export locale and icons",
|
|
description: "Export the the locale and icons from an instance and upload it to the controller.",
|
|
},
|
|
{
|
|
name: "core.instance.extract_players",
|
|
title: "Extract player stats from running save",
|
|
description:
|
|
"Run extraction to create a user for each player in the save and set the online time from the save.",
|
|
},
|
|
{
|
|
name: "core.instance.start",
|
|
title: "Start instance",
|
|
description: "Start instances.",
|
|
},
|
|
{
|
|
name: "core.instance.restart",
|
|
title: "Restart instance",
|
|
description: "Restart instances.",
|
|
},
|
|
{
|
|
name: "core.instance.load_scenario",
|
|
title: "Load scenario",
|
|
description: "Start instances by loading a scenario.",
|
|
},
|
|
{
|
|
name: "core.instance.stop",
|
|
title: "Stop instance",
|
|
description: "Stop instances.",
|
|
},
|
|
{
|
|
name: "core.instance.kill",
|
|
title: "Kill instance",
|
|
description: "Terminate running instances without saving or cleanup.",
|
|
},
|
|
{
|
|
name: "core.instance.delete",
|
|
title: "Delete instance",
|
|
description: "Delete instances (includes config and all files stored like saves and logs).",
|
|
},
|
|
{
|
|
name: "core.instance.send_rcon",
|
|
title: "Send RCON",
|
|
description: "Send arbitrary RCON commands to instances.",
|
|
},
|
|
|
|
{
|
|
name: "core.mod_pack.get",
|
|
title: "Retrieve mod pack",
|
|
description: "Get the details of a mod pack in the cluster.",
|
|
grantByDefault: true,
|
|
},
|
|
{
|
|
name: "core.mod_pack.list",
|
|
title: "List mod packs",
|
|
description: "Get the full list of a mod packs in the cluster.",
|
|
grantByDefault: true,
|
|
},
|
|
{
|
|
name: "core.mod_pack.subscribe",
|
|
title: "Subscribe to mod pack updates",
|
|
description: "Subscribe to be notified on updates on the details of mod packs.",
|
|
grantByDefault: true,
|
|
},
|
|
{
|
|
name: "core.mod_pack.create",
|
|
title: "Create mod pack",
|
|
description: "Create new mod pack in the cluster.",
|
|
},
|
|
{
|
|
name: "core.mod_pack.update",
|
|
title: "Update mod pack",
|
|
description: "Edit existing mod pack definition in the cluster.",
|
|
},
|
|
{
|
|
name: "core.mod_pack.delete",
|
|
title: "Delete mod pack",
|
|
description: "Delete mod pack definition in the cluster.",
|
|
},
|
|
{
|
|
name: "core.mod.get",
|
|
title: "Get mods",
|
|
description: "Get the details of a mod stored in the cluster.",
|
|
grantByDefault: true,
|
|
},
|
|
{
|
|
name: "core.mod.list",
|
|
title: "List mods",
|
|
description: "Get the full list of mods stored on the controller.",
|
|
grantByDefault: true,
|
|
},
|
|
{
|
|
name: "core.mod.search",
|
|
title: "Search mods",
|
|
description: "Search through the list of mods stored on the controller.",
|
|
grantByDefault: true,
|
|
},
|
|
{
|
|
name: "core.mod.search_portal",
|
|
title: "Search mod portal",
|
|
description: "Search for mods on the Factorio mod portal.",
|
|
grantByDefault: true,
|
|
},
|
|
{
|
|
name: "core.mod.subscribe",
|
|
title: "Subscribe to mod updates",
|
|
description: "Subscribe to be notified on updates on the details of mods.",
|
|
grantByDefault: true,
|
|
},
|
|
{
|
|
name: "core.mod.upload",
|
|
title: "Upload mods",
|
|
description: "Upload mods to the controller.",
|
|
},
|
|
{
|
|
name: "core.mod.download",
|
|
title: "Download mod",
|
|
description: "Download mods stored on the controller.",
|
|
grantByDefault: true,
|
|
},
|
|
{
|
|
name: "core.mod.delete",
|
|
title: "Delete mod",
|
|
description: "Delete mods stored on the controller.",
|
|
},
|
|
{
|
|
name: "core.mod.download_from_portal",
|
|
title: "Download mods from portal",
|
|
description: "Allow downloading mods directly from the Factorio mod portal to the controller.",
|
|
grantByDefault: true,
|
|
},
|
|
|
|
{
|
|
name: "core.permission.list",
|
|
title: "List permissions",
|
|
description: "Get the full list of permissions in the cluster.",
|
|
grantByDefault: true,
|
|
},
|
|
|
|
{
|
|
name: "core.role.list",
|
|
title: "List roles",
|
|
description: "Get the full list of roles and their permissions in the cluster.",
|
|
grantByDefault: true,
|
|
},
|
|
{
|
|
name: "core.role.subscribe",
|
|
title: "Subscribe to role updates",
|
|
description: "Subscribe to be notified on updates on the details of roles.",
|
|
grantByDefault: true,
|
|
},
|
|
{
|
|
name: "core.role.create",
|
|
title: "Create role",
|
|
description: "Create new roles with permissions.",
|
|
},
|
|
{
|
|
name: "core.role.update",
|
|
title: "Update role",
|
|
description: "Edit existing roles including permissions they grant.",
|
|
},
|
|
{
|
|
name: "core.role.delete",
|
|
title: "Delete role",
|
|
description: "Permanently delete roles.",
|
|
},
|
|
|
|
{
|
|
name: "core.note.list",
|
|
title: "List notes",
|
|
description: "Get the full list of notes attached to resources in the cluster.",
|
|
grantByDefault: true,
|
|
},
|
|
{
|
|
name: "core.note.subscribe",
|
|
title: "Subscribe to note updates",
|
|
description: "Subscribe to be notified when notes attached to resources are updated.",
|
|
grantByDefault: true,
|
|
},
|
|
{
|
|
name: "core.note.update",
|
|
title: "Update notes",
|
|
description: "Write, edit and remove notes attached to resources in the cluster.",
|
|
},
|
|
|
|
{
|
|
name: "core.user.get",
|
|
title: "Get user",
|
|
description: "Get the details of a user in the cluster.",
|
|
grantByDefault: true,
|
|
},
|
|
{
|
|
name: "core.user.list",
|
|
title: "List users",
|
|
description: "Get the full list of users in the cluster.",
|
|
grantByDefault: true,
|
|
},
|
|
{
|
|
name: "core.user.subscribe",
|
|
title: "Subscribe to user updates",
|
|
description: "Subscribe to be notified on updates on the details and status of users.",
|
|
grantByDefault: true,
|
|
},
|
|
{
|
|
name: "core.user.create",
|
|
title: "Create users",
|
|
description: "Create user acounts with a given name.",
|
|
},
|
|
{
|
|
name: "core.user.revoke_token",
|
|
title: "Revoke user token",
|
|
description: "Revoke access token and terminate all existing control connections for oneself.",
|
|
grantByDefault: true,
|
|
},
|
|
{
|
|
name: "core.user.revoke_other_token",
|
|
title: "Revoke other user's token",
|
|
description: "Allow revoking tokens for other users than oneself. Requires Revoke user token.",
|
|
},
|
|
{
|
|
name: "core.user.update_roles",
|
|
title: "Update user roles",
|
|
description: "Add or remove any role to any user.",
|
|
},
|
|
{
|
|
name: "core.user.set_admin",
|
|
title: "Set user admin status",
|
|
description: "Promote or demote any user to Factorio admin.",
|
|
},
|
|
{
|
|
name: "core.user.set_banned",
|
|
title: "Set user ban status",
|
|
description: "Ban or unban any user.",
|
|
},
|
|
{
|
|
name: "core.user.set_whitelisted",
|
|
title: "Set user whitelist status",
|
|
description: "Add or remove any user to/from the whitelist.",
|
|
},
|
|
{
|
|
name: "core.user.delete",
|
|
title: "Delete user",
|
|
description: "Delete users and all data stored for them.",
|
|
},
|
|
{
|
|
name: "core.user.bulk_import",
|
|
title: "Bulk user import",
|
|
description: "Bulk import users including admin, whitelist, and bans." +
|
|
" (Imports types are restricted by other permissions, e.g. core.user.set_admin)",
|
|
},
|
|
{
|
|
name: "core.user.bulk_export",
|
|
title: "Bulk user export",
|
|
description: "Bulk export users including admin, whitelist, and bans.",
|
|
},
|
|
{
|
|
name: "core.user.bulk_restore",
|
|
title: "Bulk user restore",
|
|
description: "Bulk restore users including admin, whitelist, and bans." +
|
|
" (Restore types are restricted by other permissions, e.g. core.user.set_admin)",
|
|
},
|
|
|
|
{
|
|
name: "core.log.follow",
|
|
title: "Follow cluster log",
|
|
description: "Receive new entries in the cluster log. Required to see instance console.",
|
|
},
|
|
{
|
|
name: "core.log.query",
|
|
title: "Query cluster log",
|
|
description: "Query past entries in the cluster log. Required to see past entries in instance console.",
|
|
},
|
|
|
|
{
|
|
name: "core.plugin.list",
|
|
title: "List plugins",
|
|
description: "List all installed plugins on a machine.",
|
|
},
|
|
{
|
|
name: "core.plugin.update",
|
|
title: "Update plugin",
|
|
description: "Remotely update a plugin if the target allows remote updates of plugins.",
|
|
},
|
|
{
|
|
name: "core.plugin.install",
|
|
title: "Install plugin",
|
|
description: "Remotely install a plugin if the target allows remote installs of plugins.",
|
|
},
|
|
{
|
|
name: "core.plugin.search",
|
|
title: "Search plugins",
|
|
description: "Search the npm registry for plugins via the controller.",
|
|
},
|
|
|
|
{
|
|
name: "core.debug.dump_ws",
|
|
title: "Dump WebSocket",
|
|
description: "Dump all WebSocket communicatation from the controller.",
|
|
},
|
|
|
|
{
|
|
name: "core.external.get_factorio_versions",
|
|
title: "Get factorio versions",
|
|
description: "Get list of all factorio versions from Wube",
|
|
},
|
|
|
|
{
|
|
name: "core.external.get_latest_releases",
|
|
title: "Get factorio releases",
|
|
description: "Get the latest stable and experimental factorio releases from Wube",
|
|
},
|
|
] as const satisfies readonly {
|
|
name: string,
|
|
title: string,
|
|
description: string,
|
|
grantByDefault?: boolean,
|
|
}[];
|
|
|
|
for (const permission of corePermissions) {
|
|
definePermission(permission);
|
|
}
|