30 lines
1.4 KiB
C#
30 lines
1.4 KiB
C#
using System.Text.RegularExpressions;
|
|
|
|
namespace ClaudeDo.Data.Models;
|
|
|
|
/// <summary>A server an interactive claude session can be started on via ssh; connection details live in the user's ssh config.</summary>
|
|
public sealed record SshWorkspace(string Id, string Name, string Host, string RemotePath)
|
|
{
|
|
// A leading '-' would make ssh parse the alias as an option (-oProxyCommand=... runs local code).
|
|
private static readonly Regex HostPattern = new(@"^[A-Za-z0-9._@][A-Za-z0-9._@-]*$", RegexOptions.Compiled);
|
|
|
|
/// <summary>Returns the first invalid field ("name", "host", "path") or null when valid.</summary>
|
|
public static string? Validate(SshWorkspace w)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(w.Name)) return "name";
|
|
if (string.IsNullOrEmpty(w.Host) || !HostPattern.IsMatch(w.Host)) return "host";
|
|
var p = w.RemotePath ?? "";
|
|
if (!(p.StartsWith('/') || p.StartsWith('~')) || p.Contains('\'') || p.Contains('\n') || p.Contains('\r'))
|
|
return "path";
|
|
return null;
|
|
}
|
|
|
|
/// <summary>Single-quotes a validated remote path for a POSIX shell, leaving a leading <c>~</c> unquoted so it still expands.</summary>
|
|
public static string QuoteRemotePath(string path)
|
|
{
|
|
if (path == "~") return "~";
|
|
if (path.StartsWith("~/")) return "~/'" + path[2..] + "'";
|
|
return "'" + path + "'";
|
|
}
|
|
}
|