Stephan Richter
3 years ago
17 changed files with 2074 additions and 207 deletions
@ -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<String, Object> 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); |
||||||
|
} |
||||||
|
} |
@ -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<String,List<Object>> where = new HashMap<>(); |
||||||
|
private HashMap<String,Object> 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<Object>()); |
||||||
|
list.add(value); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public Request values(Map<String,Object> newValues) { |
||||||
|
values.putAll(newValues); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public Request values(String key, Object value) { |
||||||
|
values.put(key,value); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public void run() throws SQLException { |
||||||
|
var sb = new StringBuilder(sql); |
||||||
|
var args = new ArrayList<Object>(); |
||||||
|
if (!values.isEmpty()){ |
||||||
|
var keys = new ArrayList<String>(); |
||||||
|
for (var entry : values.entrySet()) { |
||||||
|
keys.add(entry.getKey()); |
||||||
|
args.add(entry.getValue()); |
||||||
|
} |
||||||
|
sb.append("("+String.join(", ",keys)+")"); |
||||||
|
sb.append(" VALUES "); |
||||||
|
var arr = new String[args.size()]; |
||||||
|
Arrays.fill(arr,"?"); |
||||||
|
var marks = String.join(", ",arr); |
||||||
|
sb.append("(").append(marks).append(")"); |
||||||
|
} |
||||||
|
var sql = sb.toString(); |
||||||
|
LOG.debug(sql); |
||||||
|
try { |
||||||
|
var stmt = conn.prepareStatement(sql); |
||||||
|
if (!args.isEmpty()) { |
||||||
|
for (int i = 0; i < args.size(); i++) stmt.setObject(i+1, args.get(i)); |
||||||
|
} |
||||||
|
stmt.execute(); |
||||||
|
} catch (SQLException sqle) { |
||||||
|
throw new SQLException(t("Query '{}' failed:",sql),sqle); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public ResultSet exec() throws SQLException { |
||||||
|
var sb = new StringBuilder(sql); |
||||||
|
var args = new ArrayList<Object>(); |
||||||
|
if (!where.isEmpty()){ |
||||||
|
var clauses = new ArrayList<String>(); |
||||||
|
sb.append(" WHERE "); |
||||||
|
|
||||||
|
for (var entry : where.entrySet()){ |
||||||
|
var arr = new String[entry.getValue().size()]; |
||||||
|
Arrays.fill(arr,"?"); |
||||||
|
var marks = String.join(", ",arr); |
||||||
|
clauses.add("("+entry.getKey()+" IN ("+marks+"))"); |
||||||
|
args.addAll(entry.getValue()); |
||||||
|
} |
||||||
|
sb.append(String.join(" AND ",clauses)); |
||||||
|
|
||||||
|
} |
||||||
|
var sql = sb.toString(); |
||||||
|
LOG.debug(sql); |
||||||
|
try { |
||||||
|
var stmt = conn.prepareStatement(sql); |
||||||
|
if (!args.isEmpty()) { |
||||||
|
for (int i = 0; i < args.size(); i++) stmt.setObject(i+1, args.get(i)); |
||||||
|
} |
||||||
|
return stmt.executeQuery(); |
||||||
|
} catch (SQLException sqle) { |
||||||
|
throw new SQLException(t("Query '{}' failed:",sql),sqle); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public Database(Connection connection) { |
||||||
|
this.conn = connection; |
||||||
|
} |
||||||
|
|
||||||
|
public static Database open() { |
||||||
|
if (singleton == null){ |
||||||
|
Configuration config = Configuration.instance(); |
||||||
|
String dbFile = config.dbLocation(); |
||||||
|
String url = "jdbc:sqlite:"+dbFile; |
||||||
|
LOG.debug("Opening {}",url); |
||||||
|
new File(dbFile).getParentFile().mkdirs(); |
||||||
|
try { |
||||||
|
singleton = new Database(DriverManager.getConnection(url)).assertTables(); |
||||||
|
} catch (SQLException sqle) { |
||||||
|
sqle.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
return singleton; |
||||||
|
} |
||||||
|
|
||||||
|
private Database assertTables() throws SQLException { |
||||||
|
if (!tableExists("Users")) createUsersTable(); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
private void createUsersTable() throws SQLException { |
||||||
|
query("CREATE TABLE Users ("+EMAIL+" "+ VARCHAR +", "+SALT+" "+VARCHAR+", "+HASHED_PASS+" "+VARCHAR+", "+NAME+" "+VARCHAR+");").run(); |
||||||
|
} |
||||||
|
|
||||||
|
private boolean tableExists(String tbName) throws SQLException { |
||||||
|
try { |
||||||
|
ResultSet rs = query("SELECT EXISTS (SELECT name FROM sqlite_schema WHERE type='table' AND name='" + tbName + "')").exec(); |
||||||
|
int val = 0; |
||||||
|
if (rs.next()) val = rs.getInt(1); |
||||||
|
rs.close(); |
||||||
|
return val > 0; |
||||||
|
} catch (SQLException e) { |
||||||
|
throw new SQLException(t("Was not able to check existence of table {}!",tbName),e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public Request query(String sql) { |
||||||
|
return new Request(sql); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,80 @@ |
|||||||
|
package de.srsoftware.widerhall.data; |
||||||
|
|
||||||
|
import de.srsoftware.widerhall.Util; |
||||||
|
|
||||||
|
import java.security.InvalidKeyException; |
||||||
|
import java.sql.ResultSet; |
||||||
|
import java.sql.SQLException; |
||||||
|
import java.time.LocalDate; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import static de.srsoftware.widerhall.data.Database.*; |
||||||
|
|
||||||
|
public class User { |
||||||
|
private static Database database = Database.open(); |
||||||
|
private String email, salt, hashedPass, name; |
||||||
|
|
||||||
|
public User(String email, String name, String salt, String hashedPass) { |
||||||
|
this.email = email; |
||||||
|
this.name = name; |
||||||
|
this.salt = salt; |
||||||
|
this.hashedPass = hashedPass; |
||||||
|
} |
||||||
|
|
||||||
|
public static User create(String email, String name, String password) throws SQLException { |
||||||
|
var salt = Util.sha256(email + name + LocalDate.now()); |
||||||
|
var hashedPass = Util.sha256(password+salt); |
||||||
|
return new User(email,name,salt,hashedPass).save(); |
||||||
|
} |
||||||
|
|
||||||
|
public static User load(String email, String password) throws InvalidKeyException, SQLException { |
||||||
|
ResultSet rs = database |
||||||
|
.query("SELECT * FROM Users") |
||||||
|
.where(EMAIL,email) |
||||||
|
.exec(); |
||||||
|
|
||||||
|
try { |
||||||
|
if (rs.next()) { |
||||||
|
email = rs.getString(EMAIL); |
||||||
|
var name = rs.getString(NAME); |
||||||
|
var hashedPassword = rs.getString(HASHED_PASS); |
||||||
|
var salt = rs.getString(SALT); |
||||||
|
var loadedUser = new User(email, name, salt, hashedPassword); |
||||||
|
if (loadedUser.matching(password)) return loadedUser; |
||||||
|
} else if (noUsers()){ |
||||||
|
return User.create(email,"Admin",password); |
||||||
|
} |
||||||
|
} finally { |
||||||
|
rs.close(); |
||||||
|
} |
||||||
|
|
||||||
|
throw new InvalidKeyException(); |
||||||
|
} |
||||||
|
|
||||||
|
private static boolean noUsers() throws SQLException { |
||||||
|
var rs = database.query("SELECT count(*) FROM users").exec(); |
||||||
|
try { |
||||||
|
if (rs.next()) { |
||||||
|
return rs.getInt(1) < 1; |
||||||
|
} |
||||||
|
} finally { |
||||||
|
rs.close(); |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
private boolean matching(String password) { |
||||||
|
return hashedPass.equals(Util.sha256(password+salt)); |
||||||
|
} |
||||||
|
|
||||||
|
private User save() throws SQLException { |
||||||
|
database.insertInto("Users") |
||||||
|
.values(Map.of(EMAIL,email,NAME,name,SALT,salt,HASHED_PASS,hashedPass)) |
||||||
|
.run(); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public Map<String,String> map() { |
||||||
|
return Map.of(EMAIL,email,NAME,name); |
||||||
|
} |
||||||
|
} |
@ -1,43 +0,0 @@ |
|||||||
package de.srsoftware.widerhall.web; |
|
||||||
|
|
||||||
import de.srsoftware.tools.Tag; |
|
||||||
import org.slf4j.Logger; |
|
||||||
import org.slf4j.LoggerFactory; |
|
||||||
|
|
||||||
import javax.servlet.ServletException; |
|
||||||
import javax.servlet.http.HttpServlet; |
|
||||||
import javax.servlet.http.HttpServletRequest; |
|
||||||
import javax.servlet.http.HttpServletResponse; |
|
||||||
import java.io.IOException; |
|
||||||
|
|
||||||
public class Index extends HttpServlet { |
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(Index.class); |
|
||||||
|
|
||||||
@Override |
|
||||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { |
|
||||||
resp.setContentType("text/html"); |
|
||||||
resp.setStatus(HttpServletResponse.SC_OK); |
|
||||||
String auth = req.getHeader("Authorization"); |
|
||||||
if (auth == null) { |
|
||||||
resp.sendRedirect("login"); |
|
||||||
return; |
|
||||||
} |
|
||||||
LOG.debug("Authorization: {}",auth); |
|
||||||
|
|
||||||
resp.getWriter().println(page(auth)); |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
private Tag head() { |
|
||||||
return new Tag("meta") |
|
||||||
.attr("charset","utf-8") |
|
||||||
.addTo(new Tag("head")); |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
private Tag page(String auth) { |
|
||||||
var body = new Tag("body").content(auth); |
|
||||||
return body.addTo(head().addTo(new Tag("html"))); |
|
||||||
} |
|
||||||
} |
|
@ -1,127 +0,0 @@ |
|||||||
package de.srsoftware.widerhall.web; |
|
||||||
|
|
||||||
import de.srsoftware.widerhall.Configuration; |
|
||||||
import de.srsoftware.widerhall.web.tags.Page; |
|
||||||
import org.slf4j.Logger; |
|
||||||
import org.slf4j.LoggerFactory; |
|
||||||
|
|
||||||
import javax.net.ssl.HttpsURLConnection; |
|
||||||
import javax.servlet.http.HttpServlet; |
|
||||||
import javax.servlet.http.HttpServletRequest; |
|
||||||
import javax.servlet.http.HttpServletResponse; |
|
||||||
import java.io.BufferedReader; |
|
||||||
import java.io.DataOutputStream; |
|
||||||
import java.io.IOException; |
|
||||||
import java.io.InputStreamReader; |
|
||||||
import java.net.URLEncoder; |
|
||||||
import java.nio.charset.StandardCharsets; |
|
||||||
import java.util.Map; |
|
||||||
import java.util.stream.Collectors; |
|
||||||
|
|
||||||
public class Login extends HttpServlet { |
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(Login.class); |
|
||||||
private final Configuration config; |
|
||||||
|
|
||||||
public Login(){ |
|
||||||
this.config = Configuration.instance(); |
|
||||||
LOG.debug("Creating new instance of Login.class"); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { |
|
||||||
var error = req.getParameter("error"); |
|
||||||
if (error != null){ |
|
||||||
var description = req.getParameter("error_description"); |
|
||||||
sendError(resp,error+": "+description); |
|
||||||
return; |
|
||||||
} |
|
||||||
LOG.debug("params: {}",req.getParameterMap()); |
|
||||||
var code = req.getParameter("code"); |
|
||||||
if (code != null){ |
|
||||||
getTokenFor(code,resp); |
|
||||||
resp.getWriter().println(new Page("rceived code: "+code)); |
|
||||||
return; |
|
||||||
} |
|
||||||
resp.sendRedirect(loginUrl()); |
|
||||||
} |
|
||||||
|
|
||||||
private static String urlEncode(Map<String, Object> 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); |
|
||||||
} |
|
||||||
|
|
||||||
private void getTokenFor(String code, HttpServletResponse resp) throws IOException { |
|
||||||
var url = config.tokenUrl(); |
|
||||||
LOG.debug("Sending 'POST' request to URL '{}'",url); |
|
||||||
HttpsURLConnection httpClient = (HttpsURLConnection) url.openConnection(); |
|
||||||
|
|
||||||
//add reuqest header
|
|
||||||
httpClient.setRequestMethod("POST"); |
|
||||||
httpClient.setRequestProperty( "Content-Type", "application/x-www-form-urlencoded"); |
|
||||||
httpClient.setRequestProperty( "Accept", "*/*" ); |
|
||||||
//httpClient.setRequestProperty("User-Agent", "Mozilla/5.0");
|
|
||||||
//httpClient.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
|
|
||||||
|
|
||||||
String urlParameters = urlEncode(Map.of( |
|
||||||
"code",code, |
|
||||||
"client_id",config.clientId(), |
|
||||||
"client_secret",config.clientSecret(), |
|
||||||
"grant_type","authorization_code")); |
|
||||||
|
|
||||||
LOG.debug("Posting parameters '{}'",urlParameters); |
|
||||||
|
|
||||||
// Send post request
|
|
||||||
httpClient.setDoOutput(true); |
|
||||||
httpClient.setDoInput(true); |
|
||||||
try (DataOutputStream wr = new DataOutputStream(httpClient.getOutputStream())) { |
|
||||||
wr.writeBytes(urlParameters); |
|
||||||
wr.flush(); |
|
||||||
} |
|
||||||
|
|
||||||
int responseCode = httpClient.getResponseCode(); |
|
||||||
LOG.debug("Response Code: {}",responseCode); |
|
||||||
|
|
||||||
try (BufferedReader in = new BufferedReader(new InputStreamReader(httpClient.getInputStream()))) { |
|
||||||
|
|
||||||
String line; |
|
||||||
StringBuilder response = new StringBuilder(); |
|
||||||
|
|
||||||
while ((line = in.readLine()) != null) { |
|
||||||
response.append(line); |
|
||||||
} |
|
||||||
|
|
||||||
//print result
|
|
||||||
//System.out.println(response.toString());
|
|
||||||
resp.getWriter().println(response); |
|
||||||
|
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void sendError(HttpServletResponse resp, String error) throws IOException { |
|
||||||
LOG.debug("error: {}",error); |
|
||||||
resp.sendError(HttpServletResponse.SC_BAD_REQUEST,error); |
|
||||||
} |
|
||||||
|
|
||||||
private String loginUrl() { |
|
||||||
return config.loginUrl()+"?"+urlEncode(Map.of( |
|
||||||
"response_type","code", |
|
||||||
"client_id",config.clientId(), |
|
||||||
"state",123456, |
|
||||||
"redirect_uri",redirectUri(), |
|
||||||
"scope","openid" |
|
||||||
)); |
|
||||||
} |
|
||||||
|
|
||||||
private String redirectUri() { |
|
||||||
int port = config.serverPort(); |
|
||||||
return config.baseUrl()+(port == 80 ? "" : ":"+port)+"/login"; |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,138 @@ |
|||||||
|
package de.srsoftware.widerhall.web; |
||||||
|
|
||||||
|
import de.srsoftware.widerhall.Configuration; |
||||||
|
import de.srsoftware.widerhall.Util; |
||||||
|
import de.srsoftware.widerhall.data.User; |
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
import org.stringtemplate.v4.STGroup; |
||||||
|
import org.stringtemplate.v4.STGroupDir; |
||||||
|
|
||||||
|
import javax.servlet.ServletException; |
||||||
|
import javax.servlet.http.HttpServlet; |
||||||
|
import javax.servlet.http.HttpServletRequest; |
||||||
|
import javax.servlet.http.HttpServletResponse; |
||||||
|
import java.io.File; |
||||||
|
import java.io.IOException; |
||||||
|
import java.nio.file.Files; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import static de.srsoftware.widerhall.Util.t; |
||||||
|
|
||||||
|
public class Static extends HttpServlet { |
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(Static.class); |
||||||
|
private final String baseDir; |
||||||
|
private final STGroup templates; |
||||||
|
|
||||||
|
public Static(){ |
||||||
|
var config = Configuration.instance(); |
||||||
|
baseDir = config.baseDir(); |
||||||
|
var templateDir = String.join(File.separator,baseDir,"templates"); |
||||||
|
templates = new STGroupDir(templateDir,'{','}'); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { |
||||||
|
String error = handleGet(req, resp); |
||||||
|
if (error != null) resp.sendError(400,error); |
||||||
|
} |
||||||
|
|
||||||
|
private String handleGet(HttpServletRequest req, HttpServletResponse resp) { |
||||||
|
var path = req.getPathInfo(); |
||||||
|
path = path == null ? "index" : path.substring(1); |
||||||
|
switch (path){ |
||||||
|
case "css": |
||||||
|
return loadFile("style.css",resp); |
||||||
|
case "js": |
||||||
|
return loadFile("widerhall.js",resp); |
||||||
|
case "jquery": |
||||||
|
return loadFile("jquery-3.6.0.min.js",resp); |
||||||
|
case "login": |
||||||
|
return loadTemplate(path, null, resp); |
||||||
|
} |
||||||
|
|
||||||
|
var u = req.getSession().getAttribute("user"); |
||||||
|
if (u instanceof User user){ |
||||||
|
Map<String,Object> data = Map.of("user",user.map()); |
||||||
|
return loadTemplate(path,data,resp); |
||||||
|
} |
||||||
|
return loginRedirect(resp); |
||||||
|
} |
||||||
|
|
||||||
|
private String loadTemplate(String path, Map<String, ? extends Object> data, HttpServletResponse resp) { |
||||||
|
var template = templates.getInstanceOf(path); |
||||||
|
if (template != null){ |
||||||
|
try { |
||||||
|
template.add("data",data); |
||||||
|
resp.getWriter().println(template.render()); |
||||||
|
return null; |
||||||
|
} catch (IOException e) { |
||||||
|
return t("Failed to load template '{}'",path); |
||||||
|
} |
||||||
|
} |
||||||
|
return t("No template for path {}!",path); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private String loginRedirect(HttpServletResponse resp) { |
||||||
|
try { |
||||||
|
resp.sendRedirect("/static/login"); |
||||||
|
return null; |
||||||
|
} catch (IOException e) { |
||||||
|
return t("Was not able to redirect to login page: {}", e.getMessage()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private String loadFile(String filename, HttpServletResponse resp) { |
||||||
|
var path = String.join(File.separator,baseDir,filename); |
||||||
|
LOG.debug("loading {}",path); |
||||||
|
var file = new File(path); |
||||||
|
if (!file.exists()) return t("File {} does not exist!",filename); |
||||||
|
try { |
||||||
|
var content = Files.readString(file.toPath()); |
||||||
|
resp.getWriter().println(content); |
||||||
|
} catch (IOException e) { |
||||||
|
return t("Failed to load file '{}'!",filename); |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { |
||||||
|
String error = handlePost(req, resp); |
||||||
|
if (error != null) resp.sendError(400,error); |
||||||
|
} |
||||||
|
|
||||||
|
private String handlePost(HttpServletRequest req, HttpServletResponse resp) { |
||||||
|
var path = req.getPathInfo(); |
||||||
|
if (path == null) path = "/"; |
||||||
|
switch (path){ |
||||||
|
case "/login": |
||||||
|
return handleLogin(req,resp); |
||||||
|
} |
||||||
|
|
||||||
|
return t("No handler for path {}!",path); |
||||||
|
} |
||||||
|
|
||||||
|
private String handleLogin(HttpServletRequest req, HttpServletResponse resp) { |
||||||
|
var email = req.getParameter("email"); |
||||||
|
var pass = req.getParameter("pass"); |
||||||
|
if (email == null || pass == null) return loginRedirect(resp); |
||||||
|
if (!Util.isEmail(email)) return loadTemplate("login", Map.of("error",t("'{}' is not a valid email address!",email)), resp); |
||||||
|
try { |
||||||
|
var user = User.load(email,pass); |
||||||
|
req.getSession().setAttribute("user",user); |
||||||
|
resp.sendRedirect("/static"); |
||||||
|
} catch (Exception e) { |
||||||
|
try { |
||||||
|
LOG.warn("Static.handleLogin failed:",e); |
||||||
|
Thread.sleep(10000); |
||||||
|
} finally { |
||||||
|
return loadTemplate("login", Map.of("error",t("Invalid username/password")), resp); |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -1,10 +0,0 @@ |
|||||||
package de.srsoftware.widerhall.web.tags; |
|
||||||
|
|
||||||
import de.srsoftware.tools.Tag; |
|
||||||
|
|
||||||
public class Header extends Tag { |
|
||||||
public Header() { |
|
||||||
super("head"); |
|
||||||
new Tag("meta").attr("charset","utf-8").addTo(this); |
|
||||||
} |
|
||||||
} |
|
@ -1,11 +0,0 @@ |
|||||||
package de.srsoftware.widerhall.web.tags; |
|
||||||
|
|
||||||
import de.srsoftware.tools.Tag; |
|
||||||
|
|
||||||
public class Page extends Tag { |
|
||||||
public Page(String content) { |
|
||||||
super("html"); |
|
||||||
new Header().addTo(this); |
|
||||||
new Tag("body").content(content).addTo(this); |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,19 @@ |
|||||||
|
label { |
||||||
|
display: block; |
||||||
|
margin: 5px 0; |
||||||
|
} |
||||||
|
|
||||||
|
#login form { |
||||||
|
width: 450px; |
||||||
|
margin: 0 auto; |
||||||
|
} |
||||||
|
|
||||||
|
h1 { |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
|
||||||
|
.error{ |
||||||
|
display: block; |
||||||
|
text-align: center; |
||||||
|
background: orange; |
||||||
|
} |
@ -0,0 +1,14 @@ |
|||||||
|
index(data) ::= << |
||||||
|
<html> |
||||||
|
<head> |
||||||
|
<meta charset="utf-8" /> |
||||||
|
<script src="static/jquery"></script> |
||||||
|
<script src="static/js"></script> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<span class="user">Logged in as <em>{data.user.name}</em></span> |
||||||
|
<h2>Users</h2> |
||||||
|
<h2>Lists</h2> |
||||||
|
</body> |
||||||
|
</html> |
||||||
|
>> |
@ -0,0 +1,30 @@ |
|||||||
|
login(data) ::= << |
||||||
|
<html> |
||||||
|
<head> |
||||||
|
<meta charset="utf-8" /> |
||||||
|
<script src="/static/jquery"></script> |
||||||
|
<script src="/static/js"></script> |
||||||
|
<link rel="stylesheet" href="/static/css" /> |
||||||
|
</head> |
||||||
|
<body id="login"> |
||||||
|
<h1>Widerhall login</h1> |
||||||
|
{if(data.error)} |
||||||
|
<span class="error">{data.error}</span> |
||||||
|
{endif} |
||||||
|
<form method="POST"> |
||||||
|
<fieldset> |
||||||
|
<legend>Login-Daten</legend> |
||||||
|
<label> |
||||||
|
<input type="text" name="email" value="" id="email" /> |
||||||
|
E-Mail-Adresse |
||||||
|
</label> |
||||||
|
<label> |
||||||
|
<input type="password" name="pass" value="" id="password" /> |
||||||
|
Passwort |
||||||
|
</label> |
||||||
|
<button type="submit">Einloggen</button> |
||||||
|
</fieldset> |
||||||
|
</form> |
||||||
|
</body> |
||||||
|
</html> |
||||||
|
>> |
Loading…
Reference in new issue