diff --git a/pom.xml b/pom.xml index 630821e..34c8b5b 100644 --- a/pom.xml +++ b/pom.xml @@ -7,19 +7,6 @@ de.gurkengewuerz postfix-rest-send 1.0-SNAPSHOT - - - - org.apache.maven.plugins - maven-compiler-plugin - - 1.8 - 1.8 - - - - - org.simplejavamail @@ -46,5 +33,50 @@ json 20170516 + + mysql + mysql-connector-java + 5.1.39 + + + + + + maven-compiler-plugin + 3.5.1 + + 1.8 + 1.8 + + + + maven-assembly-plugin + 2.6 + + false + ${project.artifactId} + + + jar-with-dependencies + + + + + ${project.groupId}.postfix_rest_send.Main + + + + + + assamble + + single + + package + + + + + \ No newline at end of file diff --git a/src/main/java/de/gurkengewuerz/postfix_rest_send/Config.java b/src/main/java/de/gurkengewuerz/postfix_rest_send/Config.java new file mode 100644 index 0000000..c30bd5e --- /dev/null +++ b/src/main/java/de/gurkengewuerz/postfix_rest_send/Config.java @@ -0,0 +1,136 @@ +package de.gurkengewuerz.postfix_rest_send; + +import org.json.JSONObject; +import org.json.JSONTokener; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.AccessDeniedException; +import java.nio.file.Files; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Created by gurkengewuerz.de on 02.07.2017. + */ +public class Config extends JSONObject { + private File file; + private JSONObject database; + private boolean firstRun = false; + + public Config(File file) throws IOException { + this.file = file; + + if (!file.exists()) { + file.createNewFile(); + firstRun = true; + } + + if (!file.isFile()) { + throw new FileNotFoundException(file.getAbsolutePath() + " not found"); + } + + if (!file.canRead() || !file.canWrite()) { + throw new AccessDeniedException(file.getAbsolutePath() + " is not accessable"); + } + + this.put("debug", true); + this.put("disable_bruteforcefilter", false); + this.put("token_expire", 730); // houres/1M + this.put("http_port", 8081); + this.put("postfixadmin_encryption", "md5crypt"); + this.put("postfixadmin_path", "/var/www/html/postfixadmin/"); + + JSONObject database = new JSONObject(); + database.put("port", 3306); + database.put("host", "127.0.0.1"); + database.put("db", "mail"); + database.put("username", "postfixadmin"); + database.put("password", "abc123"); + this.put("database", database); + } + + public void save() { + try { + FileWriter fw = new FileWriter(file.getAbsolutePath()); + fw.write(this.toString(4)); + fw.close(); + loadRestData(); + } catch (IOException e) { + Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, e); + } + } + + public void load() { + try { + String content = new String(Files.readAllBytes(file.toPath()), "UTF-8"); + if (content.isEmpty()) { + save(); + return; + } + JSONTokener jt = new JSONTokener(content); + if (jt.nextClean() != 123) { + throw jt.syntaxError("A JSONObject text must begin with '{'"); + } else { + while (jt.more()) { + char c = jt.nextClean(); + switch (c) { + case '\u0000': + throw jt.syntaxError("A JSONObject text must end with '}'"); + case '}': + return; + default: + jt.back(); + String key = jt.nextValue().toString(); + c = jt.nextClean(); + if (c != 58) { + throw jt.syntaxError("Expected a ':' after a key"); + } + + this.remove(key); + this.putOnce(key, jt.nextValue()); + switch (jt.nextClean()) { + case ',': + case ';': + if (jt.nextClean() == 125) { + return; + } + + jt.back(); + break; + case '}': + save(); + return; + default: + throw jt.syntaxError("Expected a ',' or '}'"); + } + } + } + } + } catch (IOException e) { + Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, e); + } + } + + public boolean debug() { + return getBoolean("debug"); + } + + private void loadRestData() { + database = getJSONObject("database"); + } + + public JSONObject getDatabaseConfig() { + return database; + } + + public String getDBURL() { + return "jdbc:mysql://" + getDatabaseConfig().getString("host") + ":" + getDatabaseConfig().getInt("port") + "/" + getDatabaseConfig().getString("db"); + } + + public boolean isFirstRun() { + return firstRun; + } +} \ No newline at end of file diff --git a/src/main/java/de/gurkengewuerz/postfix_rest_send/Main.java b/src/main/java/de/gurkengewuerz/postfix_rest_send/Main.java index a2c5c71..e15816d 100644 --- a/src/main/java/de/gurkengewuerz/postfix_rest_send/Main.java +++ b/src/main/java/de/gurkengewuerz/postfix_rest_send/Main.java @@ -1,104 +1,254 @@ package de.gurkengewuerz.postfix_rest_send; +import de.gurkengewuerz.postfix_rest_send.objects.BruteforceFilter; +import de.gurkengewuerz.postfix_rest_send.objects.ReturnHolder; +import de.gurkengewuerz.postfix_rest_send.utils.BashUtils; +import de.gurkengewuerz.postfix_rest_send.utils.HtmlToPlainText; +import de.gurkengewuerz.postfix_rest_send.utils.RandomUtils; import fi.iki.elonen.NanoHTTPD; +import org.hazlewood.connor.bottema.emailaddress.EmailAddressCriteria; +import org.hazlewood.connor.bottema.emailaddress.EmailAddressValidator; import org.json.JSONObject; +import org.simplejavamail.email.Email; +import org.simplejavamail.mailer.Mailer; +import org.simplejavamail.mailer.config.ServerConfig; -import java.io.BufferedReader; +import javax.mail.Message; +import java.io.File; import java.io.IOException; -import java.io.InputStreamReader; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.EnumSet; import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; /** * Created by gurkengewuerz.de on 12.07.2017. */ public class Main extends NanoHTTPD { + private static MySQL db; + private static Config conf; + private static Mailer mailer; + private static BruteforceFilter filter; + + /* + TODO: + Main umbennen + Configurierbare Domains/IPs + Post JSON Support + */ + public Main() throws IOException { - super(8081); + super(conf.getInt("http_port")); + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "Started Server :" + getListeningPort()); start(NanoHTTPD.SOCKET_READ_TIMEOUT, false); } -// http://www.simplejavamail.org/#/debugging - - public static void main(String[] args) { -// Mailer m = new Mailer(new ServerConfig("localhost", 25)); -// m.setDebug(true); -// -// Email email = new Email(); -// email.setFromAddress("admin@gurkengewuerz.de", "admin@gurkengewuerz.de"); -// email.setReplyToAddress("support@gurkengewuerz.de", "support@gurkengewuerz.de"); -// email.addRecipient("developer@the-town.net", "developer@the-town.net", Message.RecipientType.TO); -// email.setSubject("Email Test"); -// email.setText("Dies ist ein Email Test von Java.\nHoffentlich bald mit Rest API"); -// email.setTextHTML("We should meet up!"); -// -// m.sendMail(email); - -// HtmlToPlainText formatter = new HtmlToPlainText(); -// formatter.getPlainText() - try { - System.out.println("Started"); - new Main(); - } catch (IOException e) { - e.printStackTrace(); + public static void main(String[] args) throws IOException, SQLException { + String settingsFile = "." + File.separator + "settings.json"; + if (args.length >= 1) { + settingsFile = args[0]; } + File f = new File(settingsFile); + + conf = new Config(f); + conf.load(); + + if (conf.debug()) + Logger.getLogger(Main.class.getName()).log(Level.INFO, "Using Settingsfile " + f.getAbsolutePath()); + + if (conf.isFirstRun()) System.exit(0); + + db = new MySQL(MySQL.Type.MYSQL, conf.getDBURL(), conf.getDatabaseConfig().getString("username"), conf.getDatabaseConfig().getString("password")); + db.executeUpdate("CREATE TABLE IF NOT EXISTS token (" + + " tokenid int(11) NOT NULL AUTO_INCREMENT," + + " username VARCHAR(255) NOT NULL," + + " token VARCHAR(255) NOT NULL," + + " created INT NOT NULL," + + " expire INT NOT NULL," + + " PRIMARY KEY (tokenid), " + + " UNIQUE (token)" + + " ); "); + db.executeUpdate("CREATE TABLE IF NOT EXISTS token_bruteforce (" + + " id int(11) NOT NULL AUTO_INCREMENT," + + " occurred INT NOT NULL," + + " ip VARCHAR(255) NOT NULL," + + " PRIMARY KEY (id)" + + " ); "); + mailer = new Mailer(new ServerConfig("localhost", 25)); + mailer.setDebug(conf.debug()); + + filter = new BruteforceFilter(6); + + new Main(); } @Override public Response serve(IHTTPSession session) { + Map headers = session.getHeaders(); + String ip = headers.get("remote-addr"); + Logger.getLogger(Main.class.getName()).log(Level.INFO, session.getMethod().name() + ": " + session.getUri() + " " + ip); Map parms = session.getParms(); - JSONObject json = new JSONObject("{'error':'not found'}"); - Response.Status status = Response.Status.NOT_FOUND; + Response.Status status = Response.Status.NOT_IMPLEMENTED; - if (session.getUri().startsWith("/authorize")) { - if (session.getUri().startsWith("/authorize/add")) { - String username = parms.get("username"); - String password = parms.get("password"); + if (filter.banned(ip)) + return getError(Response.Status.FORBIDDEN, "you are temporary banned"); - if (username != null && password != null) { - System.out.println(checkPassword("/var/www/html/tools/functions.inc.php", "md5", "EMailFam.Schuetrumpf@123", "460b7d128333a4be972d4c7bdb0ee142")); + try { + if (session.getMethod().equals(Method.POST)) + session.parseBody(parms); + } catch (IOException | ResponseException e) { + return getError(Response.Status.INTERNAL_ERROR); + } + if (db == null) return getError(Response.Status.INTERNAL_ERROR, "Database Error"); + try { + if (session.getUri().startsWith("/authorize")) { + if (session.getUri().startsWith("/authorize/add")) { + String username = parms.get("username"); + String password = parms.get("password"); + + if (username == null || password == null) return getError(Response.Status.UNAUTHORIZED); + + boolean usernameValid = EmailAddressValidator.isValid(username, EnumSet.of(EmailAddressCriteria.ALLOW_DOMAIN_LITERALS)); + if (!usernameValid) { + filter.failed(ip); + return getError(Response.Status.UNAUTHORIZED, "invalid user"); + } + + ResultSet rs = db.executeQuery("SELECT * FROM mailbox WHERE username = ? AND active = 1;", username); + int rowcount = 0; + while (rs.next()) { + rowcount++; + } + rs.beforeFirst(); + rs.next(); + if (rowcount <= 0) { + filter.failed(ip); + return getError(Response.Status.UNAUTHORIZED); + } + + boolean correct = checkPassword(conf.getString("postfixadmin_encryption"), password, rs.getString("password")); + if (!correct) { + filter.failed(ip); + return getError(Response.Status.UNAUTHORIZED); + } + String token = RandomUtils.rndToken(username); + long expires = (System.currentTimeMillis() / 1000) + (conf.getInt("token_expire") * 60 * 60); + db.executeUpdate("INSERT INTO token (username, token, created, expire) VALUES (?,?,?,?);", username, token, (System.currentTimeMillis() / 1000), expires); status = Response.Status.OK; - json = new JSONObject("{'token':''}"); - } else { - json = new JSONObject("{'error':'username/password is null'}"); + json = new JSONObject("{'token':'" + token + "', 'expires': " + expires + "}"); + } else if (session.getUri().startsWith("/authorize/revoke")) { + String token = parms.get("token"); + if (token == null) return getError(Response.Status.BAD_REQUEST); + db.executeUpdate("DELETE FROM token WHERE token = ?;", token); + status = Response.Status.OK; + json = new JSONObject("{'status':'ok'}"); } - } else if (session.getUri().startsWith("/authorize/revoke")) { + } else if (session.getUri().startsWith("/validate/address")) { + String mail = parms.get("mail"); + if (mail == null) return getError(Response.Status.BAD_REQUEST); + boolean valid = EmailAddressValidator.isValid(mail, EnumSet.of(EmailAddressCriteria.ALLOW_DOMAIN_LITERALS)); + status = Response.Status.OK; + json = new JSONObject("{'valid':" + valid + "}"); + } else if (session.getUri().startsWith("/send")) { + String token = parms.get("token"); + String to = parms.get("to"); + String subject = parms.get("to"); + String text = parms.get("text"); + String html = parms.get("html"); + if (token == null) return getError(Response.Status.UNAUTHORIZED); + + ResultSet rs = db.executeQuery("SELECT * FROM token WHERE token = ?;", token); + int rowcount = 0; + while (rs.next()) { + rowcount++; + } + rs.beforeFirst(); + rs.next(); + if (rowcount <= 0){ + filter.banned(ip); + return getError(Response.Status.UNAUTHORIZED); + } + + if (rs.getLong("expire") <= System.currentTimeMillis() / 1000) + return getError(Response.Status.UNAUTHORIZED, "token expired"); + + String username = rs.getString("username"); + + if (to == null || subject == null || (text == null && html == null)) + return getError(Response.Status.BAD_REQUEST); + + ArrayList toList = new ArrayList<>(); + + if (to.contains(";")) { + for (String mailTo : to.split(";")) { + if (!EmailAddressValidator.isValid(mailTo, EnumSet.of(EmailAddressCriteria.ALLOW_DOMAIN_LITERALS))) + return getError(Response.Status.BAD_REQUEST, "invalid recipient"); + toList.add(mailTo); + } + } else { + if (!EmailAddressValidator.isValid(to, EnumSet.of(EmailAddressCriteria.ALLOW_DOMAIN_LITERALS))) + return getError(Response.Status.BAD_REQUEST, "invalid recipient"); + toList.add(to); + } + + Email email = new Email(); + email.setFromAddress(username, username); + toList.forEach(s -> email.addRecipient(s, s, Message.RecipientType.TO)); + email.setSubject(subject); + if (text != null) email.setText(text); + if (html != null) email.setTextHTML(html); + if (text == null && html != null) { + HtmlToPlainText formatter = new HtmlToPlainText(); + email.setText(formatter.getPlainText(html)); + } + + mailer.sendMail(email); + status = Response.Status.OK; + json = new JSONObject("{'status':'send'}"); } - } else if (session.getUri().startsWith("/validate/address")) { - - } else if (session.getUri().startsWith("/send")) { - + } catch (SQLException e) { + Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e); + return getError(Response.Status.INTERNAL_ERROR); } return newFixedLengthResponse(status, "application/json", json.toString()); } - public boolean checkPassword(String path, String encryption, String plain, String dbPW) { - String crypted = execPHP("-r '$CONF = array(); $CONF[\"encrypt\"] = \"" + encryption + "\"; include \"" + path + "\"; echo(pacrypt(\"" + plain + "\", \"" + dbPW + "\")).\"\\n\";'"); - System.out.println(crypted); - return crypted.equals(dbPW); + public boolean checkPassword(String encryption, String plain, String dbPW) { + ReturnHolder crypted = BashUtils.run(conf.debug(), "php", "-r", "$CONF = array(); $CONF[\"encrypt\"] = \"" + encryption + "\"; include \"" + conf.getString("postfixadmin_path") + "/functions.inc.php" + "\"; echo(pacrypt(\"" + plain + "\", \"" + dbPW + "\")).\"\\n\";"); + return String.join("", crypted.output).equals(dbPW); } - public String execPHP(String args) { - try { - System.out.println(args); - String line; - StringBuilder output = new StringBuilder(); - Process p = Runtime.getRuntime().exec("php " + args); - BufferedReader input = - new BufferedReader - (new InputStreamReader(p.getInputStream())); - while ((line = input.readLine()) != null) { - output.append(line); - System.out.println(line); - } - input.close(); - return output.toString(); - } catch (Exception err) { - err.printStackTrace(); + + public Response getError(Response.Status status, String error) { + JSONObject json = new JSONObject("{'error':'unknown error'}"); + json.put("error", error); + return newFixedLengthResponse(status, "application/json", json.toString()); + } + + public Response getError(Response.Status status) { + switch (status) { + case INTERNAL_ERROR: + return getError(status, "internal server rror"); + case BAD_REQUEST: + return getError(status, "bad request"); + case UNAUTHORIZED: + return getError(status, "unauthorized"); } - return ""; + return getError(status, "unknown error"); + } + + public static MySQL getDatabase() { + return db; + } + + public static Config getConfig() { + return conf; } } diff --git a/src/main/java/de/gurkengewuerz/postfix_rest_send/MySQL.java b/src/main/java/de/gurkengewuerz/postfix_rest_send/MySQL.java new file mode 100644 index 0000000..fd2b896 --- /dev/null +++ b/src/main/java/de/gurkengewuerz/postfix_rest_send/MySQL.java @@ -0,0 +1,252 @@ +package de.gurkengewuerz.postfix_rest_send; + +import java.sql.*; +import java.util.logging.Logger; + +/** + * Simple wrapper for database abstraction. + * + * @author Nijiko + * @url https://raw.githubusercontent.com/iConomy/SimpleShop/master/com/nijiko/simpleshop/database/Wrapper.java + */ +public class MySQL { + private static final Logger log = Logger.getLogger("MySQL"); + + /** + * Database Types + */ + public enum Type { + SQLITE, + MYSQL + } + + ; + + /** + * Fetch type from string. + * + * @param type + * @return + */ + public static Type getType(String type) { + for (Type dbType : Type.values()) { + if (dbType.toString().equalsIgnoreCase(type)) { + return dbType; + } + } + + return Type.SQLITE; + } + + /* + * Database Settings + */ + public Type database = null; + + /* + * Database Connection Settings + */ + private String db; + private String user; + private String pass; + + /* + * Database Memory + */ + private Connection connection; + private Statement Stmt; + private PreparedStatement Statement; + private ResultSet ResultSet; + + /** + * Create a new instance of the wrapper for usage. + * + * @param database + * @param db + * @param user + * @param pass + */ + public MySQL(Type database, String db, String user, String pass) { + this.database = database; + this.db = db; + this.user = user; + this.pass = pass; + } + + /** + * Initialize the wrapper + * + * @return Connection + * @throws ClassNotFoundException + * @throws SQLException + */ + public void initialize() { + try { + this.connection(); + } catch (SQLException ex) { + log.severe("[" + this.database.toString() + " Database] Failed to connect: " + ex); + } catch (ClassNotFoundException e) { + log.severe("[" + this.database.toString() + " Database] Connector not found: " + e); + } + } + + /** + * Connect to the database, return connection. + * + * @return Connection + * @throws ClassNotFoundException + * @throws SQLException + */ + private Connection connection() throws ClassNotFoundException, SQLException { + if (this.database.equals(database.SQLITE)) { + Class.forName("org.sqlite.JDBC"); + this.connection = DriverManager.getConnection(this.db); + } else { + Class.forName("com.mysql.jdbc.Driver"); + this.connection = DriverManager.getConnection(this.db, this.user, this.pass); + } + + return this.connection; + } + + /** + * Check to see if table exists. + * + * @param table + * @return boolean + */ + public boolean checkTable(String table) { + initialize(); + + try { + DatabaseMetaData dbm = this.connection.getMetaData(); + this.ResultSet = dbm.getTables(null, null, table, null); + return this.ResultSet.next(); + } catch (SQLException ex) { + log.severe("[" + this.database.toString() + " Database] Table check failed: " + ex); + } finally { + this.close(); + } + + return false; + } + + /** + * Execute pure SQL String. + * + * @param query + * @return + */ + public ResultSet executeQuery(String query) { + initialize(); + + try { + this.Statement = this.connection.prepareStatement(query); + + return this.Statement.executeQuery(); + } catch (SQLException ex) { + log.severe("[" + this.database.toString() + " Database] Could not execute query: " + ex); + } + + return null; + } + + /** + * Execute Query with variables. + * + * @param query + * @param variables + * @return + */ + public ResultSet executeQuery(String query, Object... variables) { + initialize(); + + try { + this.Statement = this.connection.prepareStatement(query); + int i = 1; + for (Object obj : variables) { + this.Statement.setObject(i, obj); + i++; + } + return this.Statement.executeQuery(); + } catch (SQLException ex) { + log.severe("[" + this.database.toString() + " Database] Could not execute query: " + ex); + } + + return null; + } + + /** + * Execute pure SQL String. + * + * @param query + * @return + */ + public int executeUpdate(String query) { + initialize(); + + try { + this.Stmt = this.connection.createStatement(); + return this.Stmt.executeUpdate(query); + } catch (SQLException ex) { + log.severe("[" + this.database.toString() + " Database] Could not execute query: " + ex); + } + + return 0; + } + + /** + * Execute Query with variables. + * + * @param query + * @param variables + * @return + */ + public int executeUpdate(String query, Object... variables) { + initialize(); + + try { + this.Statement = this.connection.prepareStatement(query); + int i = 1; + + for (Object obj : variables) { + this.Statement.setObject(i, obj); + i++; + } + + return this.Statement.executeUpdate(); + } catch (SQLException ex) { + log.severe("[" + this.database.toString() + " Database] Could not execute query: " + ex); + } + + return 0; + } + + public void close() { + try { + if (this.Statement != null) { + this.Statement.close(); + } + + if (this.ResultSet != null) { + this.ResultSet.close(); + } + + if (this.connection != null) { + this.connection.close(); + } + + } catch (SQLException ex) { + log.severe("[" + this.database.toString() + " Database] Failed to close connection: " + ex); + + // Close anyway. + this.connection = null; + this.Statement = null; + this.ResultSet = null; + } + } + + protected void finalize() { + close(); + } +} diff --git a/src/main/java/de/gurkengewuerz/postfix_rest_send/objects/BruteforceFilter.java b/src/main/java/de/gurkengewuerz/postfix_rest_send/objects/BruteforceFilter.java new file mode 100644 index 0000000..d7a28a2 --- /dev/null +++ b/src/main/java/de/gurkengewuerz/postfix_rest_send/objects/BruteforceFilter.java @@ -0,0 +1,71 @@ +package de.gurkengewuerz.postfix_rest_send.objects; + +import de.gurkengewuerz.postfix_rest_send.Main; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Timer; +import java.util.TimerTask; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Created by gurkengewuerz.de on 13.07.2017. + */ +public class BruteforceFilter { + private final HashMap attempts = new HashMap<>(); + private int maxAttemps = 3; + + public BruteforceFilter(int maxAttemps) { + this.maxAttemps = maxAttemps; + Timer t = new Timer(); + t.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + try { + refresh(); + } catch (SQLException e) { + Logger.getLogger(BruteforceFilter.class.getName()).log(Level.SEVERE, null, e); + } + } + }, 0, 2 * 60 * 1000); + } + + public BruteforceFilter() { + this(3); + } + + private void refresh() throws SQLException { + ResultSet rs = Main.getDatabase().executeQuery("SELECT ip, COUNT(*) count FROM token_bruteforce WHERE occurred > ? GROUP BY ip ORDER BY COUNT(*) DESC;", (System.currentTimeMillis() / 1000) - (24 * 60 * 60)); + synchronized (attempts) { + attempts.clear(); + while (rs.next()) { + attempts.put(rs.getString("ip"), rs.getInt("count")); + } + } + if (Main.getConfig().debug()) + Logger.getLogger(getClass().getName()).log(Level.INFO, "refreshed bans (" + attempts.size() + ")"); + } + + public void failed(String ip) { + if (Main.getConfig().getBoolean("disable_bruteforcefilter")) return; + Main.getDatabase().executeUpdate("INSERT INTO token_bruteforce (ip, occurred) VALUES (?, ?);", ip, System.currentTimeMillis() / 1000); + synchronized (attempts) { + if (attempts.containsKey(ip)) { + attempts.replace(ip, attempts.get(ip) + 1); + } else { + attempts.put(ip, 1); + } + if (Main.getConfig().debug()) + Logger.getLogger(getClass().getName()).log(Level.INFO, "banned " + ip + " attemp " + attempts.get(ip)); + } + } + + public boolean banned(String ip) { + if (Main.getConfig().getBoolean("disable_bruteforcefilter")) return false; + synchronized (attempts) { + return attempts.containsKey(ip) && attempts.get(ip) >= maxAttemps; + } + } +} diff --git a/src/main/java/de/gurkengewuerz/postfix_rest_send/objects/ReturnHolder.java b/src/main/java/de/gurkengewuerz/postfix_rest_send/objects/ReturnHolder.java new file mode 100644 index 0000000..63c59dc --- /dev/null +++ b/src/main/java/de/gurkengewuerz/postfix_rest_send/objects/ReturnHolder.java @@ -0,0 +1,11 @@ +package de.gurkengewuerz.postfix_rest_send.objects; + +public class ReturnHolder { + public final String[] output; + public final String[] error; + + public ReturnHolder(String[] output, String[] error) { + this.output = output; + this.error = error; + } +} diff --git a/src/main/java/de/gurkengewuerz/postfix_rest_send/utils/BashUtils.java b/src/main/java/de/gurkengewuerz/postfix_rest_send/utils/BashUtils.java new file mode 100644 index 0000000..aaf2626 --- /dev/null +++ b/src/main/java/de/gurkengewuerz/postfix_rest_send/utils/BashUtils.java @@ -0,0 +1,71 @@ +package de.gurkengewuerz.postfix_rest_send.utils; + +import de.gurkengewuerz.postfix_rest_send.objects.ReturnHolder; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Created by gurkengewuerz.de on 13.07.2017. + */ +public class BashUtils { + public static ReturnHolder run(boolean directPrint, String... command) { + try { + ProcessBuilder pb = new ProcessBuilder(command); + Process p = pb.start(); + return getOutput(directPrint, p); + } catch (IOException ex) { + Logger.getLogger(BashUtils.class.getName()).log(Level.SEVERE, "error executing command", ex); + } + return new ReturnHolder(new String[0], new String[]{"exception"}); + } + + private static ReturnHolder getOutput(boolean print, Process P) { + try { + BufferedReader stdInput = new BufferedReader(new InputStreamReader(P.getInputStream())); + BufferedReader stdError = new BufferedReader(new InputStreamReader(P.getErrorStream())); + ArrayList output = new ArrayList<>(); + ArrayList error = new ArrayList<>(); + Thread t = null; + if (print) { + t = new Thread(() -> { + String s; + try { + while ((s = stdError.readLine()) != null) { + error.add(s); + System.out.println("ERR: " + s); + } + } catch (IOException ex) { + Logger.getLogger(BashUtils.class.getName()).log(Level.SEVERE, null, ex); + } + }); + } + String s; + while ((s = stdInput.readLine()) != null) { + output.add(s); + if (print) { + System.out.println("OUT: " + s); + } + } + if (t != null) { + if (t.isAlive()) { + t.stop(); + } + } + while ((s = stdError.readLine()) != null) { + error.add(s); + if (print) { + System.out.println("ERR: " + s); + } + } + return new ReturnHolder(output.toArray(new String[output.size()]), error.toArray(new String[error.size()])); + } catch (IOException ex) { + Logger.getLogger(BashUtils.class.getName()).log(Level.SEVERE, null, ex); + } + return new ReturnHolder(new String[0], new String[]{"exception"}); + } +} diff --git a/src/main/java/de/gurkengewuerz/postfix_rest_send/utils/RandomUtils.java b/src/main/java/de/gurkengewuerz/postfix_rest_send/utils/RandomUtils.java new file mode 100644 index 0000000..51c6db5 --- /dev/null +++ b/src/main/java/de/gurkengewuerz/postfix_rest_send/utils/RandomUtils.java @@ -0,0 +1,21 @@ +package de.gurkengewuerz.postfix_rest_send.utils; + +import org.apache.commons.codec.digest.DigestUtils; + +import java.util.UUID; + +/** + * Created by gurkengewuerz.de on 13.07.2017. + */ +public class RandomUtils { + public static String rndToken() { + return rndToken(""); + } + + public static String rndToken(String extraSalt) { + String uuidFront = UUID.randomUUID().toString(); + String uuidBack = UUID.randomUUID().toString(); + String salted = uuidFront + System.currentTimeMillis() + uuidBack + extraSalt; + return DigestUtils.sha256Hex(salted); + } +}