|
|
|
|
@ -1,18 +1,32 @@
@@ -1,18 +1,32 @@
|
|
|
|
|
/* © SRSoftware 2025 */ |
|
|
|
|
package de.srsoftware.umbrella.user; |
|
|
|
|
|
|
|
|
|
import static de.srsoftware.tools.Optionals.nullable; |
|
|
|
|
import static de.srsoftware.umbrella.core.Constants.PASSWORD; |
|
|
|
|
import static de.srsoftware.umbrella.core.Constants.REDIRECT; |
|
|
|
|
import static de.srsoftware.umbrella.core.Paths.LOGOUT; |
|
|
|
|
import static de.srsoftware.umbrella.core.ResponseCode.*; |
|
|
|
|
import static de.srsoftware.umbrella.user.Constants.*; |
|
|
|
|
import static de.srsoftware.umbrella.user.Paths.LOGIN; |
|
|
|
|
import static de.srsoftware.umbrella.user.Paths.WHOAMI; |
|
|
|
|
import static java.time.temporal.ChronoUnit.DAYS; |
|
|
|
|
|
|
|
|
|
import com.sun.net.httpserver.HttpExchange; |
|
|
|
|
import de.srsoftware.tools.Path; |
|
|
|
|
import de.srsoftware.tools.PathHandler; |
|
|
|
|
import de.srsoftware.tools.SessionToken; |
|
|
|
|
import de.srsoftware.umbrella.core.UmbrellaException; |
|
|
|
|
import de.srsoftware.umbrella.user.api.UserDb; |
|
|
|
|
import de.srsoftware.umbrella.user.model.Password; |
|
|
|
|
import de.srsoftware.umbrella.user.model.Session; |
|
|
|
|
import de.srsoftware.umbrella.user.model.Token; |
|
|
|
|
import de.srsoftware.umbrella.user.model.UmbrellaUser; |
|
|
|
|
|
|
|
|
|
import java.io.IOException; |
|
|
|
|
import java.security.NoSuchAlgorithmException; |
|
|
|
|
import java.time.Instant; |
|
|
|
|
import java.util.List; |
|
|
|
|
import java.util.Map; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public class UserModule extends PathHandler { |
|
|
|
|
@ -33,10 +47,16 @@ public class UserModule extends PathHandler {
@@ -33,10 +47,16 @@ public class UserModule extends PathHandler {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private HttpExchange addCors(HttpExchange ex){ |
|
|
|
|
var headers = ex.getResponseHeaders(); |
|
|
|
|
headers.add("Allow-Origin","*"); |
|
|
|
|
headers.add("Access-Control-Allow-Origin","*"); |
|
|
|
|
headers.add("Access-Control-Allow-Headers","Content-Type"); |
|
|
|
|
var headers = ex.getRequestHeaders(); |
|
|
|
|
var origin = nullable(headers.get("Origin")).orElse(List.of()).stream().filter(url -> url.contains("://localhost")||url.contains("://127.0.0.1")).findAny(); |
|
|
|
|
if (origin.isPresent()) { |
|
|
|
|
var url = origin.get(); |
|
|
|
|
headers = ex.getResponseHeaders(); |
|
|
|
|
headers.add("Allow-Origin", url); |
|
|
|
|
headers.add("Access-Control-Allow-Origin", url); |
|
|
|
|
headers.add("Access-Control-Allow-Headers", "Content-Type"); |
|
|
|
|
headers.add("Access-Control-Allow-Credentials", "true"); |
|
|
|
|
} |
|
|
|
|
return ex; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -45,16 +65,55 @@ public class UserModule extends PathHandler {
@@ -45,16 +65,55 @@ public class UserModule extends PathHandler {
|
|
|
|
|
return sendEmptyResponse(200,addCors(ex)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public boolean doGet(Path path, HttpExchange ex) throws IOException { |
|
|
|
|
var p = path.toString(); |
|
|
|
|
switch (p){ |
|
|
|
|
case LOGOUT: return logout(ex); |
|
|
|
|
case WHOAMI: return getUser(ex); |
|
|
|
|
} |
|
|
|
|
return super.doGet(path,ex); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public boolean doPost(Path path, HttpExchange ex) throws IOException { |
|
|
|
|
addCors(ex); |
|
|
|
|
var p = path.toString(); |
|
|
|
|
switch (p){ |
|
|
|
|
case PATH_LOGIN: return postLogin(ex); |
|
|
|
|
case LOGIN: return postLogin(ex); |
|
|
|
|
} |
|
|
|
|
return super.doPost(path, ex); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private boolean getUser(HttpExchange ex) throws IOException { |
|
|
|
|
addCors(ex); |
|
|
|
|
var sessionToken = SessionToken.from(ex); |
|
|
|
|
if (sessionToken.isEmpty()) return sendEmptyResponse(UNAUTHORIZED,ex); |
|
|
|
|
try { |
|
|
|
|
Session session = users.load(Token.of(sessionToken.get())); |
|
|
|
|
UmbrellaUser user = users.load(session); |
|
|
|
|
return sendContent(ex,OK,user); |
|
|
|
|
} catch (UmbrellaException e) { |
|
|
|
|
return sendContent(ex,e.statusCode(),e.getMessage()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public boolean logout(HttpExchange ex) throws IOException { |
|
|
|
|
addCors(ex); |
|
|
|
|
var optToken = SessionToken.from(ex).map(Token::of); |
|
|
|
|
if (optToken.isPresent()){ |
|
|
|
|
var token = optToken.get(); |
|
|
|
|
try { |
|
|
|
|
users.dropSession(token); |
|
|
|
|
} catch (UmbrellaException ignored){ |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
new SessionToken(token.toString(),"/", Instant.now().minus(1, DAYS),true).addTo(ex); |
|
|
|
|
return sendEmptyResponse(OK,ex); |
|
|
|
|
} |
|
|
|
|
return sendEmptyResponse(UNAUTHORIZED,ex); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private boolean postLogin(HttpExchange ex) throws IOException { |
|
|
|
|
var json = json(ex); |
|
|
|
|
if (!(json.has(USERNAME) && json.get(USERNAME) instanceof String username)) return sendContent(ex,UNPROCESSABLE,"Username missing"); |
|
|
|
|
|