This commit is contained in:
Eilon Lipton 2014-12-22 15:17:14 -08:00
Родитель 1d16433435
Коммит c8b8b1fe47
27 изменённых файлов: 1219 добавлений и 42 удалений

66
.gitignore поставляемый
Просмотреть файл

@ -1,43 +1,25 @@
# Windows image file caches
Thumbs.db
ehthumbs.db
*.ide
[Oo]bj/
[Bb]in/
TestResults/
.nuget/
_ReSharper.*/
/packages
artifacts/
PublishProfiles/
*.user
*.suo
*.cache
*.docstates
_ReSharper.*
nuget.exe
*.psess
*.vsp
*.pidb
*.userprefs
*DS_Store
*.ncrunchsolution
*.*sdf
*.ipch
/*.vspx
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Windows shortcuts
*.lnk
# =========================
# Operating System Files
# =========================
# OSX
# =========================
.DS_Store
.AppleDouble
.LSOverride
# Thumbnails
._*
# Files that might appear on external disk
.Spotlight-V100
.Trashes
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk

22
NuGetPackageVerifier.sln Normal file
Просмотреть файл

@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.22310.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NuGetPackageVerifier", "NuGetPackageVerifier\NuGetPackageVerifier.csproj", "{2ED95FF6-1941-4053-99CE-F9748048762C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2ED95FF6-1941-4053-99CE-F9748048762C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2ED95FF6-1941-4053-99CE-F9748048762C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2ED95FF6-1941-4053-99CE-F9748048762C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2ED95FF6-1941-4053-99CE-F9748048762C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

Просмотреть файл

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/>
</startup>
</configuration>

Просмотреть файл

@ -0,0 +1,39 @@
using NuGet;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using NuGetPackageVerifier.Logging;
namespace NuGetPackageVerifier
{
public class AssemblyHasDocumentFileRule : IPackageVerifierRule
{
public IEnumerable<MyPackageIssue> Validate(IPackageRepository packageRepo, IPackage package, IPackageVerifierLogger logger)
{
if (!package.IsSatellitePackage())
{
IEnumerable<string> allXmlFiles =
from file in package.GetLibFiles()
select file.Path into path
where path.EndsWith(".xml", StringComparison.OrdinalIgnoreCase)
select path;
foreach (IPackageFile current in package.GetLibFiles())
{
string assemblyPath = current.Path;
// TODO: Does this need to check for just managed code?
if (assemblyPath.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
{
string docFilePath = Path.ChangeExtension(assemblyPath, ".xml");
if (!allXmlFiles.Contains(docFilePath, StringComparer.OrdinalIgnoreCase))
{
yield return PackageIssueFactory.AssemblyHasNoDocFile(assemblyPath);
}
}
}
}
yield break;
}
}
}

Просмотреть файл

@ -0,0 +1,181 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using NuGet;
using NuGetPackageVerifier.Logging;
namespace NuGetPackageVerifier
{
public class AssemblyStrongNameRule : IPackageVerifierRule
{
public IEnumerable<MyPackageIssue> Validate(IPackageRepository packageRepo, IPackage package, IPackageVerifierLogger logger)
{
foreach (IPackageFile currentFile in package.GetFiles())
{
string extension = Path.GetExtension(currentFile.Path);
if (extension.Equals(".dll", StringComparison.OrdinalIgnoreCase) ||
extension.Equals(".exe", StringComparison.OrdinalIgnoreCase))
{
string assemblyPath = Path.ChangeExtension(Path.Combine(Path.GetTempPath(), Path.GetTempFileName()), extension);
var isManagedCode = false;
var isStrongNameSigned = false;
int hresult = 0;
try
{
using (Stream packageFileStream = currentFile.GetStream())
{
var _assemblyBytes = new byte[packageFileStream.Length];
packageFileStream.Read(_assemblyBytes, 0, _assemblyBytes.Length);
using (var fileStream = new FileStream(assemblyPath, FileMode.Create))
{
packageFileStream.Seek(0, SeekOrigin.Begin);
packageFileStream.CopyTo(fileStream);
fileStream.Flush(true);
}
if (IsAssemblyManaged(assemblyPath))
{
isManagedCode = true;
var clrStrongName = (IClrStrongName)RuntimeEnvironment.GetRuntimeInterfaceAsObject(new Guid("B79B0ACD-F5CD-409b-B5A5-A16244610B92"), new Guid("9FD93CCF-3280-4391-B3A9-96E1CDE77C8D"));
bool verificationForced;
hresult = clrStrongName.StrongNameSignatureVerificationEx(assemblyPath, true, out verificationForced);
if (hresult == 0)
{
isStrongNameSigned = true;
}
}
}
}
catch (Exception ex)
{
logger.LogError("Error while verifying strong name signature for {0}: {1}", currentFile.Path, ex.Message);
}
finally
{
if (File.Exists(assemblyPath))
{
File.Delete(assemblyPath);
}
}
if (isManagedCode && !isStrongNameSigned)
{
yield return PackageIssueFactory.AssemblyNotStrongNameSigned(currentFile.Path, hresult);
}
}
}
yield break;
}
private static bool IsAssemblyManaged(string assemblyPath)
{
// From http://msdn.microsoft.com/en-us/library/ms173100.aspx
try
{
var testAssembly = AssemblyName.GetAssemblyName(assemblyPath);
return true;
}
catch (FileNotFoundException)
{
// The file cannot be found
}
catch (BadImageFormatException)
{
// The file is not an assembly
}
catch (FileLoadException)
{
// The assembly has already been loaded
}
return false;
}
[ComConversionLoss, Guid("9FD93CCF-3280-4391-B3A9-96E1CDE77C8D"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComImport]
internal interface IClrStrongName
{
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
int GetHashFromAssemblyFile([MarshalAs(UnmanagedType.LPStr)] [In] string pszFilePath, [MarshalAs(UnmanagedType.U4)] [In] [Out] ref int piHashAlg, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] [Out] byte[] pbHash, [MarshalAs(UnmanagedType.U4)] [In] int cchHash, [MarshalAs(UnmanagedType.U4)] out int pchHash);
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
int GetHashFromAssemblyFileW([MarshalAs(UnmanagedType.LPWStr)] [In] string pwzFilePath, [MarshalAs(UnmanagedType.U4)] [In] [Out] ref int piHashAlg, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] [Out] byte[] pbHash, [MarshalAs(UnmanagedType.U4)] [In] int cchHash, [MarshalAs(UnmanagedType.U4)] out int pchHash);
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
int GetHashFromBlob([In] IntPtr pbBlob, [MarshalAs(UnmanagedType.U4)] [In] int cchBlob, [MarshalAs(UnmanagedType.U4)] [In] [Out] ref int piHashAlg, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] [Out] byte[] pbHash, [MarshalAs(UnmanagedType.U4)] [In] int cchHash, [MarshalAs(UnmanagedType.U4)] out int pchHash);
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
int GetHashFromFile([MarshalAs(UnmanagedType.LPStr)] [In] string pszFilePath, [MarshalAs(UnmanagedType.U4)] [In] [Out] ref int piHashAlg, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] [Out] byte[] pbHash, [MarshalAs(UnmanagedType.U4)] [In] int cchHash, [MarshalAs(UnmanagedType.U4)] out int pchHash);
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
int GetHashFromFileW([MarshalAs(UnmanagedType.LPWStr)] [In] string pwzFilePath, [MarshalAs(UnmanagedType.U4)] [In] [Out] ref int piHashAlg, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] [Out] byte[] pbHash, [MarshalAs(UnmanagedType.U4)] [In] int cchHash, [MarshalAs(UnmanagedType.U4)] out int pchHash);
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
int GetHashFromHandle([In] IntPtr hFile, [MarshalAs(UnmanagedType.U4)] [In] [Out] ref int piHashAlg, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] [Out] byte[] pbHash, [MarshalAs(UnmanagedType.U4)] [In] int cchHash, [MarshalAs(UnmanagedType.U4)] out int pchHash);
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
[return: MarshalAs(UnmanagedType.U4)]
int StrongNameCompareAssemblies([MarshalAs(UnmanagedType.LPWStr)] [In] string pwzAssembly1, [MarshalAs(UnmanagedType.LPWStr)] [In] string pwzAssembly2, [MarshalAs(UnmanagedType.U4)] out int dwResult);
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
int StrongNameFreeBuffer([In] IntPtr pbMemory);
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
int StrongNameGetBlob([MarshalAs(UnmanagedType.LPWStr)] [In] string pwzFilePath, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] [Out] byte[] pbBlob, [MarshalAs(UnmanagedType.U4)] [In] [Out] ref int pcbBlob);
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
int StrongNameGetBlobFromImage([In] IntPtr pbBase, [MarshalAs(UnmanagedType.U4)] [In] int dwLength, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] [Out] byte[] pbBlob, [MarshalAs(UnmanagedType.U4)] [In] [Out] ref int pcbBlob);
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
int StrongNameGetPublicKey([MarshalAs(UnmanagedType.LPWStr)] [In] string pwzKeyContainer, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] [In] byte[] pbKeyBlob, [MarshalAs(UnmanagedType.U4)] [In] int cbKeyBlob, out IntPtr ppbPublicKeyBlob, [MarshalAs(UnmanagedType.U4)] out int pcbPublicKeyBlob);
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
[return: MarshalAs(UnmanagedType.U4)]
int StrongNameHashSize([MarshalAs(UnmanagedType.U4)] [In] int ulHashAlg, [MarshalAs(UnmanagedType.U4)] out int cbSize);
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
int StrongNameKeyDelete([MarshalAs(UnmanagedType.LPWStr)] [In] string pwzKeyContainer);
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
int StrongNameKeyGen([MarshalAs(UnmanagedType.LPWStr)] [In] string pwzKeyContainer, [MarshalAs(UnmanagedType.U4)] [In] int dwFlags, out IntPtr ppbKeyBlob, [MarshalAs(UnmanagedType.U4)] out int pcbKeyBlob);
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
int StrongNameKeyGenEx([MarshalAs(UnmanagedType.LPWStr)] [In] string pwzKeyContainer, [MarshalAs(UnmanagedType.U4)] [In] int dwFlags, [MarshalAs(UnmanagedType.U4)] [In] int dwKeySize, out IntPtr ppbKeyBlob, [MarshalAs(UnmanagedType.U4)] out int pcbKeyBlob);
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
int StrongNameKeyInstall([MarshalAs(UnmanagedType.LPWStr)] [In] string pwzKeyContainer, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] [In] byte[] pbKeyBlob, [MarshalAs(UnmanagedType.U4)] [In] int cbKeyBlob);
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
int StrongNameSignatureGeneration([MarshalAs(UnmanagedType.LPWStr)] [In] string pwzFilePath, [MarshalAs(UnmanagedType.LPWStr)] [In] string pwzKeyContainer, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] [In] byte[] pbKeyBlob, [MarshalAs(UnmanagedType.U4)] [In] int cbKeyBlob, [In] [Out] IntPtr ppbSignatureBlob, [MarshalAs(UnmanagedType.U4)] out int pcbSignatureBlob);
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
int StrongNameSignatureGenerationEx([MarshalAs(UnmanagedType.LPWStr)] [In] string wszFilePath, [MarshalAs(UnmanagedType.LPWStr)] [In] string wszKeyContainer, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] [In] byte[] pbKeyBlob, [MarshalAs(UnmanagedType.U4)] [In] int cbKeyBlob, [In] [Out] IntPtr ppbSignatureBlob, [MarshalAs(UnmanagedType.U4)] out int pcbSignatureBlob, [MarshalAs(UnmanagedType.U4)] [In] int dwFlags);
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
int StrongNameSignatureSize([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] [In] byte[] pbPublicKeyBlob, [MarshalAs(UnmanagedType.U4)] [In] int cbPublicKeyBlob, [MarshalAs(UnmanagedType.U4)] out int pcbSize);
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
[return: MarshalAs(UnmanagedType.U4)]
int StrongNameSignatureVerification([MarshalAs(UnmanagedType.LPWStr)] [In] string pwzFilePath, [MarshalAs(UnmanagedType.U4)] [In] int dwInFlags, [MarshalAs(UnmanagedType.U4)] out int dwOutFlags);
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
[return: MarshalAs(UnmanagedType.U4)]
int StrongNameSignatureVerificationEx([MarshalAs(UnmanagedType.LPWStr)] [In] string pwzFilePath, [MarshalAs(UnmanagedType.I1)] [In] bool fForceVerification, [MarshalAs(UnmanagedType.I1)] out bool fWasVerified);
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
[return: MarshalAs(UnmanagedType.U4)]
int StrongNameSignatureVerificationFromImage([In] IntPtr pbBase, [MarshalAs(UnmanagedType.U4)] [In] int dwLength, [MarshalAs(UnmanagedType.U4)] [In] int dwInFlags, [MarshalAs(UnmanagedType.U4)] out int dwOutFlags);
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
int StrongNameTokenFromAssembly([MarshalAs(UnmanagedType.LPWStr)] [In] string pwzFilePath, out IntPtr ppbStrongNameToken, [MarshalAs(UnmanagedType.U4)] out int pcbStrongNameToken);
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
int StrongNameTokenFromAssemblyEx([MarshalAs(UnmanagedType.LPWStr)] [In] string pwzFilePath, out IntPtr ppbStrongNameToken, [MarshalAs(UnmanagedType.U4)] out int pcbStrongNameToken, out IntPtr ppbPublicKeyBlob, [MarshalAs(UnmanagedType.U4)] out int pcbPublicKeyBlob);
[MethodImpl(MethodImplOptions.PreserveSig | MethodImplOptions.InternalCall)]
int StrongNameTokenFromPublicKey([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] [In] byte[] pbPublicKeyBlob, [MarshalAs(UnmanagedType.U4)] [In] int cbPublicKeyBlob, out IntPtr ppbStrongNameToken, [MarshalAs(UnmanagedType.U4)] out int pcbStrongNameToken);
}
}
}

Просмотреть файл

@ -0,0 +1,82 @@
using NuGet;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using NuGetPackageVerifier.Logging;
namespace NuGetPackageVerifier
{
public class AuthenticodeSigningRule : IPackageVerifierRule
{
public IEnumerable<MyPackageIssue> Validate(IPackageRepository packageRepo, IPackage package, IPackageVerifierLogger logger)
{
string packagePath = packageRepo.Source + "\\" + package.Id + "." + package.Version.ToString() + ".nupkg";
string nupkgWithoutExt = Path.Combine(Path.GetDirectoryName(packagePath), Path.GetFileNameWithoutExtension(packagePath));
try
{
UnzipPackage(nupkgWithoutExt);
foreach (IPackageFile current in package.GetFiles())
{
//string packagePath = package.FileSystem.Root + "\\" + Id + "." + Version + ".nupkg"
string extension = Path.GetExtension(current.Path);
// TODO: Need to add more extensions?
if (extension.Equals(".dll", StringComparison.OrdinalIgnoreCase) ||
extension.Equals(".exe", StringComparison.OrdinalIgnoreCase))
{
string pathOfFileToScan = Path.Combine(nupkgWithoutExt, current.Path);
var realAssemblyPath = pathOfFileToScan;
if (!File.Exists(realAssemblyPath))
{
realAssemblyPath = pathOfFileToScan.Replace("+", "%2B");
if (!File.Exists(realAssemblyPath))
{
logger.LogError("The assembly '{0}' in this package can't be found (a bug in this tool, most likely).", current.Path);
continue;
}
}
bool isAuthenticodeSigned = WinTrust.IsAuthenticodeSigned(realAssemblyPath);
if (!isAuthenticodeSigned)
{
yield return PackageIssueFactory.PEFileNotAuthenticodeSigned(current.Path);
}
}
}
}
finally
{
CleanUpFolder(nupkgWithoutExt, logger);
}
yield break;
}
private void UnzipPackage(string path)
{
if (Directory.Exists(path))
{
Directory.Delete(path, recursive: true);
}
Directory.CreateDirectory(path);
ZipFile.ExtractToDirectory(path + ".nupkg", path);
}
private void CleanUpFolder(string path, IPackageVerifierLogger logger)
{
try
{
if (Directory.Exists(path))
{
Directory.Delete(path, recursive: true);
}
}
catch (Exception ex)
{
logger.LogWarning("Couldn't clean temp unzip folder: " + ex.Message);
}
}
}
}

Просмотреть файл

@ -0,0 +1,12 @@
using System.Collections.Generic;
using NuGet;
using NuGetPackageVerifier.Logging;
namespace NuGetPackageVerifier
{
public interface IPackageVerifierRule
{
IEnumerable<MyPackageIssue> Validate(IPackageRepository packageRepo, IPackage package, IPackageVerifierLogger logger);
}
}

Просмотреть файл

@ -0,0 +1,10 @@
namespace NuGetPackageVerifier
{
public class IssueIgnore
{
public string PackageId { get; set; }
public string IssueId { get; set; }
public string Instance { get; set; }
public string Justification { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NuGet;
namespace NuGetPackageVerifier
{
public class IssueProcessor
{
public IssueProcessor(IEnumerable<IssueIgnore> issuesToIgnore)
{
IssuesToIgnore = issuesToIgnore;
}
public IEnumerable<IssueIgnore> IssuesToIgnore
{
get;
private set;
}
public IssueReport GetIssueReport(MyPackageIssue packageIssue, IPackage package)
{
var ignoredRules = IssuesToIgnore.Where(
issueIgnore =>
string.Equals(issueIgnore.IssueId, packageIssue.IssueId, StringComparison.OrdinalIgnoreCase) &&
string.Equals(issueIgnore.Instance, packageIssue.Instance, StringComparison.OrdinalIgnoreCase) &&
string.Equals(issueIgnore.PackageId, package.Id, StringComparison.OrdinalIgnoreCase));
var firstIgnoreRule = ignoredRules.FirstOrDefault();
return new IssueReport(packageIssue, firstIgnoreRule != null, firstIgnoreRule?.Justification);
}
}
}

Просмотреть файл

@ -0,0 +1,20 @@
using NuGetPackageVerifier.Logging;
namespace NuGetPackageVerifier
{
public class IssueReport
{
public IssueReport(MyPackageIssue packageIssue, bool ignore, string ignoreJustification)
{
PackageIssue = packageIssue;
IssueLevel = ignore ? LogLevel.Info : packageIssue.Level == MyPackageIssueLevel.Warning ? LogLevel.Warning : LogLevel.Error;
IgnoreJustification = ignoreJustification;
}
public MyPackageIssue PackageIssue { get; private set; }
public LogLevel IssueLevel { get; private set; }
public string IgnoreJustification { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,7 @@
namespace NuGetPackageVerifier.Logging
{
public interface IPackageVerifierLogger
{
void Log(LogLevel logLevel, string message);
}
}

Просмотреть файл

@ -0,0 +1,9 @@
namespace NuGetPackageVerifier.Logging
{
public enum LogLevel
{
Info,
Warning,
Error,
}
}

Просмотреть файл

@ -0,0 +1,30 @@
using System;
namespace NuGetPackageVerifier.Logging
{
public class PackageVerifierLogger : IPackageVerifierLogger
{
public void Log(LogLevel logLevel, string message)
{
ConsoleColor foreColor;
switch (logLevel)
{
case LogLevel.Error:
foreColor = ConsoleColor.Red;
break;
case LogLevel.Warning:
foreColor = ConsoleColor.Yellow;
break;
default:
case LogLevel.Info:
foreColor = ConsoleColor.Gray;
break;
}
Console.ForegroundColor = foreColor;
Console.WriteLine("{0}: {1}", logLevel.ToString().ToUpperInvariant(), message);
Console.ForegroundColor = ConsoleColor.Gray;
}
}
}

Просмотреть файл

@ -0,0 +1,25 @@
namespace NuGetPackageVerifier.Logging
{
public static class PackageVerifierLoggerExtensions
{
public static void Log(this IPackageVerifierLogger logger, LogLevel logLevel, string message, params object[] args)
{
logger.Log(logLevel, string.Format(message, args));
}
public static void LogWarning(this IPackageVerifierLogger logger, string message, params object[] args)
{
logger.Log(LogLevel.Warning, message, args);
}
public static void LogError(this IPackageVerifierLogger logger, string message, params object[] args)
{
logger.Log(LogLevel.Error, message, args);
}
public static void LogInfo(this IPackageVerifierLogger logger, string message, params object[] args)
{
logger.Log(LogLevel.Info, message, args);
}
}
}

Просмотреть файл

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{2ED95FF6-1941-4053-99CE-F9748048762C}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>NuGetPackageVerifier</RootNamespace>
<AssemblyName>NuGetPackageVerifier</AssemblyName>
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Web.XmlTransform">
<HintPath>..\packages\Microsoft.Web.Xdt.2.1.0\lib\net40\Microsoft.Web.XmlTransform.dll</HintPath>
</Reference>
<Reference Include="NuGet.Core, Version=2.8.50926.602, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\NuGet.Core.2.8.3\lib\net40-Client\NuGet.Core.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Logging\PackageVerifierLoggerExtensions.cs" />
<Compile Include="Logging\PackageVerifierLogger.cs" />
<Compile Include="Logging\IPackageVerifierLogger.cs" />
<Compile Include="Logging\LogLevel.cs" />
<Compile Include="PackageAnalyzer.cs" />
<Compile Include="AssemblyHasDocumentFileRule.cs" />
<Compile Include="AssemblyStrongNameRule.cs" />
<Compile Include="AuthenticodeSigningRule.cs" />
<Compile Include="PackageIssueFactory.cs" />
<Compile Include="IssueIgnore.cs" />
<Compile Include="IssueProcessor.cs" />
<Compile Include="IssueReport.cs" />
<Compile Include="StrictSemanticVersionValidationRule.cs" />
<Compile Include="PowerShellScriptIsSignedRule.cs" />
<Compile Include="PackageIssue.cs" />
<Compile Include="PackageIssueLevel.cs" />
<Compile Include="IPackageVerifierRule.cs" />
<Compile Include="RequiredAttributesRule.cs" />
<Compile Include="SatellitePackageRule.cs" />
<Compile Include="WinTrust.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Просмотреть файл

@ -0,0 +1,31 @@
using System.Collections.Generic;
using System.Linq;
using NuGet;
using NuGetPackageVerifier.Logging;
namespace NuGetPackageVerifier
{
public class PackageAnalyzer
{
private IList<IPackageVerifierRule> _rules = new List<IPackageVerifierRule>();
public IList<IPackageVerifierRule> Rules
{
get
{
return _rules;
}
}
public IEnumerable<MyPackageIssue> AnalyzePackage(IPackageRepository packageRepo, IPackage package, IPackageVerifierLogger logger)
{
IEnumerable<MyPackageIssue> packageIssues = new List<MyPackageIssue>();
foreach (var rule in Rules)
{
var issues = rule.Validate(packageRepo, package, logger).ToList();
packageIssues = packageIssues.Concat(issues);
}
return packageIssues;
}
}
}

Просмотреть файл

@ -0,0 +1,45 @@
namespace NuGetPackageVerifier
{
public class MyPackageIssue
{
public MyPackageIssue(string issueId, string issue, MyPackageIssueLevel level)
: this(issueId, instance: null, issue: issue, level: level)
{
}
public MyPackageIssue(string issueId, string instance, string issue, MyPackageIssueLevel level)
{
Instance = instance;
IssueId = issueId;
Issue = issue;
Level = level;
}
public MyPackageIssueLevel Level
{
get;
private set;
}
public string Issue
{
get;
private set;
}
public string IssueId
{
get; private set;
}
public string Instance
{
get; set;
}
public override string ToString()
{
return string.Format("{0} @ {1}: {2}: {3}", IssueId, Instance, Level.ToString().ToUpperInvariant(), Issue);
}
}
}

Просмотреть файл

@ -0,0 +1,94 @@
using NuGet;
namespace NuGetPackageVerifier
{
public static class PackageIssueFactory
{
public static MyPackageIssue AssemblyNotStrongNameSigned(string assemblyPath, int hResult)
{
// TODO: Translate common HRESULTS http://blogs.msdn.com/b/yizhang/
return new MyPackageIssue("SIGN_STRONGNAME", assemblyPath, string.Format("The managed assembly '{0}' in this package is either not signed or is delay signed. HRESULT=0x{1:X}", assemblyPath, hResult), MyPackageIssueLevel.Error);
}
public static MyPackageIssue NotSemanticVersion(SemanticVersion version)
{
return new MyPackageIssue("VERSION_NOTSEMANTIC",
string.Format("Version '{0}' does not follow semantic versioning guidelines.", version), MyPackageIssueLevel.Error);
}
public static MyPackageIssue Satellite_PackageSummaryNotLocalized()
{
return new MyPackageIssue("LOC_SUMMARY", "Package summary is not localized correctly", MyPackageIssueLevel.Error);
}
public static MyPackageIssue Satellite_PackageTitleNotLocalized()
{
return new MyPackageIssue("LOC_TITLE", "Package title is not localized correctly", MyPackageIssueLevel.Error);
}
public static MyPackageIssue Satellite_PackageDescriptionNotLocalized()
{
return new MyPackageIssue("LOC_DESC", "Package description is not localized correctly", MyPackageIssueLevel.Error);
}
public static MyPackageIssue RequiredCopyright()
{
return RequiredCore("NUSPEC_COPYRIGHT", "Copyright", MyPackageIssueLevel.Error);
}
public static MyPackageIssue RequiredLicenseUrl()
{
return RequiredCore("NUSPEC_LICENSEURL", "License Url", MyPackageIssueLevel.Error);
}
public static MyPackageIssue RequiredIconUrl()
{
return RequiredCore("NUSPEC_ICONURL", "Icon Url", MyPackageIssueLevel.Warning);
}
public static MyPackageIssue RequiredTags()
{
return RequiredCore("NUSPEC_TAGS", "Tags", MyPackageIssueLevel.Warning);
}
public static MyPackageIssue RequiredTitle()
{
return RequiredCore("NUSPEC_TITLE", "Title", MyPackageIssueLevel.Error);
}
public static MyPackageIssue RequiredSummary()
{
return RequiredCore("NUSPEC_SUMMARY", "Summary", MyPackageIssueLevel.Warning);
}
public static MyPackageIssue RequiredProjectUrl()
{
return RequiredCore("NUSPEC_PROJECTURL", "Project Url", MyPackageIssueLevel.Warning);
}
public static MyPackageIssue RequiredRequireLicenseAcceptanceTrue()
{
return new MyPackageIssue("NUSPEC_ACCEPTLICENSE", string.Format("NuSpec Require License Acceptance is not set to true"), MyPackageIssueLevel.Error);
}
private static MyPackageIssue RequiredCore(string issueId, string attributeName, MyPackageIssueLevel issueLevel)
{
return new MyPackageIssue(issueId, string.Format("NuSpec {0} attribute is missing", attributeName), issueLevel);
}
public static MyPackageIssue PowerShellScriptNotSigned(string scriptPath)
{
return new MyPackageIssue("SIGN_POWERSHELL", scriptPath, string.Format("The PowerShell script '{0}' is not signed.", scriptPath), MyPackageIssueLevel.Error);
}
public static MyPackageIssue PEFileNotAuthenticodeSigned(string assemblyPath)
{
return new MyPackageIssue("SIGN_AUTHENTICODE", assemblyPath, string.Format("The PE file '{0}' in this package is not authenticode signed.", assemblyPath), MyPackageIssueLevel.Error);
}
public static MyPackageIssue AssemblyHasNoDocFile(string assemblyPath)
{
return new MyPackageIssue("DOC_MISSING", assemblyPath, string.Format("The assembly '{0}' doesn't have a corresponding XML document file.", assemblyPath), MyPackageIssueLevel.Warning);
}
}
}

Просмотреть файл

@ -0,0 +1,8 @@
namespace NuGetPackageVerifier
{
public enum MyPackageIssueLevel
{
Warning,
Error
}
}

Просмотреть файл

@ -0,0 +1,48 @@
using NuGet;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using NuGetPackageVerifier.Logging;
namespace NuGetPackageVerifier
{
public class PowerShellScriptIsSignedRule : IPackageVerifierRule
{
private static readonly string[] PowerShellExtensions = new string[]
{
".ps1",
".psm1",
".psd1",
".ps1xml"
};
public IEnumerable<MyPackageIssue> Validate(IPackageRepository packageRepo, IPackage package, IPackageVerifierLogger logger)
{
foreach (IPackageFile current in package.GetFiles())
{
string extension = Path.GetExtension(current.Path);
if (PowerShellScriptIsSignedRule.PowerShellExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
{
if (!VerifySigned(current))
{
yield return PackageIssueFactory.PowerShellScriptNotSigned(current.Path);
}
}
}
yield break;
}
private static bool VerifySigned(IPackageFile packageFile)
{
bool result;
using (Stream stream = packageFile.GetStream())
{
System.IO.StreamReader streamReader = new System.IO.StreamReader(stream);
string text = streamReader.ReadToEnd();
result = (text.IndexOf("# SIG # Begin signature block", StringComparison.OrdinalIgnoreCase) > -1 && text.IndexOf("# SIG # End signature block", StringComparison.OrdinalIgnoreCase) > -1);
}
return result;
}
}
}

Просмотреть файл

@ -0,0 +1,131 @@
using System;
using System.Diagnostics;
using System.Linq;
using NuGet;
using NuGetPackageVerifier.Logging;
namespace NuGetPackageVerifier
{
public static class Program
{
private const int ReturnOk = 0;
private const int ReturnBadArgs = 1;
private const int ReturnErrorsOrWarnings = 2;
public static int Main(string[] args)
{
// TODO: Take a switch saying whether to use TeamCity logger
// TODO: Add a way to read ignores from file
if (args.Length != 1)
{
Console.WriteLine(@"USAGE: NuGetSuperBVT.exe c:\path\to\packages");
return ReturnBadArgs;
}
var totalTimeStopWatch = Stopwatch.StartNew();
var nupkgsPath = args[0];
var issuesToIgnore = new[]
{
new IssueIgnore { IssueId = "NUSPEC_TAGS", Instance = null, PackageId = "EntityFramework", Justification = "Because no tags" },
new IssueIgnore { IssueId = "NUSPEC_SUMMARY", Instance = null, PackageId = "EntityFramework", Justification = "Because no summary" },
new IssueIgnore { IssueId = "XYZ", Instance = "ZZZ", PackageId = "ABC", Justification = "Because" },
new IssueIgnore { IssueId = "XYZ", Instance = "ZZZ", PackageId = "ABC", Justification = "Because" },
new IssueIgnore { IssueId = "XYZ", Instance = "ZZZ", PackageId = "ABC", Justification = "Because" },
new IssueIgnore { IssueId = "XYZ", Instance = "ZZZ", PackageId = "ABC", Justification = "Because" },
};
var issueProcessor = new IssueProcessor(issuesToIgnore);
var analyzer = new PackageAnalyzer();
analyzer.Rules.Add(new AssemblyHasDocumentFileRule());
analyzer.Rules.Add(new AssemblyStrongNameRule());
analyzer.Rules.Add(new AuthenticodeSigningRule());
analyzer.Rules.Add(new PowerShellScriptIsSignedRule());
analyzer.Rules.Add(new RequiredAttributesRule());
analyzer.Rules.Add(new SatellitePackageRule());
analyzer.Rules.Add(new StrictSemanticVersionValidationRule());
var logger = new PackageVerifierLogger();
// TODO: Switch this to a custom IFileSystem that has only the packages we want (maybe?)
var localPackageRepo = new LocalPackageRepository(nupkgsPath);
var numPackagesInRepo = localPackageRepo.GetPackages().Count();
logger.LogInfo("Found {0} packages in {1}", numPackagesInRepo, nupkgsPath);
bool anyErrorOrWarnings = false;
foreach (var package in localPackageRepo.GetPackages())
{
var packageTimeStopWatch = Stopwatch.StartNew();
logger.LogInfo("Analyzing {0} ({1})", package.Id, package.Version);
var issues = analyzer.AnalyzePackage(localPackageRepo, package, logger).ToList();
var issuesToReport = issues.Select(issue => issueProcessor.GetIssueReport(issue, package)).ToList();
if (issuesToReport.Count > 0)
{
var infos = issuesToReport.Where(issueReport => issueReport.IssueLevel == LogLevel.Info).ToList();
var warnings = issuesToReport.Where(issueReport => issueReport.IssueLevel == LogLevel.Warning).ToList();
var errors = issuesToReport.Where(issueReport => issueReport.IssueLevel == LogLevel.Error).ToList();
LogLevel errorLevel = LogLevel.Info;
if (warnings.Count > 0)
{
errorLevel = LogLevel.Warning;
anyErrorOrWarnings = true;
}
if (errors.Count > 0)
{
errorLevel = LogLevel.Error;
anyErrorOrWarnings = true;
}
logger.Log(
errorLevel,
"{0} error(s), {1} warning(s), and {2} info(s) found with package {3} ({4})",
errors.Count, warnings.Count, infos.Count, package.Id, package.Version);
foreach (var current in issuesToReport)
{
PrintPackageIssue(logger, current);
}
}
else
{
logger.LogInfo("No issues found with package {0}", package.Id, package.Version);
}
packageTimeStopWatch.Stop();
logger.LogInfo("Took {0}ms", packageTimeStopWatch.ElapsedMilliseconds);
Console.WriteLine();
}
totalTimeStopWatch.Stop();
logger.LogInfo("Total took {0}ms", totalTimeStopWatch.ElapsedMilliseconds);
return anyErrorOrWarnings ? ReturnErrorsOrWarnings : ReturnOk;
}
private static void PrintPackageIssue(IPackageVerifierLogger logger, IssueReport issue)
{
// TODO: Support this: https://confluence.jetbrains.com/display/TCD8/Build+Script+Interaction+with+TeamCity
var issueInfo = issue.PackageIssue.IssueId;
if (issue.PackageIssue.Instance == null)
{
issueInfo += " @ " + issue.PackageIssue.Instance;
}
logger.Log(issue.IssueLevel, "{0}: {1}", issueInfo, issue.PackageIssue.Issue);
if (issue.IgnoreJustification != null)
{
logger.Log(issue.IssueLevel, "Justification: {0}", issue.IgnoreJustification);
}
}
}
}

Просмотреть файл

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("NuGetSuperBVT")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("NuGetSuperBVT")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("2ed95ff6-1941-4053-99ce-f9748048762c")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

Просмотреть файл

@ -0,0 +1,46 @@
using System.Collections.Generic;
using NuGet;
using NuGetPackageVerifier.Logging;
namespace NuGetPackageVerifier
{
public class RequiredAttributesRule : IPackageVerifierRule
{
public IEnumerable<MyPackageIssue> Validate(IPackageRepository packageRepo, IPackage package, IPackageVerifierLogger logger)
{
if (string.IsNullOrEmpty(package.Copyright))
{
yield return PackageIssueFactory.RequiredCopyright();
}
if (package.LicenseUrl == null)
{
yield return PackageIssueFactory.RequiredLicenseUrl();
}
if (package.IconUrl == null)
{
yield return PackageIssueFactory.RequiredIconUrl();
}
if (string.IsNullOrEmpty(package.Tags))
{
yield return PackageIssueFactory.RequiredTags();
}
if (string.IsNullOrEmpty(package.Title))
{
yield return PackageIssueFactory.RequiredTitle();
}
if (string.IsNullOrEmpty(package.Summary))
{
yield return PackageIssueFactory.RequiredSummary();
}
if (package.ProjectUrl == null)
{
yield return PackageIssueFactory.RequiredProjectUrl();
}
if (!package.RequireLicenseAcceptance)
{
yield return PackageIssueFactory.RequiredRequireLicenseAcceptanceTrue();
}
yield break;
}
}
}

Просмотреть файл

@ -0,0 +1,29 @@
using System.Collections.Generic;
using NuGet;
using NuGetPackageVerifier.Logging;
namespace NuGetPackageVerifier
{
public class SatellitePackageRule : IPackageVerifierRule
{
public IEnumerable<MyPackageIssue> Validate(IPackageRepository packageRepo, IPackage package, IPackageVerifierLogger logger)
{
if (package.IsSatellitePackage())
{
if (package.Summary.Contains("{"))
{
yield return PackageIssueFactory.Satellite_PackageSummaryNotLocalized();
}
if (package.Title.Contains("{"))
{
yield return PackageIssueFactory.Satellite_PackageTitleNotLocalized();
}
if (package.Description.Contains("{"))
{
yield return PackageIssueFactory.Satellite_PackageDescriptionNotLocalized();
}
}
yield break;
}
}
}

Просмотреть файл

@ -0,0 +1,22 @@
using System.Collections.Generic;
using NuGet;
using NuGetPackageVerifier.Logging;
namespace NuGetPackageVerifier
{
public class StrictSemanticVersionValidationRule : IPackageVerifierRule
{
public IEnumerable<MyPackageIssue> Validate(IPackageRepository packageRepo, IPackage package, IPackageVerifierLogger logger)
{
SemanticVersion semanticVersion;
if (SemanticVersion.TryParseStrict(package.Version.ToString(), out semanticVersion))
{
yield break;
}
else
{
yield return PackageIssueFactory.NotSemanticVersion(package.Version);
}
}
}
}

Просмотреть файл

@ -0,0 +1,134 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace NuGetPackageVerifier
{
// See http://msdn.microsoft.com/en-us/library/aa388205(v=VS.85).aspx
public class WinTrust
{
// The GUID action ID for using the AuthentiCode policy provider (see softpub.h)
private const string WINTRUST_ACTION_GENERIC_VERIFY_V2 = "{00AAC56B-CD44-11d0-8CC2-00C04FC295EE}";
// See wintrust.h
enum UIChoice
{
WTD_UI_ALL = 1,
WTD_UI_NONE,
WTD_UI_NOBAD,
WTD_UI_NOGOOD
}
enum RevocationChecks
{
WTD_REVOKE_NONE,
WTD_REVOKE_WHOLECHAIN
}
enum UnionChoice
{
WTD_CHOICE_FILE = 1,
WTD_CHOICE_CATALOG,
WTD_CHOICE_BLOB,
WTD_CHOICE_SIGNER,
WTD_CHOICE_CERT
}
enum StateAction
{
WTD_STATEACTION_IGNORE,
WTD_STATEACTION_VERIFY,
WTD_STATEACTION_CLOSE,
WTD_STATEACTION_AUTO_CACHE,
WTD_STATEACTION_AUTO_CACHE_FLUSH
}
enum Provider
{
WTD_USE_IE4_TRUST_FLAG = 0x00000001,
WTD_NO_IE4_CHAIN_FLAG = 0x00000002,
WTD_NO_POLICY_USAGE_FLAG = 0x00000004,
WTD_REVOCATION_CHECK_NONE = 0x00000010,
WTD_REVOCATION_CHECK_END_CERT = 0x00000020,
WTD_REVOCATION_CHECK_CHAIN = 0x00000040,
WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT = 0x00000080,
WTD_SAFER_FLAG = 0x00000100,
WTD_HASH_ONLY_FLAG = 0x00000200,
WTD_USE_DEFAULT_OSVER_CHECK = 0x00000400,
WTD_LIFETIME_SIGNING_FLAG = 0x00000800,
WTD_CACHE_ONLY_URL_RETRIEVAL = 0x00001000
}
[StructLayout(LayoutKind.Sequential)]
struct WinTrustData
{
public uint cbStruct;
public IntPtr pPolicyCallbackData;
public IntPtr pSIPClientData;
public uint dwUIChoice;
public uint fdwRevocationChecks;
public uint dwUnionChoice;
public IntPtr pFile; // We're not interested in other union members
public uint dwStateAction;
public IntPtr hWVTStateData;
public IntPtr pwszURLReference;
public uint dwProvFlags;
public uint dwUIContext;
}
[StructLayout(LayoutKind.Sequential)]
struct WinTrustFileInfo
{
public uint cbStruct;
[MarshalAs(UnmanagedType.LPTStr)]
public string pcwszFilePath;
public IntPtr hFile;
public IntPtr pgKnownSubject;
}
public static bool IsAuthenticodeSigned(string path)
{
WinTrustFileInfo fileInfo = new WinTrustFileInfo()
{
cbStruct = (uint)Marshal.SizeOf(typeof(WinTrustFileInfo)),
pcwszFilePath = Path.GetFullPath(path),
hFile = IntPtr.Zero,
pgKnownSubject = IntPtr.Zero
};
WinTrustData data = new WinTrustData()
{
cbStruct = (uint)Marshal.SizeOf(typeof(WinTrustData)),
dwProvFlags = Convert.ToUInt32(Provider.WTD_SAFER_FLAG),
dwStateAction = Convert.ToUInt32(StateAction.WTD_STATEACTION_IGNORE),
dwUIChoice = Convert.ToUInt32(UIChoice.WTD_UI_NONE),
dwUIContext = 0,
dwUnionChoice = Convert.ToUInt32(UnionChoice.WTD_CHOICE_FILE),
fdwRevocationChecks = Convert.ToUInt32(RevocationChecks.WTD_REVOKE_NONE),
hWVTStateData = IntPtr.Zero,
pFile = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WinTrustFileInfo))),
pPolicyCallbackData = IntPtr.Zero,
pSIPClientData = IntPtr.Zero,
pwszURLReference = IntPtr.Zero
};
// TODO: Potential memory leak. Need to invetigate
Marshal.StructureToPtr(fileInfo, data.pFile, false);
IntPtr pGuid = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid)));
IntPtr pData = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WinTrustData)));
Marshal.StructureToPtr(data, pData, true);
Marshal.StructureToPtr(new Guid(WINTRUST_ACTION_GENERIC_VERIFY_V2), pGuid, true);
uint result = WinVerifyTrust(IntPtr.Zero, pGuid, pData);
Marshal.FreeHGlobal(pGuid);
Marshal.FreeHGlobal(pData);
return result == 0;
}
[DllImport("wintrust.dll", SetLastError = true)]
internal static extern uint WinVerifyTrust(IntPtr hWnd, IntPtr pgActionID, IntPtr pWinTrustData);
}
}

Просмотреть файл

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Web.Xdt" version="2.1.0" targetFramework="net451" />
<package id="NuGet.Core" version="2.8.3" targetFramework="net451" />
</packages>