work
This commit is contained in:
parent
2da318ef44
commit
6572a3d317
58
pom.xml
58
pom.xml
@ -7,19 +7,6 @@
|
||||
<groupId>de.gurkengewuerz</groupId>
|
||||
<artifactId>postfix-rest-send</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.simplejavamail</groupId>
|
||||
@ -46,5 +33,50 @@
|
||||
<artifactId>json</artifactId>
|
||||
<version>20170516</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.39</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>2.6</version>
|
||||
<configuration>
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>
|
||||
jar-with-dependencies
|
||||
</descriptorRef>
|
||||
</descriptorRefs>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>${project.groupId}.postfix_rest_send.Main</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>assamble</id>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<phase>package</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
136
src/main/java/de/gurkengewuerz/postfix_rest_send/Config.java
Normal file
136
src/main/java/de/gurkengewuerz/postfix_rest_send/Config.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
@ -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("<img src='cid:wink1'><b>We should meet up!</b><img src='cid:wink2'>");
|
||||
//
|
||||
// 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<String, String> headers = session.getHeaders();
|
||||
String ip = headers.get("remote-addr");
|
||||
Logger.getLogger(Main.class.getName()).log(Level.INFO, session.getMethod().name() + ": " + session.getUri() + " " + ip);
|
||||
Map<String, String> 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 (filter.banned(ip))
|
||||
return getError(Response.Status.FORBIDDEN, "you are temporary banned");
|
||||
|
||||
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) {
|
||||
System.out.println(checkPassword("/var/www/html/tools/functions.inc.php", "md5", "EMailFam.Schuetrumpf@123", "460b7d128333a4be972d4c7bdb0ee142"));
|
||||
if (username == null || password == null) return getError(Response.Status.UNAUTHORIZED);
|
||||
|
||||
|
||||
status = Response.Status.OK;
|
||||
json = new JSONObject("{'token':''}");
|
||||
} else {
|
||||
json = new JSONObject("{'error':'username/password is null'}");
|
||||
boolean usernameValid = EmailAddressValidator.isValid(username, EnumSet.of(EmailAddressCriteria.ALLOW_DOMAIN_LITERALS));
|
||||
if (!usernameValid) {
|
||||
filter.failed(ip);
|
||||
return getError(Response.Status.UNAUTHORIZED, "invalid user");
|
||||
}
|
||||
} else if (session.getUri().startsWith("/authorize/revoke")) {
|
||||
|
||||
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':'" + 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("/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<String> 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'}");
|
||||
}
|
||||
} 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);
|
||||
|
||||
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());
|
||||
}
|
||||
input.close();
|
||||
return output.toString();
|
||||
} catch (Exception err) {
|
||||
err.printStackTrace();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
252
src/main/java/de/gurkengewuerz/postfix_rest_send/MySQL.java
Normal file
252
src/main/java/de/gurkengewuerz/postfix_rest_send/MySQL.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
@ -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<String, Integer> 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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<String> output = new ArrayList<>();
|
||||
ArrayList<String> 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"});
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user