diff --git a/client/index.html b/client/index.html index d84c5e0..f9c1b95 100644 --- a/client/index.html +++ b/client/index.html @@ -264,7 +264,7 @@ @@ -274,15 +274,15 @@ - - + + - - - - - - + + + + + + diff --git a/phrases.properties b/phrases.properties index ad13cfe..d74b9e6 100644 --- a/phrases.properties +++ b/phrases.properties @@ -5,7 +5,7 @@ boot-error = Error occured while starting WebSocket Server. connection-resumed-message = Connected. Already logged in, welcome back! connection-resumed-console = [WebConsole] Connected and resumed session from {0} connection-login-message = Connection started, waiting login -connection-login-console = [WebConsole] Connected and waiting login from {0} +connection-login-console = [WebConsole] Connected and waiting login from {0} unknown-command-message = Unknown command unknown-command-console = [WebConsole] Signal "{0}" was not processed since is not valid. Is your plugin/web interface up to date? forbidden-message = Forbidden @@ -19,7 +19,7 @@ error-disconnected-client = [WebConsole] Attempted to send a message to a discon cpu-usage-message = Usage is {0}% # ExecCommand.java -viewer-error-console = [WebConsole] {0} tried to run {1} without permission. +no-send-permission-console = [WebConsole] {0} tried to run {1} without permission. cmd-executed-console = [WebConsole] {0} executed "{1}". # LogInCommand.java diff --git a/phrases_cs.properties b/phrases_cs.properties index 004d38a..8cc1368 100644 --- a/phrases_cs.properties +++ b/phrases_cs.properties @@ -19,7 +19,7 @@ error-disconnected-client = [WebConsole] Pokus o odeslání zprávy odpojenému cpu-usage-message = Využití je {0}% # ExecCommand.java -viewer-error-console = [WebConsole] {0} se pokusil spustit {1} bez povolení. +no-send-permission-console = [WebConsole] {0} se pokusil spustit {1} bez povolení. cmd-executed-console = [WebConsole] {0} spustil "{1}". # LogInCommand.java diff --git a/phrases_de.properties b/phrases_de.properties index 3b94ebd..6bce551 100644 --- a/phrases_de.properties +++ b/phrases_de.properties @@ -19,7 +19,7 @@ error-disconnected-client = [WebConsole] Es wurde versucht, eine Nachricht an ei cpu-usage-message = Die CPU Auslastung liegt bei {0}%. # ExecCommand.java -viewer-error-console = [WebConsole] {0} hat versucht, {1} ohne Erlaubnis auszuführen. +no-send-permission-console = [WebConsole] {0} hat versucht, {1} ohne Erlaubnis auszuführen. cmd-executed-console = [WebConsole] {0} hat "{1}" ausgeführt. # LogInCommand.java @@ -37,7 +37,7 @@ ram-usage-message = {0} frei, {1} benutzt, {2} maximal # WebConsoleCommand.java webconsole-version = Die WebConsole Version ist {0}. webconsole-no-connections = Aktuell ist niemand mit der WebConsole verbunden -webconsole-active-connections = Aktive Verbindugen von: +webconsole-active-connections = Aktive Verbindugen von: # ReadLogFileCommand.java log-read-error = Fehler beim lesen der 'latest.log'-Logdatei diff --git a/phrases_en.properties b/phrases_en.properties index ad13cfe..d74b9e6 100644 --- a/phrases_en.properties +++ b/phrases_en.properties @@ -5,7 +5,7 @@ boot-error = Error occured while starting WebSocket Server. connection-resumed-message = Connected. Already logged in, welcome back! connection-resumed-console = [WebConsole] Connected and resumed session from {0} connection-login-message = Connection started, waiting login -connection-login-console = [WebConsole] Connected and waiting login from {0} +connection-login-console = [WebConsole] Connected and waiting login from {0} unknown-command-message = Unknown command unknown-command-console = [WebConsole] Signal "{0}" was not processed since is not valid. Is your plugin/web interface up to date? forbidden-message = Forbidden @@ -19,7 +19,7 @@ error-disconnected-client = [WebConsole] Attempted to send a message to a discon cpu-usage-message = Usage is {0}% # ExecCommand.java -viewer-error-console = [WebConsole] {0} tried to run {1} without permission. +no-send-permission-console = [WebConsole] {0} tried to run {1} without permission. cmd-executed-console = [WebConsole] {0} executed "{1}". # LogInCommand.java diff --git a/phrases_es.properties b/phrases_es.properties index d8b3eeb..0d71ee6 100644 --- a/phrases_es.properties +++ b/phrases_es.properties @@ -19,7 +19,7 @@ error-disconnected-client = [WebConsole] Se intentó enviar un mensaje a un clie cpu-usage-message = En uso {0}% # ExecCommand.java -viewer-error-console = [WebConsole] {0} intentó ejecutar {1} sin permiso. +no-send-permission-console = [WebConsole] {0} intentó ejecutar {1} sin permiso. cmd-executed-console = [WebConsole] {0} ejecutó "{1}". # LogInCommand.java diff --git a/phrases_fr.properties b/phrases_fr.properties index 4ad4b61..1556fb4 100644 --- a/phrases_fr.properties +++ b/phrases_fr.properties @@ -19,7 +19,7 @@ error-disconnected-client = [WebConsole] Vous avez tenté d'envoyer un message cpu-usage-message = L'utilisation est {0}% # ExecCommand.java -viewer-error-console = [WebConsole] {0} a tenté d'exécuter {1} sans autorisation. +no-send-permission-console = [WebConsole] {0} a tenté d'exécuter {1} sans autorisation. cmd-executed-console = [WebConsole] {0} a exécuté "{1}". # LogInCommand.java diff --git a/phrases_it.properties b/phrases_it.properties index e5bd04b..6a90a9f 100644 --- a/phrases_it.properties +++ b/phrases_it.properties @@ -5,7 +5,7 @@ boot-error = C''è stato un errore mentre avviavo WebConsole server. connection-resumed-message = Connesso. Login già fatto, Bentornato! connection-resumed-console = [WebConsole] Connesso e sessione ripresa da {0} connection-login-message = Connessione stabilita, attendo il login -connection-login-console = [WebConsole] Connesso e attendo login da {0} +connection-login-console = [WebConsole] Connesso e attendo login da {0} unknown-command-message = Comando sconosciuto unknown-command-console = [WebConsole] Il segnale "{0}" non è stato processato siccome non è valido. Il tuo plugin/web interface è aggiornato? forbidden-message = Proibito @@ -19,7 +19,7 @@ error-disconnected-client = [WebConsole] Tentativo di inviare un messaggio a un cpu-usage-message = L''uso è {0}% # ExecCommand.java -viewer-error-console = [WebConsole] {0} ha provato a eseguire {1} senza autorizzazione. +no-send-permission-console = [WebConsole] {0} ha provato a eseguire {1} senza autorizzazione. cmd-executed-console = [WebConsole] {0} eseguito "{1}". # LogInCommand.java diff --git a/phrases_ko.properties b/phrases_ko.properties index 1c2cbfb..e84062d 100644 --- a/phrases_ko.properties +++ b/phrases_ko.properties @@ -5,7 +5,7 @@ boot-error = WebSocket 서버를 시작하는 도중 오류가 발생하였습 connection-resumed-message = 연결되었습니다. 이미 로그인되어 있습니다. 안녕하세요! connection-resumed-console = [WebConsole] 연결되었으며 {0}로부터 온 세션을 이어서 시작하였습니다. connection-login-message = 연결이 시작되었고, 로그인을 기다리는 중입니다 -connection-login-console = [WebConsole] 연결되었으며 {0}로부터 로그인을 기다리는 중입니다 +connection-login-console = [WebConsole] 연결되었으며 {0}로부터 로그인을 기다리는 중입니다 unknown-command-message = 알 수 없는 명령어입니다 unknown-command-console = [WebConsole] "{0}" 신호는 알맞지 않기 때문에 처리되지 않았습니다. 플러그인 또는 웹 UI가 최신입니까? forbidden-message = 제한되었습니다 @@ -19,7 +19,7 @@ error-disconnected-client = [WebConsole] 연결이 끊긴 WebSocket 클라이언 cpu-usage-message = 사용량은 {0}%입니다 # ExecCommand.java -viewer-error-console = [WebConsole] {0}이(가) {1}을(를) 권한 없이 실행하려고 했습니다. +no-send-permission-console = [WebConsole] {0}이(가) {1}을(를) 권한 없이 실행하려고 했습니다. cmd-executed-console = [WebConsole] {0}이(가) "{1}"을(를) 실행하였습니다. # LogInCommand.java diff --git a/phrases_nl.properties b/phrases_nl.properties index af769f4..c664614 100644 --- a/phrases_nl.properties +++ b/phrases_nl.properties @@ -19,7 +19,7 @@ error-disconnected-client = [WebConsole] Poging om een bericht te sturen naar ee cpu-usage-message = Verbruik is {0}% # ExecCommand.java -viewer-error-console = [WebConsole] {0} heeft geprobeerd {1} uit te voeren zonder toestemming. +no-send-permission-console = [WebConsole] {0} heeft geprobeerd {1} uit te voeren zonder toestemming. cmd-executed-console = [WebConsole] {0} voerde "{1}" uit. # LogInCommand.java diff --git a/phrases_pt.properties b/phrases_pt.properties index 4d66632..3e42347 100644 --- a/phrases_pt.properties +++ b/phrases_pt.properties @@ -19,7 +19,7 @@ error-disconnected-client = [WebConsole] Tentativa de enviar uma mensagem para u cpu-usage-message = Consumindo {0}% # ExecCommand.java -viewer-error-console = [WebConsole] {0} tentou executar o {1} sem permissão. +no-send-permission-console = [WebConsole] {0} tentou executar o {1} sem permissão. cmd-executed-console = [WebConsole] {0} executou "{1}". # LogInCommand.java diff --git a/phrases_ru.properties b/phrases_ru.properties index 9313abb..82b649c 100644 --- a/phrases_ru.properties +++ b/phrases_ru.properties @@ -19,7 +19,7 @@ error-disconnected-client = [WebConsole] Попытка отправить со cpu-usage-message = Использование {0}% # ExecCommand.java -viewer-error-console = [WebConsole] {0} попытался запустить {1} без разрешения. +no-send-permission-console = [WebConsole] {0} попытался запустить {1} без разрешения. cmd-executed-console = [WebConsole] {0} выполнил "{1}". # LogInCommand.java diff --git a/phrases_tr.properties b/phrases_tr.properties index f8dd1d8..2d9cf69 100644 --- a/phrases_tr.properties +++ b/phrases_tr.properties @@ -5,7 +5,7 @@ boot-error = WebSocket sunucusunu başlatırken hata oluştu. connection-resumed-message = Bağlandı. Zaten giriş yaptın, tekrar hoş geldin! connection-resumed-console = [WebConsole] Bağlandı ve {0} konumundan gelen oturum devam ettirildi connection-login-message = Bağlantı başladı, giriş bekleniyor -connection-login-console = [WebConsole] Bağlandı ve {0} konumundan giriş bekleniyor +connection-login-console = [WebConsole] Bağlandı ve {0} konumundan giriş bekleniyor unknown-command-message = Bilinmeyen komut unknown-command-console = [WebConsole] "{0}" sinyali geçerli olmadığından işlenilemedi. Eklentin/web arayüzün güncellenmiş mi? forbidden-message = Forbidden @@ -19,7 +19,7 @@ error-disconnected-client = [WebConsole] Bağlantısı kesilmiş bir WebSocket'a cpu-usage-message = Şuanki kullanım %{0} # ExecCommand.java -viewer-error-console = [WebConsole] {0}, {1}'ı yetkisiz olarak çalıştırmayı denedi. +no-send-permission-console = [WebConsole] {0}, {1}'ı yetkisiz olarak çalıştırmayı denedi. cmd-executed-console = [WebConsole] {0}, "{1}" çalıştırdı. # LogInCommand.java diff --git a/phrases_zh.properties b/phrases_zh.properties index 2a11d1a..ab644db 100644 --- a/phrases_zh.properties +++ b/phrases_zh.properties @@ -19,7 +19,7 @@ error-disconnected-client = [WebConsole] 尝试向断开连接的WebSocket客户 cpu-usage-message = 已使用 {0}% # ExecCommand.java -viewer-error-console = [WebConsole] {0}试图未经许可而运行{1}。 +no-send-permission-console = [WebConsole] {0}试图未经许可而运行{1}。 cmd-executed-console = [網站控制台] {0} 執行 '{1}'. # LogInCommand.java @@ -32,7 +32,7 @@ login-failed-console = [網站控制台] 登錄時密碼不正確 {0} players-message = {0}玩家連接,最多{1} # RamUsageCommand.java -ram-usage-message = 空閒{0} , 已使用{1} , 最大內存{2} +ram-usage-message = 空閒{0} , 已使用{1} , 最大內存{2} # WebConsoleCommand.java webconsole-version = 網站控制台版本 {0}. diff --git a/plugin.yml b/plugin.yml index 342b386..bd15841 100644 --- a/plugin.yml +++ b/plugin.yml @@ -1,7 +1,7 @@ name: WebConsole main: es.mesacarlos.webconsole.WebConsole api-version: 1.13 -version: 2.1 +version: 2.2 description: WebSocket-based web console author: Carlos Mesa commands: diff --git a/pom.xml b/pom.xml index 5edc9ca..4642cc0 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 WebConsole WebConsole - 2.1 + 2.2 src diff --git a/src/es/mesacarlos/webconsole/config/ConfigManager.java b/src/es/mesacarlos/webconsole/config/ConfigManager.java index 564b610..6b95e72 100644 --- a/src/es/mesacarlos/webconsole/config/ConfigManager.java +++ b/src/es/mesacarlos/webconsole/config/ConfigManager.java @@ -1,9 +1,7 @@ package es.mesacarlos.webconsole.config; import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; +import java.util.*; import org.bukkit.Bukkit; import org.bukkit.configuration.ConfigurationSection; @@ -44,11 +42,44 @@ public class ConfigManager { // Language config config.addDefault("language", "en"); - if(config.getConfigurationSection("passwords") == null) { - ConfigurationSection passwordsSection = config.createSection("passwords"); - ConfigurationSection adminPasswordSection = passwordsSection.createSection("admin"); - adminPasswordSection.addDefault("user1", "mySecurePassword"); - passwordsSection.createSection("viewer"); + //Create passwords section if it does not exist + ConfigurationSection passwordsSection = config.getConfigurationSection("passwords"); + if(passwordsSection == null) { + passwordsSection = config.createSection("passwords"); + } + + //Create passwords.admin section if it does not exist + ConfigurationSection adminPasswordSection = passwordsSection.getConfigurationSection("admin"); + if(adminPasswordSection == null) { + adminPasswordSection = passwordsSection.createSection("admin"); + adminPasswordSection.createSection("user1"); + } + + //For each admin user, create the password value and the commandWhitelist section if it does not exist + Set adminUsersSections = adminPasswordSection.getKeys(false); + for (String adminUserSectionName : adminUsersSections) { + ConfigurationSection userSection = adminPasswordSection.getConfigurationSection(adminUserSectionName); + if(userSection == null) { + //If userSection is null, that means that the config file is prior to v2.2. We need to update the file to v2.2 by replacing the "user:password" value to a new section for each user. + String userPasswordFromOldConfig = adminPasswordSection.getString(adminUserSectionName); + userSection = adminPasswordSection.createSection(adminUserSectionName); + userSection.set("password", userPasswordFromOldConfig); + } + userSection.addDefault("password", "mySecurePassword"); + + ConfigurationSection commandWhitelist = userSection.getConfigurationSection("commandWhitelist"); + if(commandWhitelist == null) { + commandWhitelist = userSection.createSection("commandWhitelist"); + commandWhitelist.addDefault("enabled", false); + commandWhitelist.addDefault("commandWhitelistActsAsBlacklist", false); + commandWhitelist.addDefault("whitelist", Arrays.asList("whisper", "gamemode survival")); + } + } + + //Create passwords.viewer section if it does not exist + ConfigurationSection viewerPasswordSection = passwordsSection.getConfigurationSection("viewer"); + if(viewerPasswordSection == null) { + viewerPasswordSection = passwordsSection.createSection("viewer"); } config.options().copyDefaults(true); @@ -96,11 +127,19 @@ public class ConfigManager { * @return list of admin users */ private List getAdmins() { - Map passwords = plugin.getConfig().getConfigurationSection("passwords").getConfigurationSection("admin").getValues(false); - List adminUsers = new ArrayList(); + Set adminConfig = plugin.getConfig().getConfigurationSection("passwords").getConfigurationSection("admin").getKeys(false); + + List adminUsers = new ArrayList<>(); - for(Map.Entry entry : passwords.entrySet()) - adminUsers.add(new UserData(entry.getKey(), entry.getValue().toString(), UserType.ADMIN)); + for(String username : adminConfig) { + adminUsers.add(new UserData( + username, + plugin.getConfig().getString("passwords.admin." + username + ".password"), + UserType.ADMIN, + plugin.getConfig().getBoolean("passwords.admin." + username + ".commandWhitelist.enabled"), + plugin.getConfig().getBoolean("passwords.admin." + username + ".commandWhitelist.commandWhitelistActsAsBlacklist"), + plugin.getConfig().getStringList("passwords.admin." + username + ".commandWhitelist.whitelist"))); + } return adminUsers; } @@ -111,10 +150,10 @@ public class ConfigManager { */ private List getViewers() { Map passwords = plugin.getConfig().getConfigurationSection("passwords").getConfigurationSection("viewer").getValues(false); - List viewerUsers = new ArrayList(); + List viewerUsers = new ArrayList<>(); for(Map.Entry entry : passwords.entrySet()) - viewerUsers.add(new UserData(entry.getKey(), entry.getValue().toString(), UserType.VIEWER)); + viewerUsers.add(new UserData(entry.getKey(), entry.getValue().toString(), UserType.VIEWER, false, false, new ArrayList<>())); return viewerUsers; } diff --git a/src/es/mesacarlos/webconsole/config/UserData.java b/src/es/mesacarlos/webconsole/config/UserData.java index dfd8590..1f8428d 100644 --- a/src/es/mesacarlos/webconsole/config/UserData.java +++ b/src/es/mesacarlos/webconsole/config/UserData.java @@ -1,16 +1,25 @@ package es.mesacarlos.webconsole.config; +import java.util.List; + public class UserData { private String username; private String password; private UserType userType; + private boolean isWhitelistEnabled; + private boolean isWhitelistActsAsBlacklist; + private List whitelistedCommands; - public UserData(String username, String password, UserType userType) { + public UserData(String username, String password, UserType userType, + boolean isWhitelistEnabled, boolean isWhitelistActsAsBlacklist, List whitelistedCommands) { this.username = username; this.password = password; this.userType = userType; + this.isWhitelistEnabled = isWhitelistEnabled; + this.isWhitelistActsAsBlacklist = isWhitelistActsAsBlacklist; + this.whitelistedCommands = whitelistedCommands; } - + public String getUsername() { return username; } @@ -22,4 +31,16 @@ public class UserData { public UserType getUserType() { return userType; } + + public boolean isWhitelistEnabled() { + return isWhitelistEnabled; + } + + public boolean isWhitelistActsAsBlacklist() { + return isWhitelistActsAsBlacklist; + } + + public List getWhitelistedCommands() { + return whitelistedCommands; + } } \ No newline at end of file diff --git a/src/es/mesacarlos/webconsole/websocket/command/ExecCommand.java b/src/es/mesacarlos/webconsole/websocket/command/ExecCommand.java index e7ced5a..f14fef0 100644 --- a/src/es/mesacarlos/webconsole/websocket/command/ExecCommand.java +++ b/src/es/mesacarlos/webconsole/websocket/command/ExecCommand.java @@ -2,6 +2,8 @@ package es.mesacarlos.webconsole.websocket.command; import java.util.concurrent.ExecutionException; +import es.mesacarlos.webconsole.config.ConfigManager; +import es.mesacarlos.webconsole.config.UserData; import org.bukkit.Bukkit; import org.bukkit.command.ConsoleCommandSender; import org.java_websocket.WebSocket; @@ -14,13 +16,20 @@ import es.mesacarlos.webconsole.util.Internationalization; import es.mesacarlos.webconsole.websocket.WSServer; public class ExecCommand implements WSCommand { + LoginManager loginManager = LoginManager.getInstance(); @Override public void execute(WSServer wsServer, WebSocket conn, String command) { ConnectedUser u = LoginManager.getInstance().getUser(conn.getRemoteSocketAddress()); if(u == null || u.getUserType() != UserType.ADMIN) { if(u != null) - Bukkit.getLogger().warning(Internationalization.getPhrase("viewer-error-console", u, command)); + Bukkit.getLogger().warning(Internationalization.getPhrase("no-send-permission-console", u, command)); + return; + } + + boolean allowCommand = checkWhitelist(conn, command); + if (!allowCommand) { + Bukkit.getLogger().warning(Internationalization.getPhrase("no-send-permission-console", u, command)); return; } @@ -36,5 +45,51 @@ public class ExecCommand implements WSCommand { } } + + private boolean checkWhitelist(WebSocket conn, String command) { + for(UserData ud : ConfigManager.getInstance().getAllUsers()) { + if (ud.getUsername().equals(loginManager.getUser(conn.getRemoteSocketAddress()).getUsername())) { + + if (!ud.isWhitelistEnabled()) { //Skip whitelist check. + return true; + } + + String[] splitCommand = command.split(" "); + + for (String whitelistedCommand : ud.getWhitelistedCommands()) { + String[] splitWhitelistedCommand = whitelistedCommand.split(" "); + + if(equalsArray(splitCommand, splitWhitelistedCommand)) { + //Command matches the whitelist + if(ud.isWhitelistActsAsBlacklist()) + return false; //If acts as blacklist, do not allow command + else + return true; //If acts as Whitelist, allow command + } + } + + //If execution reached this point, then the command is not in the blacklist. + if(ud.isWhitelistActsAsBlacklist()) + return true; //If acts as blacklist, allow command + else + return false; //If acts as Whitelist, do not allow command + } + } + throw new RuntimeException("No user matched the whitelist check."); + } + + /** + * Check if the user command matches the whitelisted command + * + * @param splitCommand Command sent by user + * @param splitWhitelistedCommand Command in the whitelist + * @return true if the user command matches the whitelist command + */ + private boolean equalsArray(String[] splitCommand, String[] splitWhitelistedCommand) { + for (int i = 0; i < splitWhitelistedCommand.length; i++) + if (!splitCommand[i].equalsIgnoreCase(splitWhitelistedCommand[i])) + return false; //Does not match so far + return true; //Matches the command + } } \ No newline at end of file