diff --git a/.gitignore b/.gitignore index 2353a94..61baa9b 100644 --- a/.gitignore +++ b/.gitignore @@ -63,8 +63,12 @@ genTwitterTokens/classes/generatetwittertokens .idea out/ *.iml +target/ # Netbeans Project files nbproject # Eclipse Project files + + +*access* \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..d030dd2 --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +## NGINX Reverse Config + server { + listen 80; + listen [::]:80; + server_name paste.mc8051.de; + + root /var/www/html/; + index index.html index.php index.htm; + + client_max_body_size 25m; + + ## Definition Reverse Proxy ## + location / { + proxy_pass http://127.0.0.1:8080/; + proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; + proxy_redirect off; + proxy_buffering off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + } diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..06c2bdf --- /dev/null +++ b/pom.xml @@ -0,0 +1,90 @@ + + + 4.0.0 + + de.gurkengewuerz + termbin + 1.0-SNAPSHOT + + + + MIT License + https://opensource.org/licenses/MIT + repo + + + + + + Gurkengewuerz + admin@gurkengewuerz.de + https://gurkengewuerz.de + Europe/Berlin + + + + + + org.eclipse.jetty + jetty-server + 9.4.3.v20170317 + + + org.xerial + sqlite-jdbc + 3.16.1 + + + org.json + json + 20160810 + + + org.apache.commons + commons-lang3 + 3.5 + + + + + + + maven-compiler-plugin + 3.5.1 + + 1.8 + 1.8 + + + + maven-assembly-plugin + 2.6 + + false + ${project.artifactId} + + + jar-with-dependencies + + + + + ${project.groupId}.${project.artifactId}.Termbin + + + + + + assamble + + single + + package + + + + + + \ No newline at end of file diff --git a/src/de/gurkengewuerz/termbin/Config.java b/src/main/java/de/gurkengewuerz/termbin/Config.java similarity index 83% rename from src/de/gurkengewuerz/termbin/Config.java rename to src/main/java/de/gurkengewuerz/termbin/Config.java index 5bf1c85..87291fe 100644 --- a/src/de/gurkengewuerz/termbin/Config.java +++ b/src/main/java/de/gurkengewuerz/termbin/Config.java @@ -20,8 +20,12 @@ import java.util.logging.Logger; */ public class Config extends JSONObject { private File file; - private static List ban = new ArrayList<>(); - private static List whitelist = new ArrayList<>(); + private List ban = new ArrayList<>(); + private List whitelist = new ArrayList<>(); + + private JSONObject uploadServerConf; + private JSONObject dataServerConf; + private JSONObject apiServerConf; public Config(File file) throws IOException { this.file = file; @@ -38,9 +42,11 @@ public class Config extends JSONObject { throw new AccessDeniedException(file.getAbsolutePath() + " is not accessable"); } - this.put("log", "termvin.log"); + this.put("accesslog", "access"); this.put("database", "db.sqlite3"); this.put("domain", "http://localhost/"); + this.put("uploadlifetime", 24 * 7); // 1 week hours + this.put("maxkb", 1024 * 2); // 2 mb JSONObject uploadserver = new JSONObject(); uploadserver.put("port", 8888); @@ -48,7 +54,7 @@ public class Config extends JSONObject { this.put("uploadserver", uploadserver); JSONObject dataserver = new JSONObject(); - dataserver.put("port", 8080); + dataserver.put("port", 7070); this.put("dataserver", dataserver); JSONObject apiserver = new JSONObject(); @@ -116,7 +122,7 @@ public class Config extends JSONObject { jt.back(); break; case '}': - loadRestData(); + save(); return; default: throw jt.syntaxError("Expected a ',' or '}'"); @@ -140,9 +146,29 @@ public class Config extends JSONObject { if (whitelist.contains(json_ban.getString(i))) continue; ban.add(json_ban.getString(i)); } + + uploadServerConf = getJSONObject("uploadserver"); + dataServerConf = getJSONObject("dataserver"); + apiServerConf = getJSONObject("apiserver"); } public boolean isBanned(String ipv4) { return ban.contains(ipv4); } + + public List getBans() { + return ban; + } + + public JSONObject getUploadServerConfig() { + return uploadServerConf; + } + + public JSONObject getDataServerConfig() { + return dataServerConf; + } + + public JSONObject getApiServerConfig() { + return apiServerConf; + } } diff --git a/src/de/gurkengewuerz/termbin/Database.java b/src/main/java/de/gurkengewuerz/termbin/Database.java similarity index 100% rename from src/de/gurkengewuerz/termbin/Database.java rename to src/main/java/de/gurkengewuerz/termbin/Database.java diff --git a/src/de/gurkengewuerz/termbin/Server/APIHandler.java b/src/main/java/de/gurkengewuerz/termbin/Server/APIHandler.java similarity index 92% rename from src/de/gurkengewuerz/termbin/Server/APIHandler.java rename to src/main/java/de/gurkengewuerz/termbin/Server/APIHandler.java index 7c6d5f5..0e37804 100644 --- a/src/de/gurkengewuerz/termbin/Server/APIHandler.java +++ b/src/main/java/de/gurkengewuerz/termbin/Server/APIHandler.java @@ -24,9 +24,10 @@ public class APIHandler extends AbstractHandler { @Override public void handle(String s, Request request, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException, ServletException { - Logger.getLogger(getClass().getName()).log(Level.INFO, "API Request by " + request.getRemoteAddr() + "@" + s); + Logger.getLogger(getClass().getName()).log(Level.INFO, "API Request by " + request.getHeader("User-Agent") + " " + request.getRemoteAddr() + "@" + s); + Termbin.getAccesslog().log(Level.INFO, request.getRemoteAddr() + " - - " + request.getHeader("User-Agent") + " - " + s); - if(Termbin.getConfig().isBanned(request.getRemoteAddr())) { + if (Termbin.getConfig().isBanned(request.getRemoteAddr())) { request.setHandled(true); Logger.getLogger(getClass().getName()).log(Level.INFO, "API Request by " + request.getRemoteAddr() + "@" + s + " closed BANNED"); return; @@ -53,7 +54,7 @@ public class APIHandler extends AbstractHandler { int n = httpServletRequest.getInputStream().read(buff); if (n < 0) break; baos.write(buff, 0, n); - if (baos.size() > 1024 * 1024 * 2) {// 2 MB + if (baos.size() > 1024 * Termbin.getConfig().getInt("maxkb")) { breaked = true; returnObject.put("error", "File too big"); Logger.getLogger(getClass().getName()).log(Level.INFO, "API Request by " + request.getRemoteAddr() + "@" + s + " closed FILE TOO BIG"); diff --git a/src/de/gurkengewuerz/termbin/Server/DataHandler.java b/src/main/java/de/gurkengewuerz/termbin/Server/DataHandler.java similarity index 84% rename from src/de/gurkengewuerz/termbin/Server/DataHandler.java rename to src/main/java/de/gurkengewuerz/termbin/Server/DataHandler.java index c9057e5..f35f4e5 100644 --- a/src/de/gurkengewuerz/termbin/Server/DataHandler.java +++ b/src/main/java/de/gurkengewuerz/termbin/Server/DataHandler.java @@ -21,7 +21,8 @@ public class DataHandler extends AbstractHandler { @Override public void handle(String s, Request request, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException, ServletException { - Logger.getLogger(getClass().getName()).log(Level.INFO, "Request by " + request.getRemoteAddr() + "@" + s); + Logger.getLogger(getClass().getName()).log(Level.INFO, "API Request by " + request.getHeader("User-Agent") + " " + request.getRemoteAddr() + "@" + s); + Termbin.getAccesslog().log(Level.INFO, request.getRemoteAddr() + " - - " + request.getHeader("User-Agent") + " - " + s); if (Termbin.getConfig().isBanned(request.getRemoteAddr())) { request.setHandled(true); @@ -37,6 +38,8 @@ public class DataHandler extends AbstractHandler { boolean found = false; httpServletResponse.setStatus(HttpServletResponse.SC_OK); while (rs.next()) { + if ((((System.currentTimeMillis() / 1000) - rs.getFloat("timestamp")) / 60 / 60) > Termbin.getConfig().getInt("uploadlifetime")) + break; found = true; httpServletResponse.setContentType(rs.getString("filetype")); if (rs.getString("filetype").equals("text/plain")) { @@ -49,12 +52,14 @@ public class DataHandler extends AbstractHandler { if (!found) { httpServletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND); + httpServletResponse.setContentType("text/html"); httpServletResponse.getOutputStream().write("".getBytes("UTF-8")); } } catch (SQLException e) { Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, e); httpServletResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + httpServletResponse.setContentType("text/html"); httpServletResponse.getOutputStream().write("".getBytes("UTF-8")); } diff --git a/src/de/gurkengewuerz/termbin/Server/UploadServer.java b/src/main/java/de/gurkengewuerz/termbin/Server/UploadServer.java similarity index 93% rename from src/de/gurkengewuerz/termbin/Server/UploadServer.java rename to src/main/java/de/gurkengewuerz/termbin/Server/UploadServer.java index 1b3b183..7402804 100644 --- a/src/de/gurkengewuerz/termbin/Server/UploadServer.java +++ b/src/main/java/de/gurkengewuerz/termbin/Server/UploadServer.java @@ -17,16 +17,21 @@ import java.util.logging.Logger; */ public class UploadServer { + private ServerSocket listener; + private int clientNumber = 1; + public UploadServer(String ipv4, int port) throws IOException { Logger.getLogger("Main").log(Level.INFO, "Starting..."); - int clientNumber = 1; - ServerSocket listener = new ServerSocket(port); + + listener = new ServerSocket(port); if (!ipv4.isEmpty() && !ipv4.equals("0.0.0.0")) { listener.bind(new InetSocketAddress(ipv4, port)); } Logger.getLogger(getClass().getName()).log(Level.INFO, "Started. Waiting for Clients."); + } + public void start() throws IOException { try { while (true) { Socket socketOfServer = listener.accept(); @@ -53,7 +58,7 @@ public class UploadServer { Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, e); } Logger.getLogger(getClass().getName()).log(Level.INFO, "opened " + client + " at " + socketOfServer.getLocalAddress() + ":" + socketOfServer.getLocalPort()); - + Termbin.getAccesslog().log(Level.INFO, clientIP + " - - socket " + socketOfServer.getLocalPort()); if (Termbin.getConfig().isBanned(clientIP)) { Logger.getLogger(getClass().getName()).log(Level.INFO, "closed " + client + " with error banned"); try { @@ -77,7 +82,7 @@ public class UploadServer { int n = socketOfServer.getInputStream().read(buff); if (n < 0) break; baos.write(buff, 0, n); - if (baos.size() > 1024 * 1024 * 2) {// 2 MB + if (baos.size() > 1024 * Termbin.getConfig().getInt("maxkb")) {// 2 MB Logger.getLogger(getClass().getName()).log(Level.INFO, "closed " + client + " with file to big"); os.write("File to big!"); os.newLine(); diff --git a/src/de/gurkengewuerz/termbin/Termbin.java b/src/main/java/de/gurkengewuerz/termbin/Termbin.java similarity index 52% rename from src/de/gurkengewuerz/termbin/Termbin.java rename to src/main/java/de/gurkengewuerz/termbin/Termbin.java index 3e3aaf9..a7eb108 100644 --- a/src/de/gurkengewuerz/termbin/Termbin.java +++ b/src/main/java/de/gurkengewuerz/termbin/Termbin.java @@ -5,14 +5,14 @@ import de.gurkengewuerz.termbin.Server.DataHandler; import de.gurkengewuerz.termbin.Server.UploadServer; import de.gurkengewuerz.termbin.Utils.HashUtils; import org.eclipse.jetty.server.Server; -import org.json.JSONObject; import java.io.File; import java.io.IOException; import java.sql.PreparedStatement; import java.sql.SQLException; -import java.util.logging.Level; -import java.util.logging.Logger; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.logging.*; /** * Created by gurkengewuerz.de on 02.07.2017. @@ -21,74 +21,94 @@ public class Termbin { private static Database db; private static Config conf; + private static final Logger accesslog = Logger.getLogger("Accesslog"); - public static void main(String args[]) { - File f = new File("." + File.separator + "settings.json"); - - try { - conf = new Config(f); - } catch (IOException e) { - Logger.getLogger(Termbin.class.getName()).log(Level.SEVERE, null, e); - System.exit(1); + public static void main(String args[]) throws Exception { + String settingsFile = "." + File.separator + "settings.json"; + if (args.length >= 1) { + settingsFile = args[0]; } + File f = new File(settingsFile); + + conf = new Config(f); conf.load(); - try { - db = new Database(conf.getString("database")); - createDatabase(); - } catch (Exception e) { - Logger.getLogger(Termbin.class.getName()).log(Level.SEVERE, null, e); - } + db = new Database(conf.getString("database")); + createDatabase(); - Runnable uploadServerTask = () -> { + FileHandler fh = new FileHandler(conf.getString("accesslog") + ".%u.log", 5242880, 5, true); +// FileHandler fh = new FileHandler(conf.getString("accesslog") + ".log", true); + SimpleFormatter sf = new SimpleFormatter(); + fh.setFormatter(sf); + accesslog.setUseParentHandlers(false); + accesslog.addHandler(fh); + + CountDownLatch lock = new CountDownLatch(3); + + Thread uploadServerThread = new Thread(() -> { try { - JSONObject uploadServerConf = conf.getJSONObject("uploadserver"); - new UploadServer(uploadServerConf.getString("bind"), uploadServerConf.getInt("port")); + UploadServer uploadServer = new UploadServer(conf.getUploadServerConfig().getString("bind"), conf.getUploadServerConfig().getInt("port")); + lock.countDown(); + uploadServer.start(); } catch (IOException e) { Logger.getLogger(Termbin.class.getName()).log(Level.SEVERE, null, e); } - }; - Thread uploadServerThread = new Thread(uploadServerTask); + }); uploadServerThread.start(); - - Runnable dataServerTask = () -> { + Thread dataServerThread = new Thread(() -> { try { - JSONObject dataServerConf = conf.getJSONObject("dataserver"); - Server dataServer = new Server(dataServerConf.getInt("port")); + Server dataServer = new Server(conf.getDataServerConfig().getInt("port")); dataServer.setHandler(new DataHandler()); dataServer.start(); - dataServer.join(); + lock.countDown(); } catch (Exception e) { Logger.getLogger(Termbin.class.getName()).log(Level.SEVERE, null, e); } - }; - Thread dataServerThread = new Thread(dataServerTask); + }); dataServerThread.start(); - - Runnable apiServerTask = () -> { + Thread apiServerThread = new Thread(() -> { try { - JSONObject apiServerConf = conf.getJSONObject("apiserver"); - Server apiServer = new Server(apiServerConf.getInt("port")); + Server apiServer = new Server(conf.getApiServerConfig().getInt("port")); apiServer.setHandler(new APIHandler()); apiServer.start(); - apiServer.join(); + lock.countDown(); } catch (Exception e) { Logger.getLogger(Termbin.class.getName()).log(Level.SEVERE, null, e); } - }; - Thread apiServerThread = new Thread(apiServerTask); + }); apiServerThread.start(); - // TODO: Check if all threads started successfully - // TODO: log to file - // TODO: Arguments (Settings file) - // TODO: print start values (all ports etc.) - // TODO: Config Max lifetime => Check insert time on request - // TODO: Maven + boolean counts = lock.await(4, TimeUnit.SECONDS); + if (counts) { + String cr = System.getProperty("line.separator"); + String stringInfo = cr + + "########################################" + cr + + " Configfile: " + f.getAbsolutePath() + cr + + " Domain: " + conf.getString("domain") + cr + + " Upload Lifetime: " + conf.getInt("uploadlifetime") + "h" + cr + + " Upload Size: " + conf.getInt("maxkb") + "kb" + cr + + " Bans listed: " + conf.getBans().size() + cr + + " Accesslog: " + conf.getString("accesslog") + cr + + " Upload Server: " + conf.getUploadServerConfig().getString("bind") + ":" + conf.getUploadServerConfig().getInt("port") + cr + + " API Server: 0.0.0.0:" + conf.getApiServerConfig().getInt("port") + cr + + " Data Server: 0.0.0.0:" + conf.getDataServerConfig().getInt("port") + cr + + "########################################" + cr; + + Logger.getLogger(Termbin.class.getName()).log(Level.INFO, stringInfo); + + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + for (Handler h : accesslog.getHandlers()) { + h.close(); + } + })); + } else { + Logger.getLogger(Termbin.class.getName()).log(Level.SEVERE, "Servers couldn't started!"); + System.exit(1); + } } public static Database getDatabase() { @@ -100,8 +120,12 @@ public class Termbin { return conf; } + public static Logger getAccesslog() { + return accesslog; + } + public static String upload(String ip, String text, byte[] rawData, FileType fileType) throws SQLException { - String answerID = HashUtils.getSha256(System.currentTimeMillis() + "").substring(0, 8); + String answerID = HashUtils.getSha256(System.currentTimeMillis() + ip).substring(0, 8); PreparedStatement ps = getDatabase().getPreparedStatement("INSERT INTO data (uniqueid, timestamp, fromClient, filetype, text, rawData) VALUES (?, ?, ?, ?, ?, ?);"); ps.setString(1, answerID); ps.setInt(2, (int) (System.currentTimeMillis() / 1000)); @@ -110,9 +134,12 @@ public class Termbin { if (fileType.equals(FileType.TXT)) { ps.setString(5, text); ps.setBytes(6, null); + getAccesslog().log(Level.INFO, ip + " - - upload with text " + " id#" + answerID); + } else { ps.setString(5, null); ps.setBytes(6, rawData); + getAccesslog().log(Level.INFO, ip + "upload with " + rawData.length + " bytes " + " id#" + answerID); } ps.execute(); diff --git a/src/de/gurkengewuerz/termbin/Utils/HashUtils.java b/src/main/java/de/gurkengewuerz/termbin/Utils/HashUtils.java similarity index 100% rename from src/de/gurkengewuerz/termbin/Utils/HashUtils.java rename to src/main/java/de/gurkengewuerz/termbin/Utils/HashUtils.java diff --git a/src/de/gurkengewuerz/termbin/Utils/ImageUtils.java b/src/main/java/de/gurkengewuerz/termbin/Utils/ImageUtils.java similarity index 100% rename from src/de/gurkengewuerz/termbin/Utils/ImageUtils.java rename to src/main/java/de/gurkengewuerz/termbin/Utils/ImageUtils.java diff --git a/src/de/gurkengewuerz/termbin/Utils/SQLInjectionEscaper.java b/src/main/java/de/gurkengewuerz/termbin/Utils/SQLInjectionEscaper.java similarity index 100% rename from src/de/gurkengewuerz/termbin/Utils/SQLInjectionEscaper.java rename to src/main/java/de/gurkengewuerz/termbin/Utils/SQLInjectionEscaper.java