π§
This is the successor of Fork-legacy and aims to be a general purpose Minecraft Server Manager GUI, that allows individuals to host Minecraft servers with very little knowledge.
- Platform independent (Runs on Windows, Mac and Linux)
- Clean and seamless UI
- Free and Open Source (no hidden costs and everyone can contribute code)
- Fast server setup (Most of the stuff is less than 5 clicks away)
- Support for a wide range of different servers (Vanilla, Paper, Waterfall, ...)
- Integrated Discord-Bot to control your server from Discord
- Automatic server start, stop and restart
- In-App Code Editor for editing you server configuration files
- and many many more...
This repository is only the backend part of the Fork App, which is the core application. There is also a frontend implemented in Blazor Webassambly found in the ForkFrontend repository and a common library hosted found in the ForkCommon repository.
As both the backend and frontend are written in C# and specifically in .NET 6 we can use the common library as a shared space for both of them and that's why the objects, that are transported between them are there.
Fork is based on two communication layers, the first one is a REST-API that is used to send commands from the frontend ( or any other service) to the backend. The second one is a WebSocket that is hosted by the backend, where the frontend ( or any other service) can subscribe to notifications, like server status changes, etc.
Running this application in development mode will host a swagger documentation on http://localhost:35565/swagger
, so
you can explore the API yourself and get more infos about the endpoints. Notice, that all requests must have
the Authorization
-Header set with the token as value. More Infos about authorization later on.
This documentation will also be provided on the Fork website at a later stage.
All endoints start with /v1/application
Method | Endpoint | Required Privilege | Description |
---|---|---|---|
GET | /state | any | Get the current state of the application |
as State object | |||
GET | /privileges | any | Get a list of privileges associated to the provided token |
All endoints start with /v1/entity
Method | Endpoint | Required Privilege | Description |
---|---|---|---|
POST | /createserver | CreateEntityPrivilege | Creates a new server based on the |
provided CreateServerPayload | |||
POST | /{EntityId}/start | WriteConsoleTabPrivilege | Starts the specified entity |
POST | /{EntityId}/stop | WriteConsoleTabPrivilege | Stops the specified entity |
POST | /{EntityId}/restart | WriteConsoleTabPrivilege | Restarts the specified entity by executing stop and start |
POST | /{EntityId}/consolein | WriteConsoleTabPrivilege | Write a line to the console of the specified entity. The |
body is interpreted as plain text input | |||
GET | /{EntityId}/console | ReadConsoleConsoleTabPrivilege | Get a list of all console messages for an entity (Max. |
1000 messages) | |||
The WebSocket is used for sending updates to all clients simultaneously, which propagates the state of the app to all clients to keep everything up to date. A typical frontend should send commands through the API and subscribe to this WebSocket to update the UI according to the state of the app.
To subscribe to the WebSocket you need to connect to the WebSocket Server and send the following subscribe message:
{token}
Read more about this and the Token in the Authorization part of this readme
At the current state your WebSocket connection is then getting all notifications that are emitted if you have the privilege to receive them. At a later stage there will be a more advanced mechanism, where the UI can register to certain notifications, which helps in network performance.
Each Notification is sent as JSON blob and is represented by a C# class in this table
Notification | Required Privilege | Description |
---|---|---|
Each notification has an EntityId from the related entity attached
Notification | Required Privilege | Description |
---|---|---|
ConsoleAddNotification | ReadConsoleConsoleTabPrivilege | Fired after a line is added to the console by either a user or the Minecraft server |
EntityStatusChangedNotification | IReadEntityPrivilege | Fired after the status of an entity changes (Started, Stopped, ...) |
UpdatePlayerNotification | ReadPlayerlistConsoleTabPrivilege | Fired after a player on the playerlist is updated (Added or Changed) |
UpdateBanlistPlayerNotification | ReadBanlistConsoleTabPrivilege | Fired after a player is added, removed or updated on the banlist |
UpdateWhitelistPlayerNotification | ReadWhitelistConsoleTabPrivilege | Fired after a player is added, removed or updated on the whitelist |
Because the communication of Fork is open to all connections and any 3rd party app as well as multiple users with different privileges can join at the same time. For this reason there is a token based authorization process at the core of Fork.
In this part we will cover the basics of how the authorization system works
Privileges are based on a tree like structure that decides what a token is able to do and what information it can
access.
The full tree:
Admin
βββ Application
β βββ Create Entity
β βββ Delete Entity
β βββ Rename Entity
β βββ Update Application (Stops all servers)
βββ AppSettings
β βββ Read AppSettings
β β βββ Read General
β β βββ Read Discord Bot
β β βββ Read Tokens (Only token settings not the acutal tokens)
β β βββ Read Advanced
β βββ Write AppSettings
β βββ Write General
β βββ Write Discord Bot
β βββ Write Tokens (This can be used to gain admin!)
β βββ Write Advanced
βββ Entity (One Node for each entity)
βββ Read Entity
β βββ Read ConsoleTab
β β βββ Read Console
β β βββ Read Playerlist
β β βββ Read Banlist
β β βββ Read Whitelist
β βββ Read SettingsTab
β β βββ Read Settings
β β βββ Read server.properties
β β βββ Read version specific files
β βββ Read WorldsTab
β βββ Read PluginsTab (only if available)
β βββ Read ModsTab (only if available)
βββ Write Entity
βββ Write ConsoleTab
βββ Write SettingsTab
β βββ Write Settings
β βββ Write server.properties
β βββ Write version specific files
βββ Write WorldsTab
βββ Write PluginsTab (only if available)
βββ Write ModsTab (only if available)
Each command in the API and each Notification require a certain node in this tree. Granting access to a node of this graph will allow the token access to all the sub-nodes connected to that node.
Examples:
Granting access to the Read Discord Bot
node will only allow him to see the settings not to write them
Granting access to the Read AppSettings
node will also only allow to read, but all of the Settings on that page
Granting access to the AppSettings
node will allow read and write access to all AppSettings
Granting access to the Read AppSettings
node and the Write Discord Bot
node will allow the token to read all
settings, but only modify the Discord Bot settings
The token is a key part of how the authorization works and is used to authenticate against the application. The token should be kept secret from all non authorized people, this means that the token should never be shared and all communication with the app should be done over https.
There are some basic principles for tokens:
- Tokens can be created, changed and deleted at any time by anyone with the according privilege
- Connections without a token will ALWAYS result in a
401 Unauthorized
response
As localhost:
There is a local token created while installing Fork, which automatically has Admin
priviledges. This token is stored
in the installation path of Fork, so everyone with access to that directory has access to that token!
As remote: The preferred approach is to make an input field for the user to input a token before connecting to the app. Be carefull when storing the token somewhere!
For local applications you can just read the local Admin
token and the settings of Fork to get the ports for API and
WebSocket. To connect to Fork you use localhost:port
.
For remote applications this is a bit more complex, as you need a way to find IP-Adress and Ports for a connection. For
this reason you can use the public Fork API, where each token is registered with the according IP, API-Port and
WebSocket-Port.
π§ This service is not built yet π§