mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-20 23:54:26 +08:00
feat.在线安装器,更好的Issue与pull request模板。
This commit is contained in:
129
LanDesktopPLONDS.installer/Services/InstallerPathGuard.cs
Normal file
129
LanDesktopPLONDS.installer/Services/InstallerPathGuard.cs
Normal file
@@ -0,0 +1,129 @@
|
||||
namespace LanDesktopPLONDS.Installer.Services;
|
||||
|
||||
public static class InstallerPathGuard
|
||||
{
|
||||
public static string GetDefaultInstallPath()
|
||||
{
|
||||
var programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
|
||||
if (string.IsNullOrWhiteSpace(programFiles))
|
||||
{
|
||||
programFiles = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
||||
"Programs");
|
||||
}
|
||||
|
||||
return Path.Combine(programFiles, "LanMountainDesktop");
|
||||
}
|
||||
|
||||
public static string NormalizeInstallPath(string path)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
throw new ArgumentException("Installation path is required.", nameof(path));
|
||||
}
|
||||
|
||||
var fullPath = Path.GetFullPath(path.Trim());
|
||||
ValidateInstallPath(fullPath);
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
public static void ValidateInstallPath(string path)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
throw new InvalidOperationException("Installation path is required.");
|
||||
}
|
||||
|
||||
var fullPath = Path.GetFullPath(path);
|
||||
var root = Path.GetPathRoot(fullPath);
|
||||
if (string.Equals(
|
||||
fullPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar),
|
||||
root?.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar),
|
||||
StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new InvalidOperationException("Choose a folder instead of a drive root.");
|
||||
}
|
||||
|
||||
var blockedNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
"Windows",
|
||||
"System32",
|
||||
"SysWOW64",
|
||||
"Program Files",
|
||||
"Program Files (x86)",
|
||||
"Users"
|
||||
};
|
||||
var name = Path.GetFileName(fullPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar));
|
||||
if (blockedNames.Contains(name))
|
||||
{
|
||||
throw new InvalidOperationException("Choose a dedicated application folder.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void EnsureUsableInstallPath(string path, long requiredBytes)
|
||||
{
|
||||
var fullPath = NormalizeInstallPath(path);
|
||||
var directory = Directory.Exists(fullPath)
|
||||
? new DirectoryInfo(fullPath)
|
||||
: Directory.CreateDirectory(fullPath);
|
||||
|
||||
var testPath = Path.Combine(directory.FullName, $".write-test-{Guid.NewGuid():N}.tmp");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(testPath, string.Empty);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (File.Exists(testPath))
|
||||
{
|
||||
File.Delete(testPath);
|
||||
}
|
||||
}
|
||||
|
||||
var drive = new DriveInfo(directory.Root.FullName);
|
||||
if (drive.AvailableFreeSpace > 0 && drive.AvailableFreeSpace < requiredBytes)
|
||||
{
|
||||
throw new InvalidOperationException("The selected drive does not have enough free space.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void EnsureChildPath(string parent, string child)
|
||||
{
|
||||
if (!IsSameOrChildPath(parent, child))
|
||||
{
|
||||
throw new InvalidDataException($"Path escapes the expected root: {child}");
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsSameOrChildPath(string parent, string child)
|
||||
{
|
||||
var resolvedParent = Path.GetFullPath(parent)
|
||||
.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
||||
var resolvedChild = Path.GetFullPath(child);
|
||||
return string.Equals(
|
||||
resolvedParent,
|
||||
resolvedChild.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar),
|
||||
StringComparison.OrdinalIgnoreCase)
|
||||
|| resolvedChild.StartsWith(resolvedParent + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase)
|
||||
|| resolvedChild.StartsWith(resolvedParent + Path.AltDirectorySeparatorChar, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public static string NormalizeRelativePath(string relativePath)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(relativePath))
|
||||
{
|
||||
throw new InvalidDataException("Package entry path is empty.");
|
||||
}
|
||||
|
||||
var normalized = relativePath
|
||||
.Replace('\\', Path.DirectorySeparatorChar)
|
||||
.Replace('/', Path.DirectorySeparatorChar)
|
||||
.TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
||||
if (Path.IsPathRooted(normalized) || normalized.Split(Path.DirectorySeparatorChar).Contains(".."))
|
||||
{
|
||||
throw new InvalidDataException($"Package entry path is invalid: {relativePath}");
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user