- WorkspaceHelper.cs: Zentrale Workspace-Auflösung (relativ → absolut) - Session-Workspace wird relativ zum User-DefaultPath gespeichert - System-Prompt bekommt aufgelösten absoluten Pfad - Path-Traversal-Schutz: '..' in Workspace-Pfaden blockiert - Browse-API gibt '..' nicht mehr als Eintrag zurück - Folder-Browser: basePath-Limit, Back-Button navigiert zum Parent - DefaultPath nur durch Admin bearbeitbar (Profil: readonly) - Legacy: Absolute Pfade in session.Workspace weiterhin kompatibel
99 lines
3.4 KiB
C#
99 lines
3.4 KiB
C#
using System.Text.Json;
|
|
using Gott.Extensions;
|
|
using Gott.Services;
|
|
using Microsoft.AspNetCore.Builder;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Routing;
|
|
|
|
namespace Gott.Endpoints;
|
|
|
|
public static class ProfileEndpoint
|
|
{
|
|
public static void MapProfileEndpoints(this WebApplication app)
|
|
{
|
|
app.MapGet("/api/profile", HandleGet);
|
|
app.MapPut("/api/profile", HandleUpdate);
|
|
app.MapPut("/api/profile/password", HandlePasswordChange);
|
|
}
|
|
|
|
private static async System.Threading.Tasks.Task HandleGet(HttpContext ctx, DatabaseService db)
|
|
{
|
|
var userId = ctx.GetUserId();
|
|
var user = await db.GetUser(userId);
|
|
if (user == null)
|
|
{
|
|
ctx.Response.StatusCode = 404;
|
|
await ctx.Response.WriteAsJsonAsync(new { error = "User not found" });
|
|
return;
|
|
}
|
|
|
|
await ctx.Response.WriteAsJsonAsync(new
|
|
{
|
|
userId = user.UserId,
|
|
username = user.Username,
|
|
displayName = user.DisplayName,
|
|
persona = user.Persona,
|
|
defaultPath = user.DefaultPath,
|
|
isAdmin = user.IsAdmin
|
|
});
|
|
}
|
|
|
|
private static async System.Threading.Tasks.Task HandleUpdate(HttpContext ctx, DatabaseService db)
|
|
{
|
|
var userId = ctx.GetUserId();
|
|
var body = await JsonSerializer.DeserializeAsync<JsonElement>(ctx.Request.Body);
|
|
|
|
var displayName = body.TryGetProperty("displayName", out var dn) ? dn.GetString() : null;
|
|
var persona = body.TryGetProperty("persona", out var p) ? p.GetString() : null;
|
|
|
|
await db.UpdateUserProfile(userId, displayName, persona);
|
|
|
|
var user = await db.GetUser(userId);
|
|
await ctx.Response.WriteAsJsonAsync(new
|
|
{
|
|
userId = user.UserId,
|
|
username = user.Username,
|
|
displayName = user.DisplayName,
|
|
persona = user.Persona,
|
|
defaultPath = user.DefaultPath,
|
|
isAdmin = user.IsAdmin
|
|
});
|
|
}
|
|
|
|
private static async System.Threading.Tasks.Task HandlePasswordChange(HttpContext ctx, DatabaseService db, AuthService auth)
|
|
{
|
|
var userId = ctx.GetUserId();
|
|
var body = await JsonSerializer.DeserializeAsync<JsonElement>(ctx.Request.Body);
|
|
|
|
var currentPassword = body.TryGetProperty("currentPassword", out var cp) ? cp.GetString() : null;
|
|
var newPassword = body.TryGetProperty("newPassword", out var np) ? np.GetString() : null;
|
|
|
|
if (string.IsNullOrEmpty(currentPassword) || string.IsNullOrEmpty(newPassword))
|
|
{
|
|
ctx.Response.StatusCode = 400;
|
|
await ctx.Response.WriteAsJsonAsync(new { error = "Aktuelles und neues Passwort erforderlich" });
|
|
return;
|
|
}
|
|
|
|
if (newPassword.Length < 4)
|
|
{
|
|
ctx.Response.StatusCode = 400;
|
|
await ctx.Response.WriteAsJsonAsync(new { error = "Passwort muss mindestens 4 Zeichen lang sein" });
|
|
return;
|
|
}
|
|
|
|
var user = await db.GetUser(userId);
|
|
if (user == null || !auth.VerifyPassword(currentPassword, user.PasswordHash))
|
|
{
|
|
ctx.Response.StatusCode = 403;
|
|
await ctx.Response.WriteAsJsonAsync(new { error = "Aktuelles Passwort ist falsch" });
|
|
return;
|
|
}
|
|
|
|
var newHash = auth.HashPassword(newPassword);
|
|
await db.UpdateUserPassword(userId, newHash);
|
|
|
|
await ctx.Response.WriteAsJsonAsync(new { ok = true });
|
|
}
|
|
}
|