Files
gott/Services/WorkspaceHelper.cs
T
MelekiandClaude Opus 4.6 4e2815ebd3 fix: Backslash-Support im File-Explorer für Chat und Benutzerverwaltung
WorkspaceHelper gibt native Pfade zurück, Frontend-Logik unterstützt beide Separatoren.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-17 10:41:32 +02:00

122 lines
4.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.IO;
using System.Runtime.InteropServices;
using Gott.Models;
namespace Gott.Services;
public static class WorkspaceHelper
{
/// <summary>True wenn die Plattform Windows ist.</summary>
internal static bool IsWindows => RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
/// <summary>Plattformunabhängiges Temp-Verzeichnis ohne Trailing-Separator.</summary>
internal static string TempDir => Path.GetTempPath().TrimEnd(Path.DirectorySeparatorChar);
/// <summary>
/// Prüft ob ein Pfad ein Sub-Pfad eines Basis-Pfads ist (oder gleich).
/// Auf Windows case-insensitive, auf Linux case-sensitive.
/// </summary>
internal static bool IsSubPathOf(string path, string basePath)
{
var comparison = IsWindows ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
var normalizedPath = Path.GetFullPath(path);
var normalizedBase = Path.GetFullPath(basePath);
return normalizedPath.Equals(normalizedBase, comparison)
|| normalizedPath.StartsWith(normalizedBase + Path.DirectorySeparatorChar, comparison);
}
/// <summary>
/// Gibt den relativen Pfad zurück – mit nativen Separatoren (Backslash auf Windows, / auf Linux).
/// </summary>
internal static string GetRelativePath(string relativeTo, string path)
{
return Path.GetRelativePath(relativeTo, path);
}
/// <summary>
/// Gibt den Shell-Dateinamen zurück (cmd.exe auf Windows, /bin/bash auf Linux).
/// </summary>
internal static string ShellExecutable => IsWindows ? "cmd.exe" : "/bin/bash";
/// <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
if (!IsSubPathOf(resolved, Path.GetFullPath(basePath)))
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());
var comparison = IsWindows ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
if (normalizedWorkspace.StartsWith(normalizedBase + Path.DirectorySeparatorChar, comparison))
return normalizedWorkspace.Substring(normalizedBase.Length + 1);
if (normalizedWorkspace.Equals(normalizedBase, comparison))
return "";
return absoluteWorkspace; // Außerhalb des DefaultPath → absoluten Pfad beibehalten (Legacy)
}
}