Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Apply feedback
  • Loading branch information
dtivel committed Sep 18, 2024
commit 0bf23a67ff1d467437d5305b189e48bef1a24ce3
61 changes: 36 additions & 25 deletions src/Sign.Core/DataFormatSigners/ClickOnceSigner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE.txt file in the project root for more information.

using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
Expand Down Expand Up @@ -127,14 +128,17 @@ await Parallel.ForEachAsync(files, _parallelOptions, async (file, state) =>

// Inner files are now signed
// now look for the manifest file and sign that if we have one
var appManifestFromDeploymentManifest = GetApplicationManifestForDeploymentManifest(file);
FileInfo? manifestFile = filteredFiles.SingleOrDefault(f => f.Name.Equals(appManifestFromDeploymentManifest, StringComparison.OrdinalIgnoreCase));
FileInfo? applicationManifestFile = null;
if (TryGetApplicationManifestFileName(file, out string? fileName))
{
applicationManifestFile = filteredFiles.SingleOrDefault(f => f.Name.Equals(fileName, StringComparison.OrdinalIgnoreCase));
}

string fileArgs = $@"-update ""{manifestFile}"" {args}";
string fileArgs = $@"-update ""{applicationManifestFile}"" {args}";

if (manifestFile is not null && !await SignAsync(fileArgs, manifestFile, rsaPrivateKey, certificate, options))
if (applicationManifestFile is not null && !await SignAsync(fileArgs, applicationManifestFile, rsaPrivateKey, certificate, options))
{
string message = string.Format(CultureInfo.CurrentCulture, Resources.SigningFailed, manifestFile.FullName);
string message = string.Format(CultureInfo.CurrentCulture, Resources.SigningFailed, applicationManifestFile.FullName);

throw new Exception(message);
}
Expand Down Expand Up @@ -166,9 +170,9 @@ await Parallel.ForEachAsync(files, _parallelOptions, async (file, state) =>
foreach (FileInfo deploymentManifestFile in deploymentManifestFiles)
{
fileArgs = $@"-update ""{deploymentManifestFile.FullName}"" {args} {publisherParam}";
if (manifestFile is not null)
if (applicationManifestFile is not null)
{
fileArgs += $@" -appm ""{manifestFile.FullName}""";
fileArgs += $@" -appm ""{applicationManifestFile.FullName}""";
}
if (options.DescriptionUrl is not null)
{
Expand Down Expand Up @@ -276,51 +280,58 @@ public void CopySigningDependencies(FileInfo deploymentManifestFile, DirectoryIn
}

/// <summary>
/// Try and find the application manifest (.manifest) file from a clickonce application manifest (.application / .vsto
/// Try and find the application manifest (.manifest) file from a ClickOnce application manifest (.application / .vsto
/// There might not be one, if the user is attempting to only re-sign the deployment manifest without touching other files.
/// This is necessary because there might be multiple *.manifest files present, e.g. if a DLL that's part of the clickonce
/// package ships its own assembly manifest which isn't a clickonce application manifest.
/// This is necessary because there might be multiple *.manifest files present, e.g. if a DLL that's part of the ClickOnce
/// package ships its own assembly manifest which isn't a ClickOnce application manifest.
/// </summary>
/// <param name="deploymentManifest"></param>
/// <returns>A string containing the file name of the Application manifest, or null if it couldn't be found.</returns>
/// <param name="deploymentManifest">A <see cref="FileInfo"/> representing a deployment manifest file.</param>
/// <param name="applicationManifestFileName">A <see cref="string?"/> representing a manifest file name or <c>null</c> if one isn't found.</param>
/// <returns><c>true</c> if the application manifest file name was found; otherwise, <c>false</c>.</returns>
/// <exception cref="InvalidDataException"></exception>
private string? GetApplicationManifestForDeploymentManifest(FileInfo deploymentManifest)
private bool TryGetApplicationManifestFileName(FileInfo deploymentManifest, [NotNullWhen(true)] out string? applicationManifestFileName)
{
applicationManifestFileName = null;

var xml = new XmlDocument();
xml.Load(deploymentManifest.FullName);
// there should only be a single result here, if the file is a valid clickonce manifest.
var dependentAssemblies = xml.GetElementsByTagName("dependentAssembly");
XmlNodeList dependentAssemblies = xml.GetElementsByTagName("dependentAssembly");
if (dependentAssemblies.Count != 1)
{
Logger.LogDebug(Resources.ApplicationManifestNotFound);
return null;
return false;
}

var node = dependentAssemblies.Item(0);
XmlNode? node = dependentAssemblies.Item(0);
if (node is null || node.Attributes is null)
{
Logger.LogDebug(Resources.ApplicationManifestNotFound);
return null;
return false;
}

var applicationManifestFileNameAttribute = node.Attributes["codebase"];
if (applicationManifestFileNameAttribute is null || string.IsNullOrEmpty(applicationManifestFileNameAttribute.Value))
XmlAttribute? codebaseAttribute = node.Attributes["codebase"];
if (codebaseAttribute is null || string.IsNullOrEmpty(codebaseAttribute.Value))
{
Logger.LogDebug(Resources.ApplicationManifestNotFound);
return null;
return false;
}

// the codebase attribute can be a relative file path (e.g. Application Files\MyApp_1_0_0_0\MyApp.dll.manifest) or
// The codebase attribute can be a relative file path (e.g. Application Files\MyApp_1_0_0_0\MyApp.dll.manifest) or
// a URI (e.g. https://my.cdn.com/clickonce/MyApp/ApplicationFiles/MyApp_1_0_0_0/MyApp.dll.manifest) so we need to
// handle both cases and extract just the file name part.
//
// we only try and parse absolute uris, because a relative uri can just be treated like a file path for our purposes
if (Uri.TryCreate(applicationManifestFileNameAttribute.Value, UriKind.Absolute, out var uri))
// We only try and parse absolute URI's, because a relative URI can just be treated like a file path for our purposes.
if (Uri.TryCreate(codebaseAttribute.Value, UriKind.Absolute, out Uri? uri))
{
applicationManifestFileName = Path.GetFileName(uri.LocalPath); // works for http(s) and file:// uris
}
else
{
Path.GetFileName(uri.LocalPath); // works for http(s) and file:// uris
applicationManifestFileName = Path.GetFileName(codebaseAttribute.Value);
}

return Path.GetFileName(applicationManifestFileNameAttribute.Value);
return !string.IsNullOrEmpty(applicationManifestFileName);
}
}
}
1 change: 1 addition & 0 deletions src/Sign.Core/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -277,5 +277,6 @@
</data>
<data name="ApplicationManifestNotFound" xml:space="preserve">
<value>Did not find exactly 1 &lt;dependentAssembly&gt; element with a non-empty 'codebase' attribute within the deployment manifest.</value>
<comment>{Locked="&lt;dependentAssembly&gt;"} is an XML element. {Locked="codebase"} is an XML attribute.</comment>
</data>
</root>
2 changes: 1 addition & 1 deletion src/Sign.Core/xlf/Resources.cs.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<trans-unit id="ApplicationManifestNotFound">
<source>Did not find exactly 1 &lt;dependentAssembly&gt; element with a non-empty 'codebase' attribute within the deployment manifest.</source>
<target state="new">Did not find exactly 1 &lt;dependentAssembly&gt; element with a non-empty 'codebase' attribute within the deployment manifest.</target>
<note />
<note>{Locked="&lt;dependentAssembly&gt;"} is an XML element. {Locked="codebase"} is an XML attribute.</note>
</trans-unit>
<trans-unit id="AzureSignToolSignatureProviderSigning">
<source>Signing SignTool job with {count} files.</source>
Expand Down
2 changes: 1 addition & 1 deletion src/Sign.Core/xlf/Resources.de.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<trans-unit id="ApplicationManifestNotFound">
<source>Did not find exactly 1 &lt;dependentAssembly&gt; element with a non-empty 'codebase' attribute within the deployment manifest.</source>
<target state="new">Did not find exactly 1 &lt;dependentAssembly&gt; element with a non-empty 'codebase' attribute within the deployment manifest.</target>
<note />
<note>{Locked="&lt;dependentAssembly&gt;"} is an XML element. {Locked="codebase"} is an XML attribute.</note>
</trans-unit>
<trans-unit id="AzureSignToolSignatureProviderSigning">
<source>Signing SignTool job with {count} files.</source>
Expand Down
2 changes: 1 addition & 1 deletion src/Sign.Core/xlf/Resources.es.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<trans-unit id="ApplicationManifestNotFound">
<source>Did not find exactly 1 &lt;dependentAssembly&gt; element with a non-empty 'codebase' attribute within the deployment manifest.</source>
<target state="new">Did not find exactly 1 &lt;dependentAssembly&gt; element with a non-empty 'codebase' attribute within the deployment manifest.</target>
<note />
<note>{Locked="&lt;dependentAssembly&gt;"} is an XML element. {Locked="codebase"} is an XML attribute.</note>
</trans-unit>
<trans-unit id="AzureSignToolSignatureProviderSigning">
<source>Signing SignTool job with {count} files.</source>
Expand Down
2 changes: 1 addition & 1 deletion src/Sign.Core/xlf/Resources.fr.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<trans-unit id="ApplicationManifestNotFound">
<source>Did not find exactly 1 &lt;dependentAssembly&gt; element with a non-empty 'codebase' attribute within the deployment manifest.</source>
<target state="new">Did not find exactly 1 &lt;dependentAssembly&gt; element with a non-empty 'codebase' attribute within the deployment manifest.</target>
<note />
<note>{Locked="&lt;dependentAssembly&gt;"} is an XML element. {Locked="codebase"} is an XML attribute.</note>
</trans-unit>
<trans-unit id="AzureSignToolSignatureProviderSigning">
<source>Signing SignTool job with {count} files.</source>
Expand Down
2 changes: 1 addition & 1 deletion src/Sign.Core/xlf/Resources.it.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<trans-unit id="ApplicationManifestNotFound">
<source>Did not find exactly 1 &lt;dependentAssembly&gt; element with a non-empty 'codebase' attribute within the deployment manifest.</source>
<target state="new">Did not find exactly 1 &lt;dependentAssembly&gt; element with a non-empty 'codebase' attribute within the deployment manifest.</target>
<note />
<note>{Locked="&lt;dependentAssembly&gt;"} is an XML element. {Locked="codebase"} is an XML attribute.</note>
</trans-unit>
<trans-unit id="AzureSignToolSignatureProviderSigning">
<source>Signing SignTool job with {count} files.</source>
Expand Down
2 changes: 1 addition & 1 deletion src/Sign.Core/xlf/Resources.ja.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<trans-unit id="ApplicationManifestNotFound">
<source>Did not find exactly 1 &lt;dependentAssembly&gt; element with a non-empty 'codebase' attribute within the deployment manifest.</source>
<target state="new">Did not find exactly 1 &lt;dependentAssembly&gt; element with a non-empty 'codebase' attribute within the deployment manifest.</target>
<note />
<note>{Locked="&lt;dependentAssembly&gt;"} is an XML element. {Locked="codebase"} is an XML attribute.</note>
</trans-unit>
<trans-unit id="AzureSignToolSignatureProviderSigning">
<source>Signing SignTool job with {count} files.</source>
Expand Down
2 changes: 1 addition & 1 deletion src/Sign.Core/xlf/Resources.ko.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<trans-unit id="ApplicationManifestNotFound">
<source>Did not find exactly 1 &lt;dependentAssembly&gt; element with a non-empty 'codebase' attribute within the deployment manifest.</source>
<target state="new">Did not find exactly 1 &lt;dependentAssembly&gt; element with a non-empty 'codebase' attribute within the deployment manifest.</target>
<note />
<note>{Locked="&lt;dependentAssembly&gt;"} is an XML element. {Locked="codebase"} is an XML attribute.</note>
</trans-unit>
<trans-unit id="AzureSignToolSignatureProviderSigning">
<source>Signing SignTool job with {count} files.</source>
Expand Down
2 changes: 1 addition & 1 deletion src/Sign.Core/xlf/Resources.pl.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<trans-unit id="ApplicationManifestNotFound">
<source>Did not find exactly 1 &lt;dependentAssembly&gt; element with a non-empty 'codebase' attribute within the deployment manifest.</source>
<target state="new">Did not find exactly 1 &lt;dependentAssembly&gt; element with a non-empty 'codebase' attribute within the deployment manifest.</target>
<note />
<note>{Locked="&lt;dependentAssembly&gt;"} is an XML element. {Locked="codebase"} is an XML attribute.</note>
</trans-unit>
<trans-unit id="AzureSignToolSignatureProviderSigning">
<source>Signing SignTool job with {count} files.</source>
Expand Down
2 changes: 1 addition & 1 deletion src/Sign.Core/xlf/Resources.pt-BR.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<trans-unit id="ApplicationManifestNotFound">
<source>Did not find exactly 1 &lt;dependentAssembly&gt; element with a non-empty 'codebase' attribute within the deployment manifest.</source>
<target state="new">Did not find exactly 1 &lt;dependentAssembly&gt; element with a non-empty 'codebase' attribute within the deployment manifest.</target>
<note />
<note>{Locked="&lt;dependentAssembly&gt;"} is an XML element. {Locked="codebase"} is an XML attribute.</note>
</trans-unit>
<trans-unit id="AzureSignToolSignatureProviderSigning">
<source>Signing SignTool job with {count} files.</source>
Expand Down
2 changes: 1 addition & 1 deletion src/Sign.Core/xlf/Resources.ru.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<trans-unit id="ApplicationManifestNotFound">
<source>Did not find exactly 1 &lt;dependentAssembly&gt; element with a non-empty 'codebase' attribute within the deployment manifest.</source>
<target state="new">Did not find exactly 1 &lt;dependentAssembly&gt; element with a non-empty 'codebase' attribute within the deployment manifest.</target>
<note />
<note>{Locked="&lt;dependentAssembly&gt;"} is an XML element. {Locked="codebase"} is an XML attribute.</note>
</trans-unit>
<trans-unit id="AzureSignToolSignatureProviderSigning">
<source>Signing SignTool job with {count} files.</source>
Expand Down
2 changes: 1 addition & 1 deletion src/Sign.Core/xlf/Resources.tr.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<trans-unit id="ApplicationManifestNotFound">
<source>Did not find exactly 1 &lt;dependentAssembly&gt; element with a non-empty 'codebase' attribute within the deployment manifest.</source>
<target state="new">Did not find exactly 1 &lt;dependentAssembly&gt; element with a non-empty 'codebase' attribute within the deployment manifest.</target>
<note />
<note>{Locked="&lt;dependentAssembly&gt;"} is an XML element. {Locked="codebase"} is an XML attribute.</note>
</trans-unit>
<trans-unit id="AzureSignToolSignatureProviderSigning">
<source>Signing SignTool job with {count} files.</source>
Expand Down
2 changes: 1 addition & 1 deletion src/Sign.Core/xlf/Resources.zh-Hans.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<trans-unit id="ApplicationManifestNotFound">
<source>Did not find exactly 1 &lt;dependentAssembly&gt; element with a non-empty 'codebase' attribute within the deployment manifest.</source>
<target state="new">Did not find exactly 1 &lt;dependentAssembly&gt; element with a non-empty 'codebase' attribute within the deployment manifest.</target>
<note />
<note>{Locked="&lt;dependentAssembly&gt;"} is an XML element. {Locked="codebase"} is an XML attribute.</note>
</trans-unit>
<trans-unit id="AzureSignToolSignatureProviderSigning">
<source>Signing SignTool job with {count} files.</source>
Expand Down
2 changes: 1 addition & 1 deletion src/Sign.Core/xlf/Resources.zh-Hant.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<trans-unit id="ApplicationManifestNotFound">
<source>Did not find exactly 1 &lt;dependentAssembly&gt; element with a non-empty 'codebase' attribute within the deployment manifest.</source>
<target state="new">Did not find exactly 1 &lt;dependentAssembly&gt; element with a non-empty 'codebase' attribute within the deployment manifest.</target>
<note />
<note>{Locked="&lt;dependentAssembly&gt;"} is an XML element. {Locked="codebase"} is an XML attribute.</note>
</trans-unit>
<trans-unit id="AzureSignToolSignatureProviderSigning">
<source>Signing SignTool job with {count} files.</source>
Expand Down