Updated frontend to new Protocol
This commit is contained in:
@@ -2,46 +2,132 @@ package ins.frontend;
|
||||
|
||||
import ins.frontend.utils.UserDao;
|
||||
import ins.frontend.utils.WebApp;
|
||||
import org.openautonomousconnection.protocol.packets.v1_0_0.beta.web.WebResponsePacket;
|
||||
import org.openautonomousconnection.protocol.packets.v1_0_1.beta.web.impl.resource.WebResourceResponsePacket;
|
||||
import org.openautonomousconnection.protocol.side.web.ProtocolWebServer;
|
||||
import org.openautonomousconnection.protocol.side.web.managers.SessionManager;
|
||||
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.WebRequestMethod;
|
||||
import org.openautonomousconnection.protocol.versions.v1_0_1.beta.WebPacketFlags;
|
||||
import org.openautonomousconnection.protocol.versions.v1_0_1.beta.WebPacketHeader;
|
||||
import org.openautonomousconnection.webserver.api.Route;
|
||||
import org.openautonomousconnection.webserver.api.SessionContext;
|
||||
import org.openautonomousconnection.webserver.api.WebPage;
|
||||
import org.openautonomousconnection.webserver.api.WebPageContext;
|
||||
import org.openautonomousconnection.webserver.utils.HeaderMaps;
|
||||
import org.openautonomousconnection.webserver.utils.Html;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Login page with existing-session short-circuit.
|
||||
*
|
||||
* <p>Username stored in DB as plain text.</p>
|
||||
* Login page (v1.0.1).
|
||||
*/
|
||||
@Route(path = "/login.html")
|
||||
public final class login implements WebPage {
|
||||
|
||||
private static WebResponsePacket ok(String html) {
|
||||
return new WebResponsePacket(200, "text/html; charset=utf-8", HeaderMaps.mutable(), Html.utf8(html));
|
||||
}
|
||||
private enum ReqMethod { GET, POST, OTHER }
|
||||
|
||||
private static WebResponsePacket text(int code, String msg) {
|
||||
return new WebResponsePacket(code, "text/plain; charset=utf-8", HeaderMaps.mutable(), msg.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
@Override
|
||||
public WebResourceResponsePacket handle(WebPageContext ctx) throws Exception {
|
||||
WebApp.init();
|
||||
|
||||
private static WebResponsePacket redirect302(String location, String session) {
|
||||
Map<String, String> headers = HeaderMaps.mutable();
|
||||
headers.put("location", location);
|
||||
if (session != null && !session.isBlank()) {
|
||||
headers.put("Location", "dashboard.html");
|
||||
headers.put("Set-Cookie", "session=" + session + "; Path=/; HttpOnly; SameSite=Lax");
|
||||
headers.put("session", session);
|
||||
headers.put("cookie", session);
|
||||
// If a valid session already exists -> go dashboard (keep session)
|
||||
if (ctx.session != null && ctx.session.isValid() && ctx.session.getUser() != null) {
|
||||
return redirect302(ctx, "dashboard.html", ctx.session.getSessionId());
|
||||
}
|
||||
return new WebResponsePacket(302, "text/plain; charset=utf-8", headers, new byte[0]);
|
||||
|
||||
ReqMethod method = detectMethod(ctx);
|
||||
if (method == ReqMethod.GET) {
|
||||
return ok(ctx, renderForm(null));
|
||||
}
|
||||
|
||||
if (method != ReqMethod.POST) {
|
||||
return text(ctx, 405, "Method Not Allowed");
|
||||
}
|
||||
|
||||
String contentType = headerIgnoreCase(ctx.request.getHeaders(), "content-type");
|
||||
String ctLower = (contentType == null) ? "" : contentType.toLowerCase(Locale.ROOT);
|
||||
|
||||
if (!ctLower.startsWith("application/x-www-form-urlencoded")) {
|
||||
return ok(ctx, renderForm("Unsupported content-type: " + Html.esc(contentType)));
|
||||
}
|
||||
|
||||
Map<String, List<String>> form = parseFormUrlEncoded(ctx.request.getBody());
|
||||
String username = first(form, "username");
|
||||
String password = first(form, "password");
|
||||
|
||||
if (username == null || password == null) {
|
||||
return ok(ctx, renderForm("Missing username/password."));
|
||||
}
|
||||
|
||||
String lookupUsername = username.trim();
|
||||
|
||||
UserDao.UserRow user = WebApp.get().users().findByUsername(lookupUsername).orElse(null);
|
||||
if (user == null) {
|
||||
return ok(ctx, renderForm("Invalid credentials."));
|
||||
}
|
||||
|
||||
boolean okPw = WebApp.get().passwordHasher().verify(password, user.passwordEncoded());
|
||||
if (!okPw) {
|
||||
return ok(ctx, renderForm("Invalid credentials."));
|
||||
}
|
||||
|
||||
String ip = resolveIp(ctx);
|
||||
String ua = headerIgnoreCase(ctx.request.getHeaders(), "user-agent");
|
||||
if (ua == null) ua = "";
|
||||
|
||||
String session = SessionManager.create(
|
||||
String.valueOf(user.id()),
|
||||
ip,
|
||||
ua,
|
||||
(ProtocolWebServer) ctx.client.getServer()
|
||||
);
|
||||
|
||||
return redirect302(ctx, "dashboard.html", session);
|
||||
}
|
||||
|
||||
private ReqMethod detectMethod(WebPageContext ctx) {
|
||||
// Preferred: request.getMethod() via reflection (avoids depending on specific enum package).
|
||||
try {
|
||||
Method m = ctx.request.getClass().getMethod("getMethod");
|
||||
Object v = m.invoke(ctx.request);
|
||||
if (v != null) {
|
||||
String s = String.valueOf(v).trim().toUpperCase(Locale.ROOT);
|
||||
if ("GET".equals(s)) return ReqMethod.GET;
|
||||
if ("POST".equals(s)) return ReqMethod.POST;
|
||||
return ReqMethod.OTHER;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
// Fall back below.
|
||||
}
|
||||
|
||||
// Fallback: treat presence of body as POST-like.
|
||||
byte[] body = ctx.request.getBody();
|
||||
if (body != null && body.length > 0) return ReqMethod.POST;
|
||||
return ReqMethod.GET;
|
||||
}
|
||||
|
||||
private static WebResourceResponsePacket ok(WebPageContext ctx, String html) {
|
||||
byte[] body = Html.utf8(html);
|
||||
Map<String, String> headers = HeaderMaps.mutable();
|
||||
headers.put("content-length", String.valueOf(body.length));
|
||||
return new WebResourceResponsePacket(outHeader(ctx), 200, "text/html; charset=utf-8", headers, body, null);
|
||||
}
|
||||
|
||||
private static WebResourceResponsePacket text(WebPageContext ctx, int code, String msg) {
|
||||
byte[] body = (msg == null ? "" : msg).getBytes(StandardCharsets.UTF_8);
|
||||
Map<String, String> headers = HeaderMaps.mutable();
|
||||
headers.put("content-length", String.valueOf(body.length));
|
||||
return new WebResourceResponsePacket(outHeader(ctx), code, "text/plain; charset=utf-8", headers, body, null);
|
||||
}
|
||||
|
||||
private static WebResourceResponsePacket redirect302(WebPageContext ctx, String location, String session) {
|
||||
Map<String, String> headers = HeaderMaps.mutable();
|
||||
headers.put("Location", location);
|
||||
if (session != null && !session.isBlank()) {
|
||||
headers.put("Set-Cookie", "session=" + session + "; Path=/; HttpOnly; SameSite=Lax");
|
||||
// optional fallback for stacks that read a direct header:
|
||||
headers.put("session", session);
|
||||
}
|
||||
return new WebResourceResponsePacket(outHeader(ctx), 302, "text/plain; charset=utf-8", headers, new byte[0], null);
|
||||
}
|
||||
|
||||
private static String renderForm(String errOrOk) {
|
||||
@@ -140,7 +226,7 @@ public final class login implements WebPage {
|
||||
continue;
|
||||
}
|
||||
if (c == '%' && i + 2 < s.length()) {
|
||||
int hi = hex(s.charAt(i + 1));
|
||||
int hi = hex(c = s.charAt(i + 1));
|
||||
int lo = hex(s.charAt(i + 2));
|
||||
if (hi >= 0 && lo >= 0) {
|
||||
tmp[n++] = (byte) ((hi << 4) | lo);
|
||||
@@ -149,7 +235,7 @@ public final class login implements WebPage {
|
||||
}
|
||||
}
|
||||
|
||||
byte[] b = String.valueOf(c).getBytes(StandardCharsets.UTF_8);
|
||||
byte[] b = String.valueOf(s.charAt(i)).getBytes(StandardCharsets.UTF_8);
|
||||
for (byte bb : b) tmp[n++] = bb;
|
||||
}
|
||||
|
||||
@@ -163,69 +249,18 @@ public final class login implements WebPage {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebResponsePacket handle(WebPageContext ctx) throws Exception {
|
||||
WebApp.init();
|
||||
|
||||
// 1) If a valid session already exists -> go dashboard (keep session)
|
||||
SessionContext existing = SessionContext.from(
|
||||
ctx.client,
|
||||
(ProtocolWebServer) ctx.client.getServer(),
|
||||
ctx.request.getHeaders()
|
||||
private static WebPacketHeader outHeader(WebPageContext ctx) {
|
||||
WebPacketHeader in = (ctx != null && ctx.request != null) ? ctx.request.getHeader() : null;
|
||||
if (in == null) {
|
||||
return new WebPacketHeader(0, 0, 0, 0, WebPacketFlags.RESOURCE, System.currentTimeMillis());
|
||||
}
|
||||
return new WebPacketHeader(
|
||||
in.getRequestId(),
|
||||
in.getTabId(),
|
||||
in.getPageId(),
|
||||
in.getFrameId(),
|
||||
in.getFlags() | WebPacketFlags.RESOURCE,
|
||||
System.currentTimeMillis()
|
||||
);
|
||||
if (existing.isValid() && existing.getUser() != null) {
|
||||
return redirect302("dashboard.html", existing.getSessionId());
|
||||
}
|
||||
|
||||
WebRequestMethod method = ctx.request.getMethod();
|
||||
if (method == null) method = WebRequestMethod.GET;
|
||||
|
||||
if (method == WebRequestMethod.GET) {
|
||||
return ok(renderForm(null));
|
||||
}
|
||||
|
||||
if (method != WebRequestMethod.POST) {
|
||||
return text(405, "Method Not Allowed");
|
||||
}
|
||||
|
||||
String contentType = headerIgnoreCase(ctx.request.getHeaders(), "content-type");
|
||||
String ctLower = (contentType == null) ? "" : contentType.toLowerCase(Locale.ROOT);
|
||||
|
||||
if (!ctLower.startsWith("application/x-www-form-urlencoded")) {
|
||||
return ok(renderForm("Unsupported content-type: " + Html.esc(contentType)));
|
||||
}
|
||||
|
||||
Map<String, List<String>> form = parseFormUrlEncoded(ctx.request.getBody());
|
||||
String username = first(form, "username");
|
||||
String password = first(form, "password");
|
||||
|
||||
if (username == null || password == null) {
|
||||
return ok(renderForm("Missing username/password."));
|
||||
}
|
||||
|
||||
String lookupUsername = username.trim();
|
||||
|
||||
UserDao.UserRow user = WebApp.get().users().findByUsername(lookupUsername).orElse(null);
|
||||
if (user == null) {
|
||||
return ok(renderForm("Invalid credentials."));
|
||||
}
|
||||
|
||||
boolean okPw = WebApp.get().passwordHasher().verify(password, user.passwordEncoded());
|
||||
if (!okPw) {
|
||||
return ok(renderForm("Invalid credentials."));
|
||||
}
|
||||
|
||||
String ip = resolveIp(ctx);
|
||||
String ua = headerIgnoreCase(ctx.request.getHeaders(), "user-agent");
|
||||
if (ua == null) ua = "";
|
||||
|
||||
String session = SessionManager.create(
|
||||
String.valueOf(user.id()),
|
||||
ip,
|
||||
ua,
|
||||
(ProtocolWebServer) ctx.client.getServer()
|
||||
);
|
||||
|
||||
return redirect302("dashboard.html", session);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user