diff --git a/doc/data structure.dia b/doc/data structure.dia
new file mode 100644
index 0000000..bff630a
--- /dev/null
+++ b/doc/data structure.dia
@@ -0,0 +1,1519 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ #A4#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #Lists#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #Name#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #Email#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #Users#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #Email#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #HashedPassword#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #Salt#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #ListMembers#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #ListEmail#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #UserEmail#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #Name#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #State#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #imap_host#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #imap_port#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #imap_user#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #imap_pass#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #smtp_host#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #smtp_port#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #smtp_user#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #smtp_pass#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #Posts#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #ListEmail#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #From#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #Id#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #Parent#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #Subject#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #Date#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #Content#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pom.xml b/pom.xml
index 659ab99..cc2ad6f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -39,10 +39,16 @@
10.0.9
+
+ org.eclipse.jetty
+ jetty-util
+ 10.0.9
+
+
de.srsoftware
- tools
- 1.1.18
+ tools.translations
+ 1.1.3
@@ -70,6 +76,18 @@
1.1.1
+
+ org.xerial
+ sqlite-jdbc
+ 3.36.0.3
+
+
+
+ org.antlr
+ stringtemplate
+ 4.0.2
+
+
\ No newline at end of file
diff --git a/src/main/java/de/srsoftware/widerhall/Application.java b/src/main/java/de/srsoftware/widerhall/Application.java
index e531bcf..a65c605 100644
--- a/src/main/java/de/srsoftware/widerhall/Application.java
+++ b/src/main/java/de/srsoftware/widerhall/Application.java
@@ -3,23 +3,16 @@ package de.srsoftware.widerhall;
import de.srsoftware.widerhall.mail.Forwarder;
import de.srsoftware.widerhall.mail.ImapClient;
import de.srsoftware.widerhall.mail.MessageHandler;
-import de.srsoftware.widerhall.web.Index;
-import de.srsoftware.widerhall.web.Login;
+import de.srsoftware.widerhall.web.Static;
import de.srsoftware.widerhall.web.Rest;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.json.simple.JSONObject;
-import org.json.simple.parser.JSONParser;
-import org.json.simple.parser.ParseException;
import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.Map;
-import static de.srsoftware.widerhall.Constants.*;
public class Application {
@@ -33,11 +26,12 @@ public class Application {
var server = new Server();
var connector = new ServerConnector(server);
connector.setPort(config.serverPort());
+
+ SessionHandler sh = new SessionHandler();
server.setConnectors(new Connector[]{connector});
- ServletContextHandler context = new ServletContextHandler(server, "/");
+ ServletContextHandler context = new ServletContextHandler(server, "/",sh,null,null,null);
context.addServlet(Rest.class,"/api");
- context.addServlet(Login.class,"/login");
- context.addServlet(Index.class,"/");
+ context.addServlet(Static.class,"/static/*");
server.start();
}
diff --git a/src/main/java/de/srsoftware/widerhall/Configuration.java b/src/main/java/de/srsoftware/widerhall/Configuration.java
index 25a19da..6da7154 100644
--- a/src/main/java/de/srsoftware/widerhall/Configuration.java
+++ b/src/main/java/de/srsoftware/widerhall/Configuration.java
@@ -36,6 +36,7 @@ public class Configuration {
private void setDefaults() throws MalformedURLException {
if (data == null) data = new JSONObject();
+ baseDir();
serverPort();
tokenUrl();
loginUrl();
@@ -70,12 +71,22 @@ public class Configuration {
}
public String clientId() {
- if (!data.containsKey(Constants.CLIENT_ID)) data.put(CLIENT_ID,"widerhall");
+ if (!data.containsKey(CLIENT_ID)) data.put(CLIENT_ID,"widerhall");
return (String) data.get(CLIENT_ID);
}
public Object clientSecret() {
- if (!data.containsKey(Constants.CLIENT_SECRET)) data.put(CLIENT_SECRET,"changeme");
+ if (!data.containsKey(CLIENT_SECRET)) data.put(CLIENT_SECRET,"changeme");
return (String) data.get(CLIENT_SECRET);
}
+
+ public String dbLocation() {
+ if (!data.containsKey(DB_FILE)) data.put(DB_FILE,System.getProperty("user.home")+"/.config/widerhall/db.sqlite3");
+ return (String) data.get(DB_FILE);
+ }
+
+ public String baseDir() {
+ if (!data.containsKey(Constants.BASE_DIR)) data.put(BASE_DIR,System.getProperty("user.dir")+"/static");
+ return (String) data.get(BASE_DIR);
+ }
}
diff --git a/src/main/java/de/srsoftware/widerhall/Constants.java b/src/main/java/de/srsoftware/widerhall/Constants.java
index 504771a..520c846 100644
--- a/src/main/java/de/srsoftware/widerhall/Constants.java
+++ b/src/main/java/de/srsoftware/widerhall/Constants.java
@@ -13,4 +13,6 @@ public class Constants {
public static final String BASE_URL = "base_url";
public static final String CLIENT_ID = "client_id";
public static final String CLIENT_SECRET = "client_secret";
+ public static final String DB_FILE = "db_file";
+ public static final String BASE_DIR = "base_dir";
}
diff --git a/src/main/java/de/srsoftware/widerhall/Util.java b/src/main/java/de/srsoftware/widerhall/Util.java
new file mode 100644
index 0000000..94fe18a
--- /dev/null
+++ b/src/main/java/de/srsoftware/widerhall/Util.java
@@ -0,0 +1,65 @@
+package de.srsoftware.widerhall;
+
+import de.srsoftware.examples.translations.App;
+import de.srsoftware.tools.translations.Translation;
+
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+public class Util {
+
+ private static final MessageDigest SHA256 = getSha256();
+ private static final String EMAIL_PATTERN = "^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^-]+(?:\\.[a-zA-Z0-9_!#$%&'*+/=?`{|}~^-]+)*@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*$";
+
+ public static String urlEncode(Map data) {
+ String params = data.entrySet()
+ .stream()
+ .map(entry -> encode(entry.getKey()) + "=" + encode(entry.getValue()))
+ .collect(Collectors.joining("&"));
+ return params;
+ }
+
+ private static String encode(Object value) {
+ return URLEncoder.encode(value.toString(), StandardCharsets.UTF_8);
+ }
+
+
+ public static MessageDigest getSha256() {
+ try {
+ return MessageDigest.getInstance("SHA-256");
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public static String sha256(String s) {
+ byte[] bytes = SHA256.digest(s.getBytes(StandardCharsets.UTF_8));
+ return hex(bytes);
+ }
+
+ private static String hex(byte[] bytes) {
+ StringBuffer buf = new StringBuffer(bytes.length*2);
+ for (var byt : bytes) buf.append(hex(byt));
+ return buf.toString();
+ }
+
+ private static String hex(byte b){
+ return (b<16 ? "0" : "") + Integer.toHexString(b);
+ }
+
+ public static String t(String tx, Object ... fills){
+ return Translation.get(Application.class,tx,fills);
+ }
+
+ public static boolean isEmail(String email) {
+ return email.matches(EMAIL_PATTERN);
+ }
+}
diff --git a/src/main/java/de/srsoftware/widerhall/data/Database.java b/src/main/java/de/srsoftware/widerhall/data/Database.java
new file mode 100644
index 0000000..7ed26e3
--- /dev/null
+++ b/src/main/java/de/srsoftware/widerhall/data/Database.java
@@ -0,0 +1,167 @@
+package de.srsoftware.widerhall.data;
+
+import de.srsoftware.widerhall.Configuration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.*;
+
+import static de.srsoftware.widerhall.Util.t;
+
+public class Database {
+ public static final String EMAIL = "email";
+ public static final String NAME = "name";
+ public static final String HASHED_PASS = "hashedPassword";
+ public static final String SALT = "salt";
+
+ private static final Logger LOG = LoggerFactory.getLogger(Database.class);
+ private static final String VARCHAR = "VARCHAR(255)";
+ private static Database singleton = null;
+ private static Connection conn;
+
+ public Request insertInto(String tbName) {
+ return query("INSERT INTO "+tbName);
+ }
+
+ public class Request{
+
+ private final String sql;
+ private HashMap> where = new HashMap<>();
+ private HashMap values = new HashMap<>();
+
+ public Request(String sql) {
+ this.sql = sql;
+ }
+
+ public Request where(String key, Object ... values) {
+ for (var val : values) where(key,val);
+ return this;
+ }
+
+ public Request where(String key, Object value) {
+ var list = where.get(key);
+ if (list == null) where.put(key,list = new ArrayList