From 18461c142caf683e8413235d2cf45b03e1afc30c Mon Sep 17 00:00:00 2001 From: Dries007 Date: Sun, 9 Nov 2014 15:16:02 +0100 Subject: [PATCH] The rebirth, Part 2. Order to (some of the) chaos --- .../backend/commands/CommandHandler.java | 3 +- .../backend/server/FileManager.java | 1 + .../doubledoordev/backend/server/Server.java | 4 +- .../backend/server/WorldManager.java | 9 +- .../backend/server/query/MCQuery.java | 5 +- .../net/doubledoordev/backend/util/Cache.java | 7 - .../doubledoordev/backend/util/Constants.java | 159 ++++++++++-------- .../doubledoordev/backend/util/Helper.java | 1 + .../doubledoordev/backend/util/PortRange.java | 9 +- .../util/exceptions/BackupException.java | 53 ++++++ .../util/exceptions/OutOfPortsException.java | 53 ++++++ .../util/exceptions/PostException.java | 74 ++++++++ .../backend/web/http/FreemarkerHandler.java | 28 +-- .../backend/web/http/PostHandler.java | 158 +++++++++++------ .../ServerControlSocketApplication.java | 7 +- .../socket/ServerListSocketApplication.java | 2 +- .../backend/webserver_old/methods/Get.java | 2 +- .../backend/webserver_old/methods/Post.java | 2 +- src/main/resources/templates/header.ftl | 16 +- src/main/resources/templates/newserver.ftl | 8 +- src/main/resources/templates/servers.ftl | 17 +- 21 files changed, 428 insertions(+), 190 deletions(-) create mode 100644 src/main/java/net/doubledoordev/backend/util/exceptions/BackupException.java create mode 100644 src/main/java/net/doubledoordev/backend/util/exceptions/OutOfPortsException.java create mode 100644 src/main/java/net/doubledoordev/backend/util/exceptions/PostException.java diff --git a/src/main/java/net/doubledoordev/backend/commands/CommandHandler.java b/src/main/java/net/doubledoordev/backend/commands/CommandHandler.java index 6b5fb21..4575413 100644 --- a/src/main/java/net/doubledoordev/backend/commands/CommandHandler.java +++ b/src/main/java/net/doubledoordev/backend/commands/CommandHandler.java @@ -56,6 +56,7 @@ import net.doubledoordev.backend.server.Server; import net.doubledoordev.backend.server.WorldManager; import net.doubledoordev.backend.util.Cache; +import net.doubledoordev.backend.util.exceptions.BackupException; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -170,7 +171,7 @@ public void cmdBackup(Server[] servers) throws CommandException server.getWorldManager().bypassLimits = true; server.getWorldManager().makeAllOfTheBackup(); } - catch (WorldManager.BackupException e) + catch (BackupException e) { CMDLOGGER.warn("Error when making a backup of " + server.getID()); CMDLOGGER.warn(e); diff --git a/src/main/java/net/doubledoordev/backend/server/FileManager.java b/src/main/java/net/doubledoordev/backend/server/FileManager.java index 7544321..13aeadd 100644 --- a/src/main/java/net/doubledoordev/backend/server/FileManager.java +++ b/src/main/java/net/doubledoordev/backend/server/FileManager.java @@ -56,6 +56,7 @@ import java.io.IOException; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.LinkedList; import static net.doubledoordev.backend.webserver_old.NanoHTTPD.MIME_PLAINTEXT; diff --git a/src/main/java/net/doubledoordev/backend/server/Server.java b/src/main/java/net/doubledoordev/backend/server/Server.java index 1f08be4..ef316ec 100644 --- a/src/main/java/net/doubledoordev/backend/server/Server.java +++ b/src/main/java/net/doubledoordev/backend/server/Server.java @@ -645,7 +645,7 @@ public void setExtraJavaParameters(List list) throws Exception { if (getOnline()) throw new ServerOnlineException(); for (String s : list) - for (Pattern pattern : Constants.ILLEGAL_OPTIONS) + for (Pattern pattern : Constants.SERVER_START_ARGS_BLACKLIST_PATTERNS) if (pattern.matcher(s).matches()) throw new Exception(s + " NOT ALLOWED."); data.extraJavaParameters = list; Settings.save(); @@ -665,7 +665,7 @@ public void setExtraMCParameters(List list) throws Exception { if (getOnline()) throw new ServerOnlineException(); for (String s : list) - for (Pattern pattern : Constants.ILLEGAL_OPTIONS) + for (Pattern pattern : Constants.SERVER_START_ARGS_BLACKLIST_PATTERNS) if (pattern.matcher(s).matches()) throw new Exception(s + " NOT ALLOWED."); data.extraMCParameters = list; Settings.save(); diff --git a/src/main/java/net/doubledoordev/backend/server/WorldManager.java b/src/main/java/net/doubledoordev/backend/server/WorldManager.java index befe6b3..a93dfad 100644 --- a/src/main/java/net/doubledoordev/backend/server/WorldManager.java +++ b/src/main/java/net/doubledoordev/backend/server/WorldManager.java @@ -40,6 +40,7 @@ package net.doubledoordev.backend.server; +import net.doubledoordev.backend.util.exceptions.BackupException; import net.lingala.zip4j.core.ZipFile; import net.lingala.zip4j.exception.ZipException; import net.lingala.zip4j.model.ZipParameters; @@ -167,12 +168,4 @@ private boolean checkSpace() if (bypassLimits) return !(bypassLimits = false); return server.getOwnerObject().getMaxDiskspace() == -1 || server.getOwnerObject().getDiskspaceLeft() <= 0; } - - public class BackupException extends Exception - { - public BackupException(String s) - { - super(s); - } - } } diff --git a/src/main/java/net/doubledoordev/backend/server/query/MCQuery.java b/src/main/java/net/doubledoordev/backend/server/query/MCQuery.java index 490e64e..435bc39 100644 --- a/src/main/java/net/doubledoordev/backend/server/query/MCQuery.java +++ b/src/main/java/net/doubledoordev/backend/server/query/MCQuery.java @@ -40,10 +40,13 @@ package net.doubledoordev.backend.server.query; +import net.doubledoordev.backend.util.Constants; import net.doubledoordev.backend.util.exceptions.ServerOfflineException; import java.net.*; +import static net.doubledoordev.backend.util.Constants.LOCALHOST; + /** * A class that handles Minecraft Query protocol requests * @@ -54,7 +57,7 @@ public class MCQuery final static byte HANDSHAKE = 9; final static byte STAT = 0; - String serverAddress = "localhost"; + String serverAddress = LOCALHOST; int queryPort = 25565; // the default minecraft query port int localPort = 25566; // the local port we're connected to the server on diff --git a/src/main/java/net/doubledoordev/backend/util/Cache.java b/src/main/java/net/doubledoordev/backend/util/Cache.java index 86b52c1..3d4bad7 100644 --- a/src/main/java/net/doubledoordev/backend/util/Cache.java +++ b/src/main/java/net/doubledoordev/backend/util/Cache.java @@ -216,13 +216,6 @@ public void run() } } }; - /** - * Time vars - */ - public static long REALLY_LONG_CACHE_TIMEOUT = 1000 * 60 * 60 * 24; // 24 hours - public static long LONG_CACHE_TIMEOUT = 1000 * 60 * 60; // 1 hour - public static long MEDIUM_CACHE_TIMEOUT = 1000 * 60; // 1 minute - public static long SHORT_CACHE_TIMEOUT = 1000 * 10; // 20 seconds /** * Forge version related things */ diff --git a/src/main/java/net/doubledoordev/backend/util/Constants.java b/src/main/java/net/doubledoordev/backend/util/Constants.java index 3ac488d..0e00f8c 100644 --- a/src/main/java/net/doubledoordev/backend/util/Constants.java +++ b/src/main/java/net/doubledoordev/backend/util/Constants.java @@ -41,13 +41,9 @@ package net.doubledoordev.backend.util; import com.google.common.base.Joiner; -import com.google.common.collect.ImmutableList; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonParser; -import freemarker.ext.beans.BeansWrapper; -import freemarker.template.TemplateModel; -import freemarker.template.TemplateModelException; import net.doubledoordev.backend.server.Server; import net.doubledoordev.backend.server.ServerData; import net.doubledoordev.backend.util.winreg.JavaFinder; @@ -68,43 +64,74 @@ */ public class Constants { - public static final String NAME = "D3 Backend"; - public static final String LOCALHOST = "localhost"; - public static final Pattern USERNAME_CHECK = Pattern.compile("^[\\w-]+$"); - public static final Gson GSON = new GsonBuilder() - .registerTypeAdapter(Server.class, new Server.Deserializer()) - .registerTypeAdapter(ServerData.class, new ServerData.Deserializer()) - .registerTypeAdapter(Server.class, new Server.Serializer()) - .setPrettyPrinting() - .create(); - public static final Random RANDOM = new Random(); + /* + * String constants + */ + public static final String NAME = "D3 Backend"; + public static final String LOCALHOST = "localhost"; + public static final String COOKIE_KEY = "user"; + public static final String WORLD = "world"; + public static final String SERVER = "server"; + public static final String FILE = "file"; + public static final String INDEX = "index"; + public static final String USER = "user"; + public static final String DIM = "DIM"; + public static final String TEMPLATE_EXTENSION = ".ftl"; + public static final String ERROR_TEMPLATE = "error.ftl"; + /* + * URL and PATH constants + */ + public static final String SLASH_STR = "/"; + public static final String STATIC_PATH = "/static/"; + public static final String TEMPLATES_PATH = "/templates/"; + public static final String P2S_PATH = "/pay2spawn/"; + public static final String SOCKET_CONTEXT = "/socket"; + public static final String LOGIN_URL = "/login"; + public static final String REGISTER_URL = "/register"; + public static final String NEWSERVER_URL = "/newserver"; + public static final String SERVER_URL = "/server?server="; + public static final String FAVOTICON = "favicon.ico"; - public static final char[] symbols = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); - public static final File ROOT = getRootFile(); - public static final File CONFIG_FILE = new File(ROOT, "config.json"); - public static final File SERVERS_FILE = new File(ROOT, "servers.json"); - public static final File USERS_FILE = new File(ROOT, "users.json"); - public static final File SERVERS = new File(ROOT, "servers"); - public static final File BACKUPS = new File(ROOT, "backups"); - public static final ImmutableList ADMINPAGES = ImmutableList.of("console", "backendConsoleText"); - public static final String STATIC_PATH = "/static/"; - public static final String TEMPLATES_PATH = "/templates/"; - public static final String P2S_PATH = "/pay2spawn/"; - public static final String SOCKET_CONTEXT = "/socket"; - public static final String FAVOTICON = "favicon.ico"; - public static final String ERROR_TEMPLATE = "error.ftl"; - public static final String COOKIE_KEY = "user"; - public static final JsonParser JSONPARSER = new JsonParser(); - public static final String MC_VERIONS_URL = "https://s3.amazonaws.com/Minecraft.Download/versions/versions.json"; - public static final String FORGE_VERIONS_URL = "http://files.minecraftforge.net/maven/net/minecraftforge/forge/json"; - public static final String MC_SERVER_JAR_URL = "https://s3.amazonaws.com/Minecraft.Download/versions/%ID%/minecraft_server.%ID%.jar"; - public static final String FORGE_INSTALLER_URL = "http://files.minecraftforge.net/maven/net/minecraftforge/forge/%ID%/forge-%ID%-installer.jar"; - public static final Pattern ILLEGAL_OPTIONS[] = {Pattern.compile("^-Xms.*$"), Pattern.compile("^-Xmx.*$"), Pattern.compile("^-XX:MaxPermSize=.*$")}; - public static final SimpleDateFormat BACKUP_SDF = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss"); - public static final String WORLD = "world"; - public static final String SERVER = "server"; - public static final String DIM = "DIM"; - public final static FilenameFilter NOT_DIM_FILTER = new FilenameFilter() + public static final String MC_VERIONS_URL = "https://s3.amazonaws.com/Minecraft.Download/versions/versions.json"; + public static final String FORGE_VERIONS_URL = "http://files.minecraftforge.net/maven/net/minecraftforge/forge/json"; + public static final String MC_SERVER_JAR_URL = "https://s3.amazonaws.com/Minecraft.Download/versions/%ID%/minecraft_server.%ID%.jar"; + public static final String FORGE_INSTALLER_URL = "http://files.minecraftforge.net/maven/net/minecraftforge/forge/%ID%/forge-%ID%-installer.jar"; + public static final String VERSION_CHECKER_URL = "http://jenkins.dries007.net/view/D3_misc/job/D3Backend/api/json?tree=lastStableBuild[number,artifacts[*]]"; + /* + * FORM field names + */ + public static final String USERNAME = "username"; + public static final String PASSWORD = "password"; + public static final String OLD_PASSWORD = "oldPassword"; + public static final String NEW_PASSWORD = "newPassword"; + public static final String ARE_YOU_HUMAN = "areyouhuman"; + /* + * File constants + */ + public static final File ROOT = getRootFile(); + public static final File CONFIG_FILE = new File(ROOT, "config.json"); + public static final File SERVERS_FILE = new File(ROOT, "servers.json"); + public static final File USERS_FILE = new File(ROOT, "users.json"); + public static final File SERVERS = new File(ROOT, "servers"); + public static final File BACKUPS = new File(ROOT, "backups"); + /* + * Time constants + */ + public static final long SOCKET_PING_TIME = 1000 * 50; // 50 seconds + public static final long REALLY_LONG_CACHE_TIMEOUT = 1000 * 60 * 60 * 24; // 24 hours + public static final long LONG_CACHE_TIMEOUT = 1000 * 60 * 60; // 1 hour + public static final long MEDIUM_CACHE_TIMEOUT = 1000 * 60; // 1 minute + public static final long SHORT_CACHE_TIMEOUT = 1000 * 10; // 20 seconds + /* + * Pattern constants + */ + public static final Pattern USERNAME_PATTERN = Pattern.compile("^[\\w-]+$"); + public static final Pattern VERSION_PATTERN = Pattern.compile("\\d+(?:\\.\\d+)+"); + public static final Pattern SERVER_START_ARGS_BLACKLIST_PATTERNS[] = {Pattern.compile("^-Xms.*$"), Pattern.compile("^-Xmx.*$"), Pattern.compile("^-XX:MaxPermSize=.*$")}; + /* + * FilenameFilter constants + */ + public final static FilenameFilter NOT_DIM_FILTER = new FilenameFilter() { @Override public boolean accept(File dir, String name) @@ -112,7 +139,7 @@ public boolean accept(File dir, String name) return !name.startsWith(DIM); } }; - public final static FilenameFilter DIM_ONLY_FILTER = new FilenameFilter() + public final static FilenameFilter DIM_ONLY_FILTER = new FilenameFilter() { @Override public boolean accept(File dir, String name) @@ -120,7 +147,7 @@ public boolean accept(File dir, String name) return name.startsWith(DIM); } }; - public final static FilenameFilter ACCEPT_ALL_FILTER = new FilenameFilter() + public final static FilenameFilter ACCEPT_ALL_FILTER = new FilenameFilter() { @Override public boolean accept(File dir, String name) @@ -128,7 +155,7 @@ public boolean accept(File dir, String name) return !name.equalsIgnoreCase("eula.txt"); } }; - public final static FilenameFilter ACCEPT_NONE_FILTER = new FilenameFilter() + public final static FilenameFilter ACCEPT_NONE_FILTER = new FilenameFilter() { @Override public boolean accept(File dir, String name) @@ -136,7 +163,7 @@ public boolean accept(File dir, String name) return false; } }; - public final static FilenameFilter ACCEPT_FORGE_FILTER = new FilenameFilter() + public final static FilenameFilter ACCEPT_FORGE_FILTER = new FilenameFilter() { @Override public boolean accept(File dir, String name) @@ -144,7 +171,7 @@ public boolean accept(File dir, String name) return name.startsWith("forge"); } }; - public final static FilenameFilter ACCEPT_MINECRAFT_SERVER_FILTER = new FilenameFilter() + public final static FilenameFilter ACCEPT_MINECRAFT_SERVER_FILTER = new FilenameFilter() { @Override public boolean accept(File dir, String name) @@ -152,22 +179,29 @@ public boolean accept(File dir, String name) return name.startsWith("minecraft_server"); } }; - public static final TemplateModel HELPER_TEMPLATE_MODEL = getStaticHelper(); - public static final Timer TIMER = new Timer(); - public static final Joiner JOINER_COMMA_SPACE = Joiner.on(", "); - public static final Joiner JOINER_COMMA = Joiner.on(','); - public static final Joiner JOINER_SPACE = Joiner.on(' '); - public static final String VERSION_CHECKER_URL = "http://jenkins.dries007.net/view/D3_misc/job/D3Backend/api/json?tree=lastStableBuild[number,artifacts[*]]"; - public static final Pattern VERSION_PATTERN = Pattern.compile("\\d+(?:\\.\\d+)+"); - public static final String JAVAPATH = getJavaPath(); - public static final String SLASH_STR = "/"; - public static final String TEMPLATE_EXTENSION = ".ftl"; - public static final long SOCKET_PING_TIME = 1000 * 50; + /* + * JSON constants + */ + public static final Gson GSON = getGSON(); + public static final JsonParser JSONPARSER = new JsonParser(); + /* + * Joiner constants + */ + public static final Joiner JOINER_COMMA_SPACE = Joiner.on(", "); + public static final Joiner JOINER_COMMA = Joiner.on(','); + public static final Joiner JOINER_SPACE = Joiner.on(' '); + /* + * Special constants + * Can be order sensitive! + */ + public static final Random RANDOM = new Random(); + public static final String JAVAPATH = getJavaPath(); + public static final SimpleDateFormat BACKUP_SDF = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss"); + public static final Timer TIMER = new Timer(); /** * Methods that only get called to init the Constants */ - private Constants() { } @@ -204,15 +238,8 @@ else if (OSUtils.getCurrentOS() == OSUtils.OS.WINDOWS) return System.getProperty("java.home") + "/bin/java"; } - private static TemplateModel getStaticHelper() + private static Gson getGSON() { - try - { - return BeansWrapper.getDefaultInstance().getStaticModels().get(Helper.class.getName()); - } - catch (TemplateModelException e) - { - throw new RuntimeException(e); - } + return new GsonBuilder().registerTypeAdapter(Server.class, new Server.Deserializer()).registerTypeAdapter(ServerData.class, new ServerData.Deserializer()).registerTypeAdapter(Server.class, new Server.Serializer()).setPrettyPrinting().create(); } } diff --git a/src/main/java/net/doubledoordev/backend/util/Helper.java b/src/main/java/net/doubledoordev/backend/util/Helper.java index e07b867..71315ac 100644 --- a/src/main/java/net/doubledoordev/backend/util/Helper.java +++ b/src/main/java/net/doubledoordev/backend/util/Helper.java @@ -100,6 +100,7 @@ public static boolean isPortAvailable(String hostname, int port) } } + private static final char[] symbols = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); public static String randomString(int length) { return new String(randomCharArray(length)); diff --git a/src/main/java/net/doubledoordev/backend/util/PortRange.java b/src/main/java/net/doubledoordev/backend/util/PortRange.java index c16f576..a4696c3 100644 --- a/src/main/java/net/doubledoordev/backend/util/PortRange.java +++ b/src/main/java/net/doubledoordev/backend/util/PortRange.java @@ -41,6 +41,7 @@ package net.doubledoordev.backend.util; import net.doubledoordev.backend.server.Server; +import net.doubledoordev.backend.util.exceptions.OutOfPortsException; import java.util.HashSet; @@ -73,12 +74,4 @@ public int getNextAvailablePort() throws OutOfPortsException { return getNextAvailablePort(-1); } - - public static class OutOfPortsException extends Exception - { - private OutOfPortsException() - { - super("We have run out of available ports..."); - } - } } diff --git a/src/main/java/net/doubledoordev/backend/util/exceptions/BackupException.java b/src/main/java/net/doubledoordev/backend/util/exceptions/BackupException.java new file mode 100644 index 0000000..74fd37c --- /dev/null +++ b/src/main/java/net/doubledoordev/backend/util/exceptions/BackupException.java @@ -0,0 +1,53 @@ +/* + * Unless otherwise specified through the '@author' tag or comments at + * the top of the file or on a specific portion of the code the following license applies: + * + * Copyright (c) 2014, DoubleDoorDevelopment + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * The header specified or the above copyright notice, this list of conditions + * and the following disclaimer below must be displayed at the top of the source code + * of any web page received while using any part of the service this software provides. + * + * The header to be displayed: + * This page was generated by DoubleDoorDevelopment's D3Backend or a derivative thereof. + * + * Neither the name of the project nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.doubledoordev.backend.util.exceptions; + +/** + * @author Dries007 + */ +public class BackupException extends Exception +{ + public BackupException(String s) + { + super(s); + } +} diff --git a/src/main/java/net/doubledoordev/backend/util/exceptions/OutOfPortsException.java b/src/main/java/net/doubledoordev/backend/util/exceptions/OutOfPortsException.java new file mode 100644 index 0000000..2bdf3a2 --- /dev/null +++ b/src/main/java/net/doubledoordev/backend/util/exceptions/OutOfPortsException.java @@ -0,0 +1,53 @@ +/* + * Unless otherwise specified through the '@author' tag or comments at + * the top of the file or on a specific portion of the code the following license applies: + * + * Copyright (c) 2014, DoubleDoorDevelopment + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * The header specified or the above copyright notice, this list of conditions + * and the following disclaimer below must be displayed at the top of the source code + * of any web page received while using any part of the service this software provides. + * + * The header to be displayed: + * This page was generated by DoubleDoorDevelopment's D3Backend or a derivative thereof. + * + * Neither the name of the project nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.doubledoordev.backend.util.exceptions; + +/** + * @author Dries007 + */ +public class OutOfPortsException extends Exception +{ + public OutOfPortsException() + { + super("We have run out of available ports..."); + } +} diff --git a/src/main/java/net/doubledoordev/backend/util/exceptions/PostException.java b/src/main/java/net/doubledoordev/backend/util/exceptions/PostException.java new file mode 100644 index 0000000..a83d898 --- /dev/null +++ b/src/main/java/net/doubledoordev/backend/util/exceptions/PostException.java @@ -0,0 +1,74 @@ +/* + * Unless otherwise specified through the '@author' tag or comments at + * the top of the file or on a specific portion of the code the following license applies: + * + * Copyright (c) 2014, DoubleDoorDevelopment + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * The header specified or the above copyright notice, this list of conditions + * and the following disclaimer below must be displayed at the top of the source code + * of any web page received while using any part of the service this software provides. + * + * The header to be displayed: + * This page was generated by DoubleDoorDevelopment's D3Backend or a derivative thereof. + * + * Neither the name of the project nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +package net.doubledoordev.backend.util.exceptions; + +import net.doubledoordev.backend.web.http.PostHandler; + +/** + * @author Dries007 + */ +public class PostException extends Exception +{ + public PostException() + { + } + + public PostException(String message) + { + super(message); + } + + public PostException(String message, Throwable cause) + { + super(message, cause); + } + + public PostException(Throwable cause) + { + super(cause); + } + + public PostException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) + { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/src/main/java/net/doubledoordev/backend/web/http/FreemarkerHandler.java b/src/main/java/net/doubledoordev/backend/web/http/FreemarkerHandler.java index 7e3a859..7aad29e 100644 --- a/src/main/java/net/doubledoordev/backend/web/http/FreemarkerHandler.java +++ b/src/main/java/net/doubledoordev/backend/web/http/FreemarkerHandler.java @@ -41,11 +41,14 @@ package net.doubledoordev.backend.web.http; +import com.google.common.collect.ImmutableList; +import freemarker.ext.beans.BeansWrapper; import freemarker.template.*; import net.doubledoordev.backend.permissions.User; import net.doubledoordev.backend.server.FileManager; import net.doubledoordev.backend.server.Server; import net.doubledoordev.backend.util.Constants; +import net.doubledoordev.backend.util.Helper; import net.doubledoordev.backend.util.Settings; import org.apache.commons.lang3.exception.ExceptionUtils; import org.glassfish.grizzly.http.Method; @@ -61,8 +64,7 @@ import java.util.HashMap; import java.util.Map; -import static net.doubledoordev.backend.util.Constants.ERROR_TEMPLATE; -import static net.doubledoordev.backend.util.Constants.SLASH_STR; +import static net.doubledoordev.backend.util.Constants.*; import static net.doubledoordev.backend.web.http.PostHandler.POST_HANDLER; /** @@ -72,7 +74,8 @@ */ public class FreemarkerHandler extends StaticHttpHandlerBase implements ErrorPageGenerator { - private final Configuration freemarker = new Configuration(); + private static final ImmutableList ADMINPAGES = ImmutableList.of("console", "backendConsoleText"); + private final Configuration freemarker = new Configuration(); public FreemarkerHandler(Class clazz, String path) throws TemplateModelException { @@ -83,7 +86,7 @@ public FreemarkerHandler(Class clazz, String path) throws TemplateModelException freemarker.setIncompatibleImprovements(new Version(2, 3, 20)); // FreeMarker 2.3.20 Map dataObject = new HashMap<>(); dataObject.put("Settings", Settings.SETTINGS); - dataObject.put("Helper", Constants.HELPER_TEMPLATE_MODEL); + dataObject.put("Helper", BeansWrapper.getDefaultInstance().getStaticModels().get(Helper.class.getName())); freemarker.setAllSharedVariables(new SimpleHash(dataObject)); } @@ -93,14 +96,16 @@ protected boolean handle(String uri, Request request, Response response) throws if (request.getSession(false) != null) request.getSession(); HashMap data = new HashMap<>(request.getSession().attributes().size() + 10); + // Put all session data in map, take 1 + data.putAll(request.getSession().attributes()); /** * Data processing */ if (request.getMethod() == Method.GET) { - data.put("server", Settings.getServerByName(request.getParameter("server"))); - if (uri.equals("/filemanager")) data.put("fm", new FileManager((Server) data.get("server"), request.getParameter("file"))); + data.put(SERVER, Settings.getServerByName(request.getParameter(SERVER))); + if (uri.equals("/filemanager")) data.put("fm", new FileManager((Server) data.get(SERVER), request.getParameter(FILE))); } else if (request.getMethod() == Method.POST) { @@ -114,25 +119,22 @@ else if (request.getMethod() == Method.POST) /** * fix up the url to match template */ - if (uri.endsWith(SLASH_STR)) uri += "index"; + if (uri.endsWith(SLASH_STR)) uri += INDEX; if (uri.startsWith(SLASH_STR)) uri = uri.substring(1); - if (request.getSession().getAttribute("user") == null && !Settings.SETTINGS.anonPages.contains(uri)) + if (request.getSession().getAttribute(USER) == null && !Settings.SETTINGS.anonPages.contains(uri)) { response.sendError(HttpStatus.UNAUTHORIZED_401.getStatusCode()); return true; } - else if (Constants.ADMINPAGES.contains(uri) && !((User) request.getSession().getAttribute("user")).isAdmin()) + else if (ADMINPAGES.contains(uri) && !((User) request.getSession().getAttribute(USER)).isAdmin()) { response.sendError(HttpStatus.UNAUTHORIZED_401.getStatusCode()); return true; } if (!uri.endsWith(Constants.TEMPLATE_EXTENSION)) uri += Constants.TEMPLATE_EXTENSION; - /** - * Put all session data in map - */ - + // Put all session data in map, take 2 data.putAll(request.getSession().attributes()); try diff --git a/src/main/java/net/doubledoordev/backend/web/http/PostHandler.java b/src/main/java/net/doubledoordev/backend/web/http/PostHandler.java index 63e8000..4eb84a8 100644 --- a/src/main/java/net/doubledoordev/backend/web/http/PostHandler.java +++ b/src/main/java/net/doubledoordev/backend/web/http/PostHandler.java @@ -44,33 +44,36 @@ import net.doubledoordev.backend.Main; import net.doubledoordev.backend.permissions.Group; import net.doubledoordev.backend.permissions.User; +import net.doubledoordev.backend.server.Server; +import net.doubledoordev.backend.server.ServerData; import net.doubledoordev.backend.util.Constants; import net.doubledoordev.backend.util.PasswordHash; +import net.doubledoordev.backend.util.PortRange; import net.doubledoordev.backend.util.Settings; +import net.doubledoordev.backend.util.exceptions.OutOfPortsException; +import net.doubledoordev.backend.util.exceptions.PostException; +import org.apache.commons.io.FileUtils; import org.glassfish.grizzly.http.server.Request; import org.glassfish.grizzly.http.server.Response; import org.glassfish.grizzly.http.util.Parameters; +import java.io.File; +import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidKeySpecException; +import java.util.Arrays; +import java.util.Date; import java.util.HashMap; import java.util.Set; +import static net.doubledoordev.backend.util.Constants.*; + /** * @author Dries007 - *

- * todo: New server!! */ public class PostHandler { public static final PostHandler POST_HANDLER = new PostHandler(); - private static final String LOGIN = "/login"; - private static final String REGISTER = "/register"; - private static final String USERNAME = "username"; - private static final String PASSWORD = "password"; - private static final String OLD_PASSWORD = "oldPassword"; - private static final String NEW_PASSWORD = "newPassword"; - private static final String ARE_YOU_HUMAN = "areyouhuman"; private PostHandler() { @@ -82,10 +85,12 @@ public String handle(HashMap data, String uri, Request request, { switch (uri) { - case LOGIN: + case LOGIN_URL: return doLogin(uri, request, response); - case REGISTER: + case REGISTER_URL: return doRegister(uri, request, response); + case NEWSERVER_URL: + return doNewserver(data, uri, request, response); } } catch (PostException e) @@ -95,22 +100,100 @@ public String handle(HashMap data, String uri, Request request, return uri; } + private String doNewserver(HashMap data, String uri, Request request, Response response) throws PostException + { + Parameters parameters = request.getParameters(); + Set names = request.getParameterNames(); + + User user = (User) data.get("user"); + if (user == null) throw new PostException("Not logged in."); + if (user.getMaxServers() != -1 && user.getServerCount() >= user.getMaxServers()) throw new PostException("Max server count reached."); + ServerData serverData = new ServerData(); + if (user.getGroup() == Group.ADMIN && names.contains("owner")) serverData.owner = parameters.getParameter("owner"); + else serverData.owner = user.getUsername(); + + serverData.ID = serverData.owner + "_" + parameters.getParameter("name"); + if (Settings.getServerByName(serverData.ID) != null) throw new PostException("Duplicate server ID"); + + serverData.ramMin = Integer.parseInt(parameters.getParameter("RAMmin")); + serverData.ramMax = Integer.parseInt(parameters.getParameter("RAMmax")); + if (serverData.ramMax < serverData.ramMin) + { + int temp = serverData.ramMax; + serverData.ramMax = serverData.ramMin; + serverData.ramMin = temp; + } + if (user.getMaxRam() != -1 && user.getMaxRamLeft() < serverData.ramMax) throw new PostException("You are over your max RAM."); + if (serverData.ramMax < 2 || serverData.ramMin < 2) throw new PostException("RAM settings invalid."); + + serverData.permGen = Integer.parseInt(parameters.getParameter("PermGen")); + if (serverData.permGen < 2) throw new PostException("PermGen settings invalid."); + + if (parameters.getParameter("extraJavaParameters").trim().length() != 0) serverData.extraJavaParameters = Arrays.asList(parameters.getParameter("extraJavaParameters").trim().split("\n")); + if (parameters.getParameter("extraMCParameters").trim().length() != 0) serverData.extraMCParameters = Arrays.asList(parameters.getParameter("extraMCParameters").trim().split("\n")); + if (parameters.getParameter("admins").trim().length() != 0) serverData.admins = Arrays.asList(parameters.getParameter("admins").trim().split("\n")); + if (parameters.getParameter("coOwners").trim().length() != 0) serverData.coOwners = Arrays.asList(parameters.getParameter("coOwners").trim().split("\n")); + + serverData.jarName = parameters.getParameter("jarname"); + serverData.rconPswd = parameters.getParameter("rconpass"); + try + { + serverData.serverPort = Settings.SETTINGS.fixedPorts ? Settings.SETTINGS.portRange.getNextAvailablePort() : Integer.parseInt(parameters.getParameter("serverport")); + serverData.rconPort = Settings.SETTINGS.fixedPorts ? Settings.SETTINGS.portRange.getNextAvailablePort(serverData.serverPort) : Integer.parseInt(parameters.getParameter("rconport")); + } + catch (OutOfPortsException e) + { + throw new PostException("The backend ran out of ports to assign."); + } + serverData.ip = parameters.getParameter("ip"); + serverData.autoStart = names.contains("autostart") && parameters.getParameter("autostart").equals("on"); + + Server server = new Server(serverData, true); + Settings.SETTINGS.servers.put(serverData.ID, server); + Settings.save(); + data.put("server", server); + + try + { + FileUtils.writeStringToFile(new File(server.getFolder(), "eula.txt"), + "#The server owner indicated to agree with the EULA when submitting the from that produced this server instance.\n" + + "#That means that there is no need for extra halting of the server startup sequence with this stupid file.\n" + + "#" + new Date().toString() + "\n" + + "eula=true\n"); + } + catch (IOException e) + { + server.printLine("Error making the eula file...."); + e.printStackTrace(); + } + try + { + response.sendRedirect(Constants.SERVER_URL + serverData.ID); + } + catch (IOException e) + { + e.printStackTrace(); + } + + return uri; + } + private String doRegister(String uri, Request request, Response response) throws PostException { Parameters parameters = request.getParameters(); Set names = request.getParameterNames(); - if (names.contains(USERNAME) && names.contains(PASSWORD) && names.contains(ARE_YOU_HUMAN)) + if (names.contains(Constants.USERNAME) && names.contains(Constants.PASSWORD) && names.contains(Constants.ARE_YOU_HUMAN)) { - String username = parameters.getParameter(USERNAME); - boolean admin = Main.adminKey != null && parameters.getParameter(ARE_YOU_HUMAN).equals(Main.adminKey); - if (!admin && !parameters.getParameter(ARE_YOU_HUMAN).trim().equals("4")) throw new PostException("You failed the human test..."); + String username = parameters.getParameter(Constants.USERNAME); + boolean admin = Main.adminKey != null && parameters.getParameter(Constants.ARE_YOU_HUMAN).equals(Main.adminKey); + if (!admin && !parameters.getParameter(Constants.ARE_YOU_HUMAN).trim().equals("4")) throw new PostException("You failed the human test..."); User user = Settings.getUserByName(username); if (user != null) throw new PostException("Username taken."); - if (!Constants.USERNAME_CHECK.matcher(username).matches()) throw new PostException("Username contains invalid chars.
Only a-Z, 0-9, _ and - please."); + if (!Constants.USERNAME_PATTERN.matcher(username).matches()) throw new PostException("Username contains invalid chars.
Only a-Z, 0-9, _ and - please."); try { - user = new User(username, PasswordHash.createHash(parameters.getParameter(PASSWORD))); + user = new User(username, PasswordHash.createHash(parameters.getParameter(Constants.PASSWORD))); if (admin) { user.setGroup(Group.ADMIN); @@ -121,7 +204,7 @@ private String doRegister(String uri, Request request, Response response) throws request.getSession().setAttribute("user", user); Settings.save(); - return LOGIN; + return LOGIN_URL; } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { @@ -137,11 +220,11 @@ private String doLogin(String uri, Request request, Response response) throws Po Parameters parameters = request.getParameters(); Set names = request.getParameterNames(); - if (names.contains(USERNAME) && names.contains(PASSWORD)) + if (names.contains(Constants.USERNAME) && names.contains(Constants.PASSWORD)) { - User user = Settings.getUserByName(parameters.getParameter(USERNAME)); - if (user == null) throw new PostException(String.format("User %s can't be found.", parameters.getParameter(USERNAME))); - if (!user.verify(parameters.getParameter(PASSWORD))) throw new PostException("Password wrong."); + User user = Settings.getUserByName(parameters.getParameter(Constants.USERNAME)); + if (user == null) throw new PostException(String.format("User %s can't be found.", parameters.getParameter(Constants.USERNAME))); + if (!user.verify(parameters.getParameter(Constants.PASSWORD))) throw new PostException("Password wrong."); request.getSession().setAttribute("user", user); } else if (names.contains("logout")) @@ -149,40 +232,13 @@ else if (names.contains("logout")) request.getSession().attributes().clear(); request.changeSessionId(); } - else if (names.contains(OLD_PASSWORD) && names.contains(NEW_PASSWORD)) + else if (names.contains(Constants.OLD_PASSWORD) && names.contains(Constants.NEW_PASSWORD)) { User user = (User) request.getSession().getAttribute("user"); - if (!user.updatePassword(parameters.getParameter(OLD_PASSWORD), parameters.getParameter(NEW_PASSWORD))) throw new PostException("Password wrong."); + if (!user.updatePassword(parameters.getParameter(Constants.OLD_PASSWORD), parameters.getParameter(Constants.NEW_PASSWORD))) throw new PostException("Password wrong."); } else throw new PostException("Form not of known format."); return uri; } - - public static class PostException extends Exception - { - public PostException() - { - } - - public PostException(String message) - { - super(message); - } - - public PostException(String message, Throwable cause) - { - super(message, cause); - } - - public PostException(Throwable cause) - { - super(cause); - } - - public PostException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) - { - super(message, cause, enableSuppression, writableStackTrace); - } - } } diff --git a/src/main/java/net/doubledoordev/backend/web/socket/ServerControlSocketApplication.java b/src/main/java/net/doubledoordev/backend/web/socket/ServerControlSocketApplication.java index 7f36e37..e42039d 100644 --- a/src/main/java/net/doubledoordev/backend/web/socket/ServerControlSocketApplication.java +++ b/src/main/java/net/doubledoordev/backend/web/socket/ServerControlSocketApplication.java @@ -61,13 +61,13 @@ import static net.doubledoordev.backend.util.Constants.*; /** + * TODO: change to /server/id + * * @author Dries007 - *

- * TODO: change to /server/id */ public class ServerControlSocketApplication extends WebSocketApplication { - public static final String URL_PATTERN = "/server/*"; + private static final String URL_PATTERN = "/server/*"; public static final ServerControlSocketApplication SERVER_CONTROL_SOCKET_APPLICATION = new ServerControlSocketApplication(); @@ -150,7 +150,6 @@ else if (!server.canUserControl((User) ((DefaultWebSocket) socket).getUpgradeReq jsonObject.addProperty("status", "error"); jsonObject.addProperty("message", ""); } - Main.LOGGER.info(jsonObject.toString()); socket.send(jsonObject.toString()); socket.close(); } diff --git a/src/main/java/net/doubledoordev/backend/web/socket/ServerListSocketApplication.java b/src/main/java/net/doubledoordev/backend/web/socket/ServerListSocketApplication.java index 646558a..d134bdc 100644 --- a/src/main/java/net/doubledoordev/backend/web/socket/ServerListSocketApplication.java +++ b/src/main/java/net/doubledoordev/backend/web/socket/ServerListSocketApplication.java @@ -64,7 +64,7 @@ */ public class ServerListSocketApplication extends WebSocketApplication { - public static final String URL_PATTERN = "/serverlist"; + private static final String URL_PATTERN = "/serverlist"; public static final ServerListSocketApplication SERVER_LIST_SOCKET_APPLICATION = new ServerListSocketApplication(); diff --git a/src/main/java/net/doubledoordev/backend/webserver_old/methods/Get.java b/src/main/java/net/doubledoordev/backend/webserver_old/methods/Get.java index 9227290..0427ec2 100644 --- a/src/main/java/net/doubledoordev/backend/webserver_old/methods/Get.java +++ b/src/main/java/net/doubledoordev/backend/webserver_old/methods/Get.java @@ -91,7 +91,7 @@ public class Get */ Map dataObject = new HashMap<>(); dataObject.put("Settings", Settings.SETTINGS); - dataObject.put("Helper", Constants.HELPER_TEMPLATE_MODEL); + //dataObject.put("Helper", Constants.HELPER_TEMPLATE_MODEL); FREEMARKER_CFG.setAllSharedVariables(new SimpleHash(dataObject)); } catch (TemplateModelException e) diff --git a/src/main/java/net/doubledoordev/backend/webserver_old/methods/Post.java b/src/main/java/net/doubledoordev/backend/webserver_old/methods/Post.java index da66fa1..84ac2b8 100644 --- a/src/main/java/net/doubledoordev/backend/webserver_old/methods/Post.java +++ b/src/main/java/net/doubledoordev/backend/webserver_old/methods/Post.java @@ -175,7 +175,7 @@ else if (!map.get("areyouhuman").trim().equals("4")) // only do human test if no } User user = Settings.getUserByName(map.get("username")); - if (!Constants.USERNAME_CHECK.matcher(map.get("username")).matches()) + if (!Constants.USERNAME_PATTERN.matcher(map.get("username")).matches()) { dataObject.put("message", "Username contains invalid chars.
Only a-Z, 0-9, _ and - please."); } diff --git a/src/main/resources/templates/header.ftl b/src/main/resources/templates/header.ftl index 4a30419..ebe9bbf 100644 --- a/src/main/resources/templates/header.ftl +++ b/src/main/resources/templates/header.ftl @@ -68,20 +68,20 @@ } function call(url, message, func) { - websocket = new WebSocket(wsurl(url)); + var websocket = new WebSocket(wsurl(url)); websocket.onopen = function (evt) { websocket.send(message); } - websocket.onclose = function (evt) { - alert("The socket connction closed. Refresh the page."); - }; websocket.onmessage = function (evt) { - console.log(func); - console.log(typeof func); - if (typeof func !== 'undefined') func(); + if (typeof func === 'undefined') + { + var temp = JSON.parse(evt.data); + if (temp.status !== "ok") alert(temp.message); + } + else func(evt.data); }; websocket.onerror = function (evt) { - alert("The socket connction errored. Refresh the page."); + alert("The call socket connction errored. Try again."); }; } diff --git a/src/main/resources/templates/newserver.ftl b/src/main/resources/templates/newserver.ftl index ef90c7d..e3fbab8 100644 --- a/src/main/resources/templates/newserver.ftl +++ b/src/main/resources/templates/newserver.ftl @@ -1,12 +1,7 @@ <#include "header.ftl"> <#if message??> -

+ -<#if step2??> - -<#else>
<#if user.isAdmin()>
@@ -162,5 +157,4 @@ } } - <#include "footer.ftl"> diff --git a/src/main/resources/templates/servers.ftl b/src/main/resources/templates/servers.ftl index a988148..6efb9d5 100644 --- a/src/main/resources/templates/servers.ftl +++ b/src/main/resources/templates/servers.ftl @@ -40,10 +40,10 @@ function createBtnGroup(row, type, set1, meta) { return '
' + - '' + + '' + '' + - '' + - '' + + '' + + '' + '
' } @@ -52,7 +52,7 @@ $(td).click(function() {window.document.location = "/server?server=" + rowData.id}); } - table = $('#servers').DataTable({ + var table = $('#servers').DataTable({ paging: false, searching: false, data: [], @@ -71,19 +71,14 @@ { data: 'motd', createdCell:makeClickable } ] }); - websocket = new WebSocket(wsurl("serverlist")); + var websocket = new WebSocket(wsurl("serverlist")); websocket.onmessage = function (evt) { var temp = JSON.parse(evt.data); if (temp.status === "ok") { - - table.rows(function (idx, data, node) - { - return data.id === temp.data.id; - }).remove(); + table.rows(function (idx, data, node) { return data.id === temp.data.id; }).remove(); table.row.add(temp.data); - table.draw(); } else alert(temp.message);