JSON responses implemented and improvements
This commit is contained in:
parent
5adbe63ede
commit
2f1385631d
31
README.md
31
README.md
@ -1,30 +1,51 @@
|
|||||||
|
|
||||||
# WebConsole
|
# WebConsole
|
||||||
|
|
||||||
WebConsole is a Spigot plugin for Minecraft 1.14 that enables you to view your server console and manage your server from anywhere. It creates a WebSocket server in the background used by the web interface to send commands, receive your console log and manage your server.
|
WebConsole is a Spigot plugin for Minecraft 1.14 that enables you to view your server console and manage your server from anywhere. It creates a WebSocket server in the background used by the web interface to send commands, receive your console log and manage your server.
|
||||||
|
|
||||||
Dont worry about privacy: all data is stored in your browser offline and your PC will connect directly to your minecraft server. No intermediary web servers, just you and your server.
|
Dont worry about privacy: all data is stored in your browser offline and your PC will connect directly to your minecraft server. No intermediary web servers, just you and your server.
|
||||||
|
|
||||||
|
|
||||||
## Plugin installation
|
## Plugin installation
|
||||||
|
|
||||||
1. Plugin download
|
1. Plugin download
|
||||||
2. Filling config.yml. Port and password configuration
|
2. Filling config.yml. Port and password configuration
|
||||||
|
|
||||||
|
|
||||||
## How it works
|
## How it works
|
||||||
|
|
||||||
1. How to install web interface / connect to github pages
|
1. How to install web interface / connect to github pages
|
||||||
2. How to add servers
|
2. How to add servers
|
||||||
|
|
||||||
|
|
||||||
## Technical information
|
## Technical information
|
||||||
|
|
||||||
### WebSocket commands
|
### WebSocket commands
|
||||||
|
|
||||||
The following tables represent how server communicates with the client(s), something like a language between them.
|
The following tables represent how server communicates with the client(s), something like a language between them.
|
||||||
|
|
||||||
|
|
||||||
#### Websocket Server -> Client
|
#### Websocket Server -> Client
|
||||||
| Code |Meaning |
|
|
||||||
|---------------------|--------------------------------------|
|
Server communicate with all connected clients using JSON. The following table shows all possible JSON variables.
|
||||||
|200 *(message)* |Query was processed with no errors |
|
| Variable |Meaning |
|
||||||
|403 *(message)* |You are not allowed to do that action |
|
|---------------------|-----------------------------------------------------------------------------|
|
||||||
|LOG *(message)* |Message is a console output |
|
| status |Status code (as integer), representing response type. See table below |
|
||||||
|
| statusDescription |Status description (as String) describing status code |
|
||||||
|
| respondsTo |`(Optional)` Original command sent by client which triggered this response|
|
||||||
|
| message |Response content |
|
||||||
|
|
||||||
|
*Status codes are listed below:
|
||||||
|
- **010**: Console output.
|
||||||
|
- **200**: Ok/Processed.
|
||||||
|
- **400**: Unknown command.
|
||||||
|
- **401**: Login required/Not logged in.
|
||||||
|
- **403**: Forbidden/Unauthorised (Probably not logged in).
|
||||||
|
|
||||||
|
|
||||||
#### Client -> Websocket Server
|
#### Client -> Websocket Server
|
||||||
|
|
||||||
|
Clients can communicate with server using commands. The following table shows existing commands.
|
||||||
| Code |Meaning |Extra info |
|
| Code |Meaning |Extra info |
|
||||||
|---------------------|-----------------------------------------|--------------|
|
|---------------------|-----------------------------------------|--------------|
|
||||||
|LOGIN *(password)* |Login to start communication with server | |
|
|LOGIN *(password)* |Login to start communication with server | |
|
||||||
|
@ -8,20 +8,22 @@ import org.java_websocket.WebSocket;
|
|||||||
|
|
||||||
import com.mesacarlos.webconsole.websockets.WSServer;
|
import com.mesacarlos.webconsole.websockets.WSServer;
|
||||||
|
|
||||||
public class ExecuteCmdCommand implements WSCommand{
|
public class ExecuteCmdCommand implements WSCommand {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(WSServer wsServer, WebSocket conn, String command) {
|
public void execute(WSServer wsServer, WebSocket conn, String command) {
|
||||||
|
|
||||||
|
Bukkit.getLogger().info("[WebConsole] " + conn.getRemoteSocketAddress() + " executed '" + command + "'");
|
||||||
ConsoleCommandSender sender = Bukkit.getServer().getConsoleSender();
|
ConsoleCommandSender sender = Bukkit.getServer().getConsoleSender();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
boolean success = Bukkit.getScheduler().callSyncMethod( wsServer.getMainClass(), () -> Bukkit.dispatchCommand( sender, command ) ).get();
|
boolean success = Bukkit.getScheduler()
|
||||||
|
.callSyncMethod(wsServer.getMainClass(), () -> Bukkit.dispatchCommand(sender, command)).get();
|
||||||
} catch (InterruptedException | ExecutionException e) {
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -3,28 +3,31 @@ package com.mesacarlos.webconsole.command;
|
|||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.java_websocket.WebSocket;
|
import org.java_websocket.WebSocket;
|
||||||
|
|
||||||
|
import com.mesacarlos.webconsole.json.Forbidden;
|
||||||
|
import com.mesacarlos.webconsole.json.Processed;
|
||||||
import com.mesacarlos.webconsole.util.LoginManager;
|
import com.mesacarlos.webconsole.util.LoginManager;
|
||||||
import com.mesacarlos.webconsole.websockets.WSServer;
|
import com.mesacarlos.webconsole.websockets.WSServer;
|
||||||
|
|
||||||
public class LogInCommand implements WSCommand{
|
public class LogInCommand implements WSCommand {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(WSServer wsServer, WebSocket conn, String password) {
|
public void execute(WSServer wsServer, WebSocket conn, String password) {
|
||||||
//If user is logged in, then return.
|
// If user is logged in, then return.
|
||||||
if(LoginManager.getInstance().isLoggedIn(conn.getRemoteSocketAddress().getAddress().toString()))
|
if (LoginManager.getInstance().isLoggedIn(conn.getRemoteSocketAddress().getAddress().toString()))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//Get password from config files
|
// Get password from config files
|
||||||
String receivedPassword = wsServer.getMainClass().getConfig().getString("password");
|
String receivedPassword = wsServer.getMainClass().getConfig().getString("password");
|
||||||
|
|
||||||
if(receivedPassword.equals(password)) {
|
if (receivedPassword.equals(password)) {
|
||||||
//Password is correct, logging in
|
// Password is correct, logging in
|
||||||
LoginManager.getInstance().logIn(conn.getRemoteSocketAddress().getAddress().toString());
|
LoginManager.getInstance().logIn(conn.getRemoteSocketAddress().getAddress().toString());
|
||||||
conn.send("200 Logged In");
|
wsServer.sendToClient(conn, new Processed("Logged In", "LOGIN ********"));
|
||||||
Bukkit.getLogger().info("[WebConsole] Successfully logged in from " + conn.getRemoteSocketAddress());
|
Bukkit.getLogger().info("[WebConsole] Successfully logged in from " + conn.getRemoteSocketAddress());
|
||||||
}else {
|
} else {
|
||||||
conn.send("403 Forbidden");
|
wsServer.sendToClient(conn, new Forbidden("Forbidden","LOGIN ********"));
|
||||||
Bukkit.getLogger().info("[WebConsole] Password incorrect while login from " + conn.getRemoteSocketAddress());
|
Bukkit.getLogger()
|
||||||
|
.info("[WebConsole] Password incorrect while login from " + conn.getRemoteSocketAddress());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
36
src/com/mesacarlos/webconsole/json/ConsoleOutput.java
Normal file
36
src/com/mesacarlos/webconsole/json/ConsoleOutput.java
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package com.mesacarlos.webconsole.json;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
public class ConsoleOutput implements JSONOutput{
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
public ConsoleOutput(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getStatusCode() {
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRespondsTo() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toJSON() {
|
||||||
|
JsonObject object = new JsonObject();
|
||||||
|
object.addProperty("status", getStatusCode());
|
||||||
|
object.addProperty("statusDescription", "Console Output");
|
||||||
|
object.addProperty("message", getMessage());
|
||||||
|
return object.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
39
src/com/mesacarlos/webconsole/json/Forbidden.java
Normal file
39
src/com/mesacarlos/webconsole/json/Forbidden.java
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package com.mesacarlos.webconsole.json;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
public class Forbidden implements JSONOutput{
|
||||||
|
private String message;
|
||||||
|
private String respondsTo;
|
||||||
|
|
||||||
|
public Forbidden(String message, String respondsTo) {
|
||||||
|
this.message = message;
|
||||||
|
this.respondsTo = respondsTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getStatusCode() {
|
||||||
|
return 403;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRespondsTo() {
|
||||||
|
return respondsTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toJSON() {
|
||||||
|
JsonObject object = new JsonObject();
|
||||||
|
object.addProperty("status", getStatusCode());
|
||||||
|
object.addProperty("statusDescription", "Forbidden");
|
||||||
|
object.addProperty("respondsTo", getRespondsTo());
|
||||||
|
object.addProperty("message", getMessage());
|
||||||
|
return object.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
28
src/com/mesacarlos/webconsole/json/JSONOutput.java
Normal file
28
src/com/mesacarlos/webconsole/json/JSONOutput.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package com.mesacarlos.webconsole.json;
|
||||||
|
|
||||||
|
public interface JSONOutput {
|
||||||
|
/**
|
||||||
|
* Gets status code representing this message. See docs for code meanings.
|
||||||
|
* @return Status code representing this message
|
||||||
|
*/
|
||||||
|
int getStatusCode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the command sended by client who created this response.
|
||||||
|
* In case of a server-generated response (like ConsoleOutput), this will be null
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String getRespondsTo();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Explanatory message of this response
|
||||||
|
* @return Explanatory message of this response
|
||||||
|
*/
|
||||||
|
String getMessage();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coverts this object into JSON, ready to send it over WS
|
||||||
|
* @return JSON Object Stringified
|
||||||
|
*/
|
||||||
|
String toJSON();
|
||||||
|
}
|
36
src/com/mesacarlos/webconsole/json/LoginRequired.java
Normal file
36
src/com/mesacarlos/webconsole/json/LoginRequired.java
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package com.mesacarlos.webconsole.json;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
public class LoginRequired implements JSONOutput{
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
public LoginRequired(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getStatusCode() {
|
||||||
|
return 401;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRespondsTo() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toJSON() {
|
||||||
|
JsonObject object = new JsonObject();
|
||||||
|
object.addProperty("status", getStatusCode());
|
||||||
|
object.addProperty("statusDescription", "Login Required");
|
||||||
|
object.addProperty("message", getMessage());
|
||||||
|
return object.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
39
src/com/mesacarlos/webconsole/json/Processed.java
Normal file
39
src/com/mesacarlos/webconsole/json/Processed.java
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package com.mesacarlos.webconsole.json;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
public class Processed implements JSONOutput{
|
||||||
|
private String message;
|
||||||
|
private String respondsTo;
|
||||||
|
|
||||||
|
public Processed(String message, String respondsTo) {
|
||||||
|
this.message = message;
|
||||||
|
this.respondsTo = respondsTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getStatusCode() {
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRespondsTo() {
|
||||||
|
return respondsTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toJSON() {
|
||||||
|
JsonObject object = new JsonObject();
|
||||||
|
object.addProperty("status", getStatusCode());
|
||||||
|
object.addProperty("statusDescription", "Processed");
|
||||||
|
object.addProperty("respondsTo", getRespondsTo());
|
||||||
|
object.addProperty("message", getMessage());
|
||||||
|
return object.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
38
src/com/mesacarlos/webconsole/json/UnknownWSCmd.java
Normal file
38
src/com/mesacarlos/webconsole/json/UnknownWSCmd.java
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package com.mesacarlos.webconsole.json;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
public class UnknownWSCmd implements JSONOutput{
|
||||||
|
private String message;
|
||||||
|
private String respondsTo;
|
||||||
|
|
||||||
|
public UnknownWSCmd(String message, String respondsTo) {
|
||||||
|
this.message = message;
|
||||||
|
this.respondsTo = respondsTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getStatusCode() {
|
||||||
|
return 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRespondsTo() {
|
||||||
|
return respondsTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toJSON() {
|
||||||
|
JsonObject object = new JsonObject();
|
||||||
|
object.addProperty("status", getStatusCode());
|
||||||
|
object.addProperty("statusDescription", "Unknown Command");
|
||||||
|
object.addProperty("respondsTo", getRespondsTo());
|
||||||
|
object.addProperty("message", getMessage());
|
||||||
|
return object.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -12,11 +12,16 @@ import org.java_websocket.server.WebSocketServer;
|
|||||||
import com.mesacarlos.webconsole.WebConsole;
|
import com.mesacarlos.webconsole.WebConsole;
|
||||||
import com.mesacarlos.webconsole.command.CommandFactory;
|
import com.mesacarlos.webconsole.command.CommandFactory;
|
||||||
import com.mesacarlos.webconsole.command.WSCommand;
|
import com.mesacarlos.webconsole.command.WSCommand;
|
||||||
|
import com.mesacarlos.webconsole.json.ConsoleOutput;
|
||||||
|
import com.mesacarlos.webconsole.json.Forbidden;
|
||||||
|
import com.mesacarlos.webconsole.json.JSONOutput;
|
||||||
|
import com.mesacarlos.webconsole.json.LoginRequired;
|
||||||
|
import com.mesacarlos.webconsole.json.UnknownWSCmd;
|
||||||
import com.mesacarlos.webconsole.util.LoginManager;
|
import com.mesacarlos.webconsole.util.LoginManager;
|
||||||
|
|
||||||
public class WSServer extends WebSocketServer {
|
public class WSServer extends WebSocketServer {
|
||||||
private WebConsole plugin;
|
|
||||||
private HashMap<String, WSCommand> commands = CommandFactory.getCommandsHashMap();
|
private HashMap<String, WSCommand> commands = CommandFactory.getCommandsHashMap();
|
||||||
|
private WebConsole plugin;
|
||||||
|
|
||||||
public WSServer(WebConsole plugin, InetSocketAddress address) {
|
public WSServer(WebConsole plugin, InetSocketAddress address) {
|
||||||
super(address);
|
super(address);
|
||||||
@ -25,15 +30,12 @@ public class WSServer extends WebSocketServer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onOpen(WebSocket conn, ClientHandshake handshake) {
|
public void onOpen(WebSocket conn, ClientHandshake handshake) {
|
||||||
conn.send("Connection started, waiting login");
|
sendToClient(conn, new LoginRequired("Connection started, waiting login"));
|
||||||
Bukkit.getLogger().info("[WebConsole] Connected and waiting login from " + conn.getRemoteSocketAddress());
|
Bukkit.getLogger().info("[WebConsole] Connected and waiting login from " + conn.getRemoteSocketAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(WebSocket conn, String message) {
|
public void onMessage(WebSocket conn, String message) {
|
||||||
// Log this action to console
|
|
||||||
Bukkit.getLogger().info("[WebConsole] Received signal from " + conn.getRemoteSocketAddress() + ": " + message);
|
|
||||||
|
|
||||||
// Get command and params
|
// Get command and params
|
||||||
String wsCommand = message.split(" ")[0];
|
String wsCommand = message.split(" ")[0];
|
||||||
String wsCommandParams = "";
|
String wsCommandParams = "";
|
||||||
@ -44,14 +46,16 @@ public class WSServer extends WebSocketServer {
|
|||||||
WSCommand cmd = commands.get(wsCommand);
|
WSCommand cmd = commands.get(wsCommand);
|
||||||
|
|
||||||
if (cmd == null) {
|
if (cmd == null) {
|
||||||
|
//Command does not exist
|
||||||
|
sendToClient(conn, new UnknownWSCmd("Unknown command", message));
|
||||||
Bukkit.getLogger().info(
|
Bukkit.getLogger().info(
|
||||||
"[WebConsole] Signal was not processed since is not valid. Is your plugin/web interface up to date?");
|
"[WebConsole] Signal '" + message + "' was not processed since is not valid. Is your plugin/web interface up to date?");
|
||||||
} else if (!LoginManager.getInstance().isLoggedIn(conn.getRemoteSocketAddress().getAddress().toString())
|
} else if (!LoginManager.getInstance().isLoggedIn(conn.getRemoteSocketAddress().getAddress().toString())
|
||||||
&& !wsCommand.equals("LOGIN")) {
|
&& !wsCommand.equals("LOGIN")) {
|
||||||
// DO NOTHING. User is not authorised
|
//User is not authorised. DO NOTHING, IMPORTANT!
|
||||||
conn.send("403 Forbidden");
|
sendToClient(conn, new Forbidden("Forbidden", message));
|
||||||
Bukkit.getLogger().warning("[WebConsole] " + conn.getRemoteSocketAddress()
|
Bukkit.getLogger().warning("[WebConsole] " + conn.getRemoteSocketAddress()
|
||||||
+ " tried to run a command while not authenticated!");
|
+ " tried to run '" + message + "' while not logged in!");
|
||||||
} else {
|
} else {
|
||||||
cmd.execute(this, conn, wsCommandParams);
|
cmd.execute(this, conn, wsCommandParams);
|
||||||
}
|
}
|
||||||
@ -72,7 +76,15 @@ public class WSServer extends WebSocketServer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
Bukkit.getLogger().info("[WebConsole] WebSockets Server started successfully");
|
Bukkit.getLogger().info("[WebConsole] WebSocket Server started successfully");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns main class
|
||||||
|
* @return Main plugin class
|
||||||
|
*/
|
||||||
|
public WebConsole getMainClass() {
|
||||||
|
return plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -82,17 +94,17 @@ public class WSServer extends WebSocketServer {
|
|||||||
Collection<WebSocket> connections = getConnections();
|
Collection<WebSocket> connections = getConnections();
|
||||||
for (WebSocket connection : connections) {
|
for (WebSocket connection : connections) {
|
||||||
if (LoginManager.getInstance().isLoggedIn(connection.getRemoteSocketAddress().getAddress().toString()))
|
if (LoginManager.getInstance().isLoggedIn(connection.getRemoteSocketAddress().getAddress().toString()))
|
||||||
connection.send("LOG " + line);
|
sendToClient(connection, new ConsoleOutput(line));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns main class
|
* Sends this JSONOutput to client
|
||||||
*
|
* @param conn Connection to client
|
||||||
* @return
|
* @param content JSONOutput object
|
||||||
*/
|
*/
|
||||||
public WebConsole getMainClass() {
|
public void sendToClient(WebSocket conn, JSONOutput content) {
|
||||||
return plugin;
|
conn.send(content.toJSON());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user