|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable
using System.ComponentModel;
using System.Runtime.Versioning;
using Microsoft.Win32.SafeHandles;
namespace Microsoft.DotNet.Cli.Utils.Tests
{
public class DangerousFileDetectorTests : SdkTest
{
private const int REGDB_E_CLASSNOTREG = unchecked((int)0x80040154);
public DangerousFileDetectorTests(ITestOutputHelper log) : base(log)
{
}
#if NETCOREAPP
[SupportedOSPlatform("windows")]
#endif
[WindowsOnlyFact]
public void ItShouldDetectFileWithMarkOfTheWeb()
{
var testFile = Path.Combine(_testAssetsManager.CreateTestDirectory().Path, Path.GetRandomFileName());
File.WriteAllText(testFile, string.Empty);
AlternateStream.WriteAlternateStream(
testFile,
"Zone.Identifier",
"[ZoneTransfer]\r\nZoneId=3\r\nReferrerUrl=C:\\Users\\test.zip\r\n");
bool isTestFileDangerous = new DangerousFileDetector().IsDangerous(testFile);
if (!HasInternetSecurityManagerNativeApi())
{
isTestFileDangerous.Should().BeFalse("Locked down version of Windows does not have IE to download files");
}
else
{
isTestFileDangerous.Should().BeTrue();
}
}
[Fact]
public void WhenThereIsNoFileItReturnsFalse()
{
var testFile = Path.Combine(_testAssetsManager.CreateTestDirectory().Path, Path.GetRandomFileName());
new DangerousFileDetector().IsDangerous(testFile).Should().BeFalse();
}
[UnixOnlyFact]
public void WhenRunOnNonWindowsReturnFalse()
{
var testFile = Path.Combine(_testAssetsManager.CreateTestDirectory().Path, Path.GetRandomFileName());
File.WriteAllText(testFile, string.Empty);
new DangerousFileDetector().IsDangerous(testFile).Should().BeFalse();
}
#if NETCOREAPP
[SupportedOSPlatform("windows")]
#endif
private static bool HasInternetSecurityManagerNativeApi()
{
try
{
string CLSID_InternetSecurityManager = "7b8a2d94-0ac9-11d1-896c-00c04fb6bfc4";
Type iismType = Type.GetTypeFromCLSID(new Guid(CLSID_InternetSecurityManager));
var internetSecurityManager = (IInternetSecurityManager)Activator.CreateInstance(iismType);
return true;
}
catch (COMException ex) when (ex.ErrorCode == REGDB_E_CLASSNOTREG)
{
// When the COM is missing(Class not registered error), it is in a locked down
// version like Nano Server
return false;
}
}
private static class AlternateStream
{
private const uint GenericWrite = 0x40000000;
public static void WriteAlternateStream(string filePath, string altStreamName, string content)
{
if (string.IsNullOrWhiteSpace(filePath))
{
throw new ArgumentException("message", nameof(filePath));
}
if (string.IsNullOrWhiteSpace(altStreamName))
{
throw new ArgumentException("message", nameof(altStreamName));
}
if (content == null)
{
throw new ArgumentNullException(nameof(content));
}
string altStream = filePath + ":" + altStreamName;
SafeFileHandle fileHandle
= CreateFile(
filename: altStream,
desiredAccess: GenericWrite,
shareMode: 0,
attributes: IntPtr.Zero,
creationDisposition: (uint)FileMode.CreateNew,
flagsAndAttributes: 0,
templateFile: IntPtr.Zero);
if (!fileHandle.IsInvalid)
{
using (var streamWriter = new StreamWriter(new FileStream(fileHandle, FileAccess.Write)))
{
streamWriter.WriteLine(content);
streamWriter.Flush();
}
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern SafeFileHandle CreateFile(
string filename,
uint desiredAccess,
uint shareMode,
IntPtr attributes,
uint creationDisposition,
uint flagsAndAttributes,
IntPtr templateFile);
}
}
}
|