| File: PathUtil\PathValidator.cs | Web Access |
| Project: src\nuget-client\src\NuGet.Core\NuGet.Common\NuGet.Common.csproj (NuGet.Common) |
// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Text.RegularExpressions; namespace NuGet.Common { public static class PathValidator { /// <summary> /// Validates that a source is a valid path or url. /// </summary> /// <param name="source">The path to validate.</param> /// <returns>True if valid, False if invalid.</returns> public static bool IsValidSource(string source) { if (source is null) { throw new ArgumentNullException(nameof(source)); } return IsValidLocalPath(source) || IsValidUncPath(source) || IsValidUrl(source) || IsValidRelativePath(source); } /// <summary> /// Validates that path is properly formatted as a local path. /// </summary> /// <remarks> /// On Windows, a valid local path must starts with the drive letter. /// Example: C:\, C:\path, C:\path\to\ /// Bad: C:\invalid\*\"\chars /// </remarks> /// <param name="path">The path to validate.</param> /// <returns>True if valid, False if invalid.</returns> [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "We don't want to throw during detection")] public static bool IsValidLocalPath(string path) { if (path is null) { throw new ArgumentNullException(nameof(path)); } try { if (RuntimeEnvironmentHelper.IsWindows) { // Checking driver letter on Windows if (!Regex.IsMatch(path.Trim(), @"^[A-Za-z]:\\")) { return false; } } Path.GetFullPath(path); // If paht is rooted and it's not a unc path, it's a local path. return Path.IsPathRooted(path) && !path.StartsWith(@"\\", StringComparison.Ordinal); } catch { return false; } } /// <summary> /// Validates that path is properly formatted as an UNC path. /// </summary> /// <remarks> /// Example: \\server\share, \\server\share\path, \\server\share\path\to\ /// Bad: \\server\invalid\*\"\chars /// </remarks> /// <param name="path">The path to validate.</param> /// <returns>True if valid, False if invalid.</returns> [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "We don't want to throw during detection")] public static bool IsValidUncPath(string path) { try { _ = Path.GetFullPath(path); return path.StartsWith(@"\\", StringComparison.Ordinal); } catch { return false; } } /// <summary> /// Validates that url is properly formatted as an URL based on .NET <see cref="System.Uri">Uri</see> class. /// </summary> /// <param name="url">The url to validate.</param> /// <returns>True if valid, False if invalid.</returns> [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "0#", Justification = "We're trying to validate that a stirng is infct a uri")] public static bool IsValidUrl(string url) { // Make sure url starts with protocol:// because Uri.TryCreate() returns true for local and UNC paths even if badly formed. return Regex.IsMatch(url, @"^\w+://", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant) && Uri.TryCreate(url, UriKind.Absolute, out _); } public static bool IsValidRelativePath(string path) { try { _ = Path.GetFullPath(path); // Becasue IsPathRooted() returns false for Url path, so if path is not rooted and is not a Url, it's relative path. return !Regex.IsMatch(path, @"^\w+://", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant) && !Path.IsPathRooted(path); } catch { return false; } } } }