Skip to content

Commit

Permalink
Provide probing paths to find references
Browse files Browse the repository at this point in the history
- Add probing paths parameter to the API so that additional directories
can be searched to resolve references.
- Console and UI will use all included file paths to probe for
references. Fixing references now don't require dependencies to be in
the same directory as the signed assembly, just include all files
(signed or not) to be processed together and references will be found
automagically.
  • Loading branch information
brutaldev committed May 30, 2015
1 parent 91a30db commit 558daf9
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 55 deletions.
26 changes: 24 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ If you are making use of the [NuGet package](https://www.nuget.org/packages/Brut
```xml
<Target Name="BeforeBuild">
<Exec ContinueOnError="false"
Command="&quot;..\packages\Brutal.Dev.StrongNameSigner.1.4.7\tools\StrongNameSigner.Console.exe&quot; -in &quot;..\packages&quot;" />
Command="&quot;..\packages\Brutal.Dev.StrongNameSigner.1.4.8\tools\StrongNameSigner.Console.exe&quot; -in &quot;..\packages&quot;" />
</Target>
```

Expand All @@ -46,7 +46,7 @@ To add multiple directories to process at the same time (similar to how the UI c
```xml
<Target Name="BeforeBuild">
<Exec ContinueOnError="false"
Command="&quot;..\packages\Brutal.Dev.StrongNameSigner.1.4.7\tools\StrongNameSigner.Console.exe&quot; -in &quot;..\packages\elmah.corelibrary.1.2.2|..\packages\Elmah.MVC.2.1.1&quot;" />
Command="&quot;..\packages\Brutal.Dev.StrongNameSigner.1.4.8\tools\StrongNameSigner.Console.exe&quot; -in &quot;..\packages\elmah.corelibrary.1.2.2|..\packages\Elmah.MVC.2.1.1&quot;" />
</Target>
```

Expand All @@ -59,6 +59,28 @@ Another alternative is to simply call the `StrongNameSigner.Console.exe` with re

`"C:\Program Files\BrutalDev\.NET Assembly Strong-Name Signer\StrongNameSigner.Console.exe" -in "..\packages"`

Dealing With Dependencies
-------------------------

To avoid a complicated explanation on how this works, just include ALL assemblies that reference each other whether they are signed or not. As of version 1.4.8, all included file paths are probed for references so they can be fixed without having to copy them into the signed assembly directory.

When dependant assemblies cannot be found and references weren't fixed correctly, the following type of error will occur during a build.

```
The type 'XYZ' is defined in an assembly that is not referenced. You must add a reference to assembly 'SomeAssembly, Version=1.2.34.5, Culture=neutral, PublicKeyToken=null'.
```

For example, ServiceStack's PostgreSQL NuGet package is not signed but other dependant assemblies are. Furthermore, these dependant assembly versions don't match what is referenced in `ServiceStack.OrmLite.PostgreSQL`. To correct the reference versions as well as ensuring the correct signed assemblies are referenced, simply include all the files that need to be processed in a single command to the strong-name signer.

```xml
<Target Name="BeforeBuild">
<Exec ContinueOnError="false"
Command="&quot;..\packages\Brutal.Dev.StrongNameSigner.1.4.8\tools\StrongNameSigner.Console.exe&quot; -in &quot;..\packages\ServiceStack.OrmLite.PostgreSQL.4.0.40\lib\net40|..\packages\ServiceStack.Text.Signed.4.0.40\lib\net40|..\packages\ServiceStack.OrmLite.Signed.4.0.40&quot;" />
</Target>
```

Even though `ServiceStack.OrmLite.PostgreSQL.dll` references the unsigned `ServiceStack.Text` v4.0.39 and the unsigned `ServiceStack.OrmLite.Signed` v4.0.40, using the command above will force it to use the included signed versions as references as well as correcting the reference versions to match.

API Usage
---------
Reference **Brutal.Dev.StrongNameSigner.dll** in your project or include it in a PowerShell script.
Expand Down
12 changes: 6 additions & 6 deletions src/Brutal.Dev.StrongNameSigner.Console/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ private static Stats SignAssemblies(Options options)
// Go through all the references excluding the file we are working on.
foreach (var referencePath in referencesToFix.Where(r => !r.Equals(filePath)))
{
if (FixSingleAssemblyReference(filePath, referencePath, options.KeyFile, options.Password))
if (FixSingleAssemblyReference(filePath, referencePath, options.KeyFile, options.Password, filesToSign.Select(f => Path.GetDirectoryName(f)).Distinct().ToArray()))
{
referenceFixes++;
}
Expand All @@ -157,7 +157,7 @@ private static Stats SignAssemblies(Options options)
// Remove all InternalsVisibleTo attributes without public keys from the processed assemblies. Signed assemblies cannot have unsigned friend assemblies.
foreach (var filePath in signedAssemblyPaths)
{
if (RemoveInvalidFriendAssemblyReferences(filePath, options.KeyFile, options.Password))
if (RemoveInvalidFriendAssemblyReferences(filePath, options.KeyFile, options.Password, filesToSign.Select(f => Path.GetDirectoryName(f)).Distinct().ToArray()))
{
referenceFixes++;
}
Expand Down Expand Up @@ -203,15 +203,15 @@ private static AssemblyInfo SignSingleAssembly(string assemblyPath, string keyPa
return null;
}

private static bool FixSingleAssemblyReference(string assemblyPath, string referencePath, string keyFile, string keyFilePassword)
private static bool FixSingleAssemblyReference(string assemblyPath, string referencePath, string keyFile, string keyFilePassword, params string[] probingPaths)
{
try
{
PrintMessage(null, LogLevel.Verbose);
PrintMessage(string.Format("Fixing references to '{1}' in '{0}'...", assemblyPath, referencePath), LogLevel.Verbose);

var info = SigningHelper.GetAssemblyInfo(assemblyPath);
if (SigningHelper.FixAssemblyReference(assemblyPath, referencePath, keyFile, keyFilePassword))
if (SigningHelper.FixAssemblyReference(assemblyPath, referencePath, keyFile, keyFilePassword, probingPaths))
{
PrintMessageColor(string.Format("References to '{1}' in '{0}' were fixed successfully.", assemblyPath, referencePath), LogLevel.Changes, ConsoleColor.Green);

Expand All @@ -234,15 +234,15 @@ private static bool FixSingleAssemblyReference(string assemblyPath, string refer
return false;
}

private static bool RemoveInvalidFriendAssemblyReferences(string assemblyPath, string keyFile, string keyFilePassword)
private static bool RemoveInvalidFriendAssemblyReferences(string assemblyPath, string keyFile, string keyFilePassword, params string[] probingPaths)
{
try
{
PrintMessage(null, LogLevel.Verbose);
PrintMessage(string.Format("Removing invalid friend references from '{0}'...", assemblyPath), LogLevel.Verbose);

var info = SigningHelper.GetAssemblyInfo(assemblyPath);
if (SigningHelper.RemoveInvalidFriendAssemblies(assemblyPath, keyFile, keyFilePassword))
if (SigningHelper.RemoveInvalidFriendAssemblies(assemblyPath, keyFile, keyFilePassword, probingPaths))
{
PrintMessageColor(string.Format("Invalid friend assemblies removed successfully from '{0}'.", assemblyPath), LogLevel.Changes, ConsoleColor.Green);

Expand Down
4 changes: 2 additions & 2 deletions src/Brutal.Dev.StrongNameSigner.UI/MainForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ private void BackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
}

log.AppendFormat("Fixing references to {1} in {0}...", filePath, reference).AppendLine();
if (SigningHelper.FixAssemblyReference(filePath, reference, keyFile, password))
if (SigningHelper.FixAssemblyReference(filePath, reference, keyFile, password, assemblyPaths.Select(f => Path.GetDirectoryName(f)).Distinct().ToArray()))
{
log.Append("Reference was found and fixed.").AppendLine();
referenceFixes++;
Expand All @@ -442,7 +442,7 @@ private void BackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
}

log.AppendFormat("Removing invalid friend references from '{0}'...", filePath).AppendLine();
if (SigningHelper.RemoveInvalidFriendAssemblies(filePath, keyFile, password))
if (SigningHelper.RemoveInvalidFriendAssemblies(filePath, keyFile, password, assemblyPaths.Select(f => Path.GetDirectoryName(f)).Distinct().ToArray()))
{
log.Append("Invalid friend assemblies removed.").AppendLine();
referenceFixes++;
Expand Down
95 changes: 50 additions & 45 deletions src/Brutal.Dev.StrongNameSigner/SigningHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,19 +77,16 @@ public static AssemblyInfo SignAssembly(string assemblyPath, string keyPath, str
/// <param name="keyPath">The path to the strong-name key file you want to use (.snk or .pfx).</param>
/// <param name="outputPath">The directory path where the strong-name signed assembly will be copied to.</param>
/// <param name="keyFilePassword">The password for the provided strong-name key file.</param>
/// <returns>The assembly information of the new strong-name signed assembly.</returns>
/// <exception cref="System.ArgumentNullException">
/// assemblyPath parameter was not provided.
/// </exception>
/// <exception cref="System.IO.FileNotFoundException">
/// Could not find provided assembly file.
/// <param name="probingPaths">Additional paths to probe for references.</param>
/// <returns>
/// The assembly information of the new strong-name signed assembly.
/// </returns>
/// <exception cref="System.ArgumentNullException">assemblyPath parameter was not provided.</exception>
/// <exception cref="System.IO.FileNotFoundException">Could not find provided assembly file.
/// or
/// Could not find provided strong-name key file file.
/// </exception>
/// <exception cref="System.BadImageFormatException">
/// The file is not a .NET managed assembly.
/// </exception>
public static AssemblyInfo SignAssembly(string assemblyPath, string keyPath, string outputPath, string keyFilePassword)
/// Could not find provided strong-name key file file.</exception>
/// <exception cref="System.BadImageFormatException">The file is not a .NET managed assembly.</exception>
public static AssemblyInfo SignAssembly(string assemblyPath, string keyPath, string outputPath, string keyFilePassword, params string[] probingPaths)
{
// Verify assembly path was passed in.
if (string.IsNullOrWhiteSpace(assemblyPath))
Expand Down Expand Up @@ -138,7 +135,7 @@ public static AssemblyInfo SignAssembly(string assemblyPath, string keyPath, str

try
{
AssemblyDefinition.ReadAssembly(assemblyPath, GetReadParameters(assemblyPath))
AssemblyDefinition.ReadAssembly(assemblyPath, GetReadParameters(assemblyPath, probingPaths))
.Write(outputFile, new WriterParameters() { StrongNameKeyPair = GetStrongNameKeyPair(keyPath, keyFilePassword) });
}
catch (Exception)
Expand All @@ -159,14 +156,13 @@ public static AssemblyInfo SignAssembly(string assemblyPath, string keyPath, str
/// Gets .NET assembly information.
/// </summary>
/// <param name="assemblyPath">The path to an assembly you want to get information from.</param>
/// <returns>The assembly information.</returns>
/// <exception cref="System.ArgumentNullException">
/// assemblyPath parameter was not provided.
/// </exception>
/// <exception cref="System.IO.FileNotFoundException">
/// Could not find provided assembly file.
/// </exception>
public static AssemblyInfo GetAssemblyInfo(string assemblyPath)
/// <param name="probingPaths">Additional paths to probe for references.</param>
/// <returns>
/// The assembly information.
/// </returns>
/// <exception cref="System.ArgumentNullException">assemblyPath parameter was not provided.</exception>
/// <exception cref="System.IO.FileNotFoundException">Could not find provided assembly file.</exception>
public static AssemblyInfo GetAssemblyInfo(string assemblyPath, params string[] probingPaths)
{
// Verify assembly path was passed in.
if (string.IsNullOrWhiteSpace(assemblyPath))
Expand All @@ -180,7 +176,7 @@ public static AssemblyInfo GetAssemblyInfo(string assemblyPath)
throw new FileNotFoundException("Could not find provided assembly file.", assemblyPath);
}

var a = AssemblyDefinition.ReadAssembly(assemblyPath, GetReadParameters(assemblyPath));
var a = AssemblyDefinition.ReadAssembly(assemblyPath, GetReadParameters(assemblyPath, probingPaths));

return new AssemblyInfo()
{
Expand Down Expand Up @@ -218,22 +214,21 @@ public static bool FixAssemblyReference(string assemblyPath, string referenceAss
/// <summary>
/// Fixes an assembly reference.
/// </summary>
/// <param name="assemblyPath">The path to the assembly you want to fix a reference for.</param>
/// <param name="assemblyPath">The path to the assembly you want to fix a reference for.</param>
/// <param name="referenceAssemblyPath">The path to the reference assembly path you want to fix in the first assembly.</param>
/// <param name="keyPath">The path to the strong-name key file you want to use (.snk or .pfx).</param>
/// <param name="keyFilePassword">The password for the provided strong-name key file.</param>
/// <returns><c>true</c> if an assembly reference was found and fixed, <c>false</c> if no reference was found.</returns>
/// <exception cref="System.ArgumentNullException">
/// assemblyPath was not provided.
/// <param name="probingPaths">Additional paths to probe for references.</param>
/// <returns>
/// <c>true</c> if an assembly reference was found and fixed, <c>false</c> if no reference was found.
/// </returns>
/// <exception cref="System.ArgumentNullException">assemblyPath was not provided.
/// or
/// referenceAssemblyPath was not provided.
/// </exception>
/// <exception cref="System.IO.FileNotFoundException">
/// Could not find provided assembly file.
/// referenceAssemblyPath was not provided.</exception>
/// <exception cref="System.IO.FileNotFoundException">Could not find provided assembly file.
/// or
/// Could not find provided reference assembly file.
/// </exception>
public static bool FixAssemblyReference(string assemblyPath, string referenceAssemblyPath, string keyPath, string keyFilePassword)
/// Could not find provided reference assembly file.</exception>
public static bool FixAssemblyReference(string assemblyPath, string referenceAssemblyPath, string keyPath, string keyFilePassword, params string[] probingPaths)
{
// Verify assembly path was passed in.
if (string.IsNullOrWhiteSpace(assemblyPath))
Expand All @@ -258,8 +253,8 @@ public static bool FixAssemblyReference(string assemblyPath, string referenceAss
}

bool fixApplied = false;
var a = AssemblyDefinition.ReadAssembly(assemblyPath, GetReadParameters(assemblyPath));
var b = AssemblyDefinition.ReadAssembly(referenceAssemblyPath, GetReadParameters(referenceAssemblyPath));
var a = AssemblyDefinition.ReadAssembly(assemblyPath, GetReadParameters(assemblyPath, probingPaths));
var b = AssemblyDefinition.ReadAssembly(referenceAssemblyPath, GetReadParameters(referenceAssemblyPath, probingPaths));

var assemblyReference = a.MainModule.AssemblyReferences.FirstOrDefault(r => r.Name == b.Name.Name);

Expand Down Expand Up @@ -324,14 +319,13 @@ public static bool RemoveInvalidFriendAssemblies(string assemblyPath)
/// <param name="assemblyPath">The path to the assembly you want to remove friend references from.</param>
/// <param name="keyPath">The path to the strong-name key file you want to use (.snk or .pfx).</param>
/// <param name="keyFilePassword">The password for the provided strong-name key file.</param>
/// <returns><c>true</c> if any invalid friend references were found and fixed, <c>false</c> if no invalid friend references was found.</returns>
/// <exception cref="System.ArgumentNullException">
/// assemblyPath was not provided.
/// </exception>
/// <exception cref="System.IO.FileNotFoundException">
/// Could not find provided assembly file.
/// </exception>
public static bool RemoveInvalidFriendAssemblies(string assemblyPath, string keyPath, string keyFilePassword)
/// <param name="probingPaths">Additional paths to probe for references.</param>
/// <returns>
/// <c>true</c> if any invalid friend references were found and fixed, <c>false</c> if no invalid friend references was found.
/// </returns>
/// <exception cref="System.ArgumentNullException">assemblyPath was not provided.</exception>
/// <exception cref="System.IO.FileNotFoundException">Could not find provided assembly file.</exception>
public static bool RemoveInvalidFriendAssemblies(string assemblyPath, string keyPath, string keyFilePassword, params string[] probingPaths)
{
// Verify assembly path was passed in.
if (string.IsNullOrWhiteSpace(assemblyPath))
Expand All @@ -346,7 +340,7 @@ public static bool RemoveInvalidFriendAssemblies(string assemblyPath, string key
}

bool fixApplied = false;
var a = AssemblyDefinition.ReadAssembly(assemblyPath, GetReadParameters(assemblyPath));
var a = AssemblyDefinition.ReadAssembly(assemblyPath, GetReadParameters(assemblyPath, probingPaths));

var ivtAttributes = a.CustomAttributes.Where(attr => attr.AttributeType.FullName == typeof(InternalsVisibleToAttribute).FullName).ToList();

Expand Down Expand Up @@ -375,7 +369,7 @@ public static bool RemoveInvalidFriendAssemblies(string assemblyPath, string key
return fixApplied;
}

private static ReaderParameters GetReadParameters(string assemblyPath)
private static ReaderParameters GetReadParameters(string assemblyPath, string[] probingPaths)
{
var resolver = new DefaultAssemblyResolver();

Expand All @@ -384,6 +378,17 @@ private static ReaderParameters GetReadParameters(string assemblyPath)
resolver.AddSearchDirectory(Path.GetDirectoryName(assemblyPath));
}

if (probingPaths != null)
{
foreach (var searchDir in probingPaths)
{
if (Directory.Exists(searchDir))
{
resolver.AddSearchDirectory(searchDir);
}
}
}

return new ReaderParameters() { AssemblyResolver = resolver };
}

Expand Down

0 comments on commit 558daf9

Please sign in to comment.