diff --git a/core/src/main/java/de/srsoftware/umbrella/core/BaseHandler.java b/core/src/main/java/de/srsoftware/umbrella/core/BaseHandler.java
index d1d3b39..3e18abb 100644
--- a/core/src/main/java/de/srsoftware/umbrella/core/BaseHandler.java
+++ b/core/src/main/java/de/srsoftware/umbrella/core/BaseHandler.java
@@ -15,7 +15,7 @@ import java.util.List;
public abstract class BaseHandler extends PathHandler {
- private static HttpExchange addCors(HttpExchange ex){
+ public HttpExchange addCors(HttpExchange ex){
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()) {
@@ -25,7 +25,7 @@ public abstract class BaseHandler extends PathHandler {
headers.add("Access-Control-Allow-Origin", url);
headers.add("Access-Control-Allow-Headers", "Content-Type");
headers.add("Access-Control-Allow-Credentials", "true");
- headers.add("Access-Control-Allow-Methods","GET, POST, PATCH");
+ headers.add("Access-Control-Allow-Methods","DELETE, GET, POST, PATCH");
}
return ex;
}
diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte
index f32a149..0b5ce71 100644
--- a/frontend/src/App.svelte
+++ b/frontend/src/App.svelte
@@ -8,6 +8,7 @@
import Footer from "./Components/Footer.svelte";
import Login from "./Components/Login.svelte";
import Menu from "./Components/Menu.svelte";
+ import Search from "./routes/search/Search.svelte";
import User from "./routes/user/User.svelte";
import UserEdit from "./routes/user/Edit.svelte";
@@ -31,10 +32,11 @@
{#if user.name }
-
-
-
-
+
+
+
+
+
Page not found
diff --git a/frontend/src/routes/search/Search.svelte b/frontend/src/routes/search/Search.svelte
new file mode 100644
index 0000000..c53379d
--- /dev/null
+++ b/frontend/src/routes/search/Search.svelte
@@ -0,0 +1,44 @@
+
+
+
+{#if html}
+
+{/if}
\ No newline at end of file
diff --git a/legacy/src/main/java/de/srsoftware/umbrella/legacy/LegacyApi.java b/legacy/src/main/java/de/srsoftware/umbrella/legacy/LegacyApi.java
index d912dc6..4029eca 100644
--- a/legacy/src/main/java/de/srsoftware/umbrella/legacy/LegacyApi.java
+++ b/legacy/src/main/java/de/srsoftware/umbrella/legacy/LegacyApi.java
@@ -55,11 +55,11 @@ public class LegacyApi extends BaseHandler {
allowOrigin(ex, "*"); // add CORS header
yield load(path,ex);
}
- case LOGIN -> getLegacyLogin(ex);
+ case LOGIN -> getLogin(ex);
case LOGOUT-> logout(ex);
case SEARCH -> {
try {
- yield legacySearch(ex);
+ yield search(ex);
} catch (UmbrellaException e){
yield send(ex,e);
}
@@ -68,54 +68,21 @@ public class LegacyApi extends BaseHandler {
};
}
- private boolean legacySearch(HttpExchange ex) throws IOException, UmbrellaException {
- var optToken = SessionToken.from(ex).map(Token::of);
- if (optToken.isEmpty()) return sendEmptyResponse(HTTP_UNAUTHORIZED,ex);
- var token = optToken.get();
- var params = queryParam(ex);
- var key = params.get(KEY) instanceof String s ? s : null;
- if (key == null) throw new UmbrellaException(HTTP_BAD_REQUEST,"Missing search key");
- var fulltext = key.contains("+") || "on".equals(params.get("fulltext"));
- StringBuilder searchResult = new StringBuilder();
- if (fulltext){
-
- for (var module : config.keys()){
- var baseUrl = config.get(module + ".baseUrl");
- if (baseUrl.isEmpty()) continue;
-
- var res = request(baseUrl.get()+"/search",token.asMap().plus(KEY,key),MIME_FORM_URL,token.asBearer());
- if (!(res instanceof String content) || content.isBlank()) continue;
- searchResult.append("\n");
- }
- } else {
- var bookmark = config.get("bookmark.baseUrl");
- if (bookmark.isEmpty()) throw new UmbrellaException(500,"Tag search not available: Bookmark module not configured!");
- var res = request(bookmark.get()+"/search",token.asMap().plus(KEY,key),MIME_FORM_URL,null);
- if (!(res instanceof String content)) throw new UmbrellaException(500,"Search did not return html content!");
- searchResult.append(content);
- }
- return sendContent(ex,searchResult.toString());
- };
-
- private boolean logout(HttpExchange ex) throws IOException {
- var returnTo = queryParam(ex).get("returnTo");
- var optToken = SessionToken.from(ex).map(Token::of);
- if (optToken.isPresent()) try{
- var token = optToken.get();
- users.dropSession(token);
- var expiredToken = new SessionToken(token.toString(),"/", Instant.now().minus(1, DAYS),true);
- expiredToken.addTo(ex);
- if (returnTo instanceof String location) return sendRedirect(ex,location);
- return sendContent(ex, Map.of(REDIRECT,"home"));
- } catch (UmbrellaException e) {
+ @Override
+ public boolean doPost(Path path, HttpExchange ex) throws IOException {
+ try {
+ return switch (path.pop()) {
+ case JSON -> jsonUser(ex);
+ case NOTIFY -> legacyNotify(ex);
+ case VALIDATE_TOKEN -> validateToken(ex);
+ default -> super.doPost(path,ex);
+ };
+ } catch (UmbrellaException e){
return send(ex,e);
}
- if (returnTo instanceof String location) return sendRedirect(ex,location);
- return sendContent(ex,Map.of(REDIRECT,"home"));
}
- private boolean getLegacyLogin(HttpExchange ex) throws IOException {
+ private boolean getLogin(HttpExchange ex) throws IOException {
var returnTo = queryParam(ex).get("returnTo");
if (returnTo instanceof String url) {
var token = SessionToken.from(ex).map(SessionToken::sessionId)
@@ -131,59 +98,8 @@ public class LegacyApi extends BaseHandler {
return sendRedirect(ex,location);
}
- @Override
- public boolean doPost(Path path, HttpExchange ex) throws IOException {
- try {
- return switch (path.pop()) {
- case JSON -> legacyJson(ex);
- case NOTIFY -> legacyNotify(ex);
- case VALIDATE_TOKEN -> validateToken(ex);
- default -> super.doPost(path,ex);
- };
- } catch (UmbrellaException e){
- return send(ex,e);
- }
- }
-
- private static String stripTrailingSlash(Object o){
- String url = o.toString();
- if (url.endsWith("/")) return url.substring(0,url.length()-1);
- return url;
- }
-
- private boolean validateToken(HttpExchange ex) throws UmbrellaException, IOException {
- String body;
- try {
- body = body(ex);
- } catch (Exception e){
- throw new UmbrellaException(400,"Failed to read request body").causedBy(e);
- }
- var map = decode(body);
- LOG.log(DEBUG,"validateToken(…, {0}), data: {1}",map);
-
- String domain = stripTrailingSlash(map.get(DOMAIN) instanceof String s ? s : "");
- var keys = config.keys();
- var match = false;
- for (var key : keys){
- var baseUrl = config.get(key + ".baseUrl").map(LegacyApi::stripTrailingSlash).orElse(null);
- if (domain.equals(baseUrl)){
- match = true;
- break;
- }
- }
- if (!match) throw new UmbrellaException(500,"Failed to verify request domain!");
-
- var o = map.get(TOKEN);
- if (!(o instanceof String token)) throw new UmbrellaException(500,"Request did not contain token!");
- var session = users.load(Token.of(token));
- var user = users.load(session);
- var userMap = user.toMap();
- userMap.put(TOKEN,Map.of(TOKEN,token,EXPIRATION,session.expiration().getEpochSecond()));
- return sendContent(ex,userMap);
- }
-
- private boolean legacyJson(HttpExchange ex) throws UmbrellaException, IOException {
- Map data = null;
+ private boolean jsonUser(HttpExchange ex) throws UmbrellaException, IOException {
+ Map data = null;
try {
data = decode(body(ex));
} catch (IOException e) {
@@ -228,12 +144,6 @@ public class LegacyApi extends BaseHandler {
return sendContent(ex, userList.getFirst().toMap());
}
- protected Session requestSession(Token token) throws UmbrellaException {
- var session = users.load(token);
- session = users.extend(session);
- return session;
- }
-
private boolean legacyNotify(HttpExchange ex) throws UmbrellaException, IOException {
if (messageUrl == null) throw new UmbrellaException(500,"missing configuration: umbrella.modules.message.baseUrl");
var mime = contentType(ex).orElse(null);
@@ -291,4 +201,94 @@ public class LegacyApi extends BaseHandler {
// TODO: should we return json?
return sendEmptyResponse(HTTP_OK,ex);
}
+
+ private boolean logout(HttpExchange ex) throws IOException {
+ var returnTo = queryParam(ex).get("returnTo");
+ var optToken = SessionToken.from(ex).map(Token::of);
+ if (optToken.isPresent()) try{
+ var token = optToken.get();
+ users.dropSession(token);
+ var expiredToken = new SessionToken(token.toString(),"/", Instant.now().minus(1, DAYS),true);
+ expiredToken.addTo(ex);
+ if (returnTo instanceof String location) return sendRedirect(ex,location);
+ return sendContent(ex, Map.of(REDIRECT,"home"));
+ } catch (UmbrellaException e) {
+ return send(ex,e);
+ }
+ if (returnTo instanceof String location) return sendRedirect(ex,location);
+ return sendContent(ex,Map.of(REDIRECT,"home"));
+ }
+
+ protected Session requestSession(Token token) throws UmbrellaException {
+ var session = users.load(token);
+ session = users.extend(session);
+ return session;
+ }
+
+ private boolean search(HttpExchange ex) throws IOException, UmbrellaException {
+ var optToken = SessionToken.from(ex).map(Token::of);
+ if (optToken.isEmpty()) return sendEmptyResponse(HTTP_UNAUTHORIZED,ex);
+ var token = optToken.get();
+ var params = queryParam(ex);
+ var key = params.get(KEY) instanceof String s ? s : null;
+ if (key == null) throw new UmbrellaException(HTTP_BAD_REQUEST,"Missing search key");
+ var fulltext = key.contains("+") || "on".equals(params.get("fulltext"));
+ StringBuilder searchResult = new StringBuilder();
+ if (fulltext){
+ for (var module : config.keys()){
+ var baseUrl = config.get(module + ".baseUrl");
+ if (baseUrl.isEmpty()) continue;
+
+ var res = request(baseUrl.get()+"/search",token.asMap().plus(KEY,key),MIME_FORM_URL,token.asBearer());
+ if (!(res instanceof String content) || content.isBlank()) continue;
+ searchResult.append("\n");
+ }
+ } else {
+ var bookmark = config.get("bookmark.baseUrl");
+ if (bookmark.isEmpty()) throw new UmbrellaException(500,"Tag search not available: Bookmark module not configured!");
+ var res = request(bookmark.get()+"/search",token.asMap().plus(KEY,key),MIME_FORM_URL,null);
+ if (!(res instanceof String content)) throw new UmbrellaException(500,"Search did not return html content!");
+ searchResult.append(content);
+ }
+ addCors(ex);
+ return sendContent(ex,searchResult.toString());
+ };
+
+ private static String stripTrailingSlash(Object o){
+ String url = o.toString();
+ if (url.endsWith("/")) return url.substring(0,url.length()-1);
+ return url;
+ }
+
+ private boolean validateToken(HttpExchange ex) throws UmbrellaException, IOException {
+ String body;
+ try {
+ body = body(ex);
+ } catch (Exception e){
+ throw new UmbrellaException(400,"Failed to read request body").causedBy(e);
+ }
+ var map = decode(body);
+ LOG.log(DEBUG,"validateToken(…, {0}), data: {1}",map);
+
+ String domain = stripTrailingSlash(map.get(DOMAIN) instanceof String s ? s : "");
+ var keys = config.keys();
+ var match = false;
+ for (var key : keys){
+ var baseUrl = config.get(key + ".baseUrl").map(LegacyApi::stripTrailingSlash).orElse(null);
+ if (domain.equals(baseUrl)){
+ match = true;
+ break;
+ }
+ }
+ if (!match) throw new UmbrellaException(500,"Failed to verify request domain!");
+
+ var o = map.get(TOKEN);
+ if (!(o instanceof String token)) throw new UmbrellaException(500,"Request did not contain token!");
+ var session = users.load(Token.of(token));
+ var user = users.load(session);
+ var userMap = user.toMap();
+ userMap.put(TOKEN,Map.of(TOKEN,token,EXPIRATION,session.expiration().getEpochSecond()));
+ return sendContent(ex,userMap);
+ }
}
diff --git a/user/src/main/java/de/srsoftware/umbrella/user/UserModule.java b/user/src/main/java/de/srsoftware/umbrella/user/UserModule.java
index bf31615..88f2514 100644
--- a/user/src/main/java/de/srsoftware/umbrella/user/UserModule.java
+++ b/user/src/main/java/de/srsoftware/umbrella/user/UserModule.java
@@ -72,20 +72,7 @@ public class UserModule extends BaseHandler {
logins = loginDb;
}
- private HttpExchange addCors(HttpExchange ex){
- 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");
- headers.add("Access-Control-Allow-Methods","DELETE, GET, POST, PATCH");
- }
- return ex;
- }
+
private boolean deleteOIDC(HttpExchange ex, UmbrellaUser user, Path path) throws IOException {
var head = path.pop();
diff --git a/web/src/main/java/de/srsoftware/umbrella/web/WebHandler.java b/web/src/main/java/de/srsoftware/umbrella/web/WebHandler.java
index 23b52d0..c2732c3 100644
--- a/web/src/main/java/de/srsoftware/umbrella/web/WebHandler.java
+++ b/web/src/main/java/de/srsoftware/umbrella/web/WebHandler.java
@@ -9,26 +9,13 @@ import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
import com.sun.net.httpserver.HttpExchange;
import de.srsoftware.tools.Path;
import de.srsoftware.tools.PathHandler;
+import de.srsoftware.umbrella.core.BaseHandler;
+
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
-public class WebHandler extends PathHandler {
-
- private HttpExchange addCors(HttpExchange ex){
- 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");
- headers.add("Access-Control-Allow-Methods","GET, POST, PATCH");
- }
- return ex;
- }
+public class WebHandler extends BaseHandler {
@Override
public boolean doGet(Path path, HttpExchange ex) throws IOException {