- 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
89 lines
3.1 KiB
C#
89 lines
3.1 KiB
C#
using System;
|
|
using System.IO;
|
|
using Gott.Models;
|
|
|
|
namespace Gott.Services;
|
|
|
|
public static class WorkspaceHelper
|
|
{
|
|
/// <summary>
|
|
/// Löst den Workspace-Pfad einer Session auf.
|
|
/// session.Workspace ist relativ zum user.DefaultPath.
|
|
/// Gibt den absoluten Pfad zurück oder null wenn kein Workspace konfiguriert ist.
|
|
/// </summary>
|
|
public static string ResolveWorkspace(SessionRecord session, UserRecord user)
|
|
{
|
|
if (session == null || string.IsNullOrWhiteSpace(session.Workspace))
|
|
return null;
|
|
|
|
var workspace = session.Workspace.Trim();
|
|
|
|
// Wenn der Workspace bereits ein absoluter Pfad ist (Legacy/Fallback)
|
|
if (Path.IsPathRooted(workspace))
|
|
return Path.GetFullPath(workspace);
|
|
|
|
// Relativer Pfad → mit DefaultPath des Users kombinieren
|
|
var basePath = user?.DefaultPath?.Trim();
|
|
if (string.IsNullOrWhiteSpace(basePath))
|
|
return null; // Kein DefaultPath gesetzt → relativer Workspace kann nicht aufgelöst werden
|
|
|
|
var resolved = Path.GetFullPath(Path.Combine(basePath, workspace));
|
|
|
|
// Sicherheit: darf nicht aus dem DefaultPath ausbrechen
|
|
var normalizedBase = Path.GetFullPath(basePath);
|
|
if (!resolved.StartsWith(normalizedBase + Path.DirectorySeparatorChar) && resolved != normalizedBase)
|
|
return null;
|
|
|
|
return resolved;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validiert einen relativen Workspace-Pfad.
|
|
/// Prüft auf Path-Traversal (.. etc.).
|
|
/// Gibt den bereinigten Pfad zurück oder null bei ungültigem Pfad.
|
|
/// </summary>
|
|
public static string ValidateRelativeWorkspace(string workspace)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(workspace))
|
|
return null;
|
|
|
|
var trimmed = workspace.Trim().TrimStart('/').TrimEnd('/');
|
|
if (string.IsNullOrEmpty(trimmed))
|
|
return null;
|
|
|
|
// Path-Traversal verhindern
|
|
if (trimmed.Contains("..") || trimmed.Contains("~"))
|
|
return null;
|
|
|
|
// Keine absoluten Pfade erlauben
|
|
if (Path.IsPathRooted(trimmed))
|
|
return null;
|
|
|
|
return trimmed;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Konvertiert einen absoluten Workspace-Pfad in einen relativen Pfad zum DefaultPath.
|
|
/// Wird beim Speichern verwendet, damit alte absolute Pfade in relative umgewandelt werden.
|
|
/// </summary>
|
|
public static string ToRelativeWorkspace(string absoluteWorkspace, string defaultPath)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(absoluteWorkspace))
|
|
return null;
|
|
|
|
if (string.IsNullOrWhiteSpace(defaultPath))
|
|
return absoluteWorkspace; // Kein DefaultPath → absoluten Pfad beibehalten (Legacy)
|
|
|
|
var normalizedBase = Path.GetFullPath(defaultPath.Trim());
|
|
var normalizedWorkspace = Path.GetFullPath(absoluteWorkspace.Trim());
|
|
|
|
if (normalizedWorkspace.StartsWith(normalizedBase + Path.DirectorySeparatorChar))
|
|
return normalizedWorkspace.Substring(normalizedBase.Length + 1);
|
|
|
|
if (normalizedWorkspace == normalizedBase)
|
|
return "";
|
|
|
|
return absoluteWorkspace; // Außerhalb des DefaultPath → absoluten Pfad beibehalten (Legacy)
|
|
}
|
|
}
|