Introduce "msi inscribe" command and use it in wix.signing.targets
Rob Mensching committed
Jan 8, 2022 at 07:44 UTC
4182d6d594301b88d4780d0222a3d1448b524fde
10 files changed
+376
-31
src/wix/WixToolset.BuildTasks/InscribeMsiWithCabinetSignatures.cs
new
+33
@@ -0,0 +1,33 @@
1
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
+
3
+namespace WixToolset.BuildTasks
4
+{
5
+ using Microsoft.Build.Framework;
6
+
7
+ /// <summary>
8
+ /// An MSBuild task to run WiX to update cabinet signatures in a MSI.
9
+ /// </summary>
10
+ public sealed partial class InscribeMsiWithCabinetSignatures : WixExeBaseTask
11
+ {
12
+ [Required]
13
+ public ITaskItem DatabaseFile { get; set; }
14
+
15
+ [Required]
16
+ public ITaskItem IntermediateDirectory { get; set; }
17
+
18
+ public ITaskItem OutputFile { get; set; }
19
+
20
+ protected override void BuildCommandLine(WixCommandLineBuilder commandLineBuilder)
21
+ {
22
+ commandLineBuilder.AppendTextUnquoted("msi inscribe");
23
+
24
+ commandLineBuilder.AppendFileNameIfNotNull(this.DatabaseFile);
25
+ commandLineBuilder.AppendSwitchIfNotNull("-out ", this.OutputFile);
26
+ commandLineBuilder.AppendSwitchIfNotNull("-intermediatefolder ", this.IntermediateDirectory);
27
+
28
+ base.BuildCommandLine(commandLineBuilder);
29
+
30
+ commandLineBuilder.AppendTextIfNotWhitespace(this.AdditionalOptions);
31
+ }
32
+ }
33
+}
src/wix/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs
+31
-20
@@ -12,20 +12,25 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
12
using WixToolset.Core.WindowsInstaller.Bind;
13
using WixToolset.Data;
14
using WixToolset.Data.WindowsInstaller;
15
- using WixToolset.Extensibility.Data;
15
using WixToolset.Extensibility.Services;
16
17
internal class InscribeMsiPackageCommand
18
{
20
- public InscribeMsiPackageCommand(IInscribeContext context)
19
+ public InscribeMsiPackageCommand(IServiceProvider serviceProvider, string inputPath, string intermediateFolder, string outputPath)
20
{
22
- this.Context = context;
23
- this.Messaging = context.ServiceProvider.GetService<IMessaging>();
24
- this.WindowsInstallerBackendHelper = context.ServiceProvider.GetService<IWindowsInstallerBackendHelper>();
21
+ this.Messaging = serviceProvider.GetService<IMessaging>();
22
+ this.WindowsInstallerBackendHelper = serviceProvider.GetService<IWindowsInstallerBackendHelper>();
23
this.TableDefinitions = new TableDefinitionCollection(WindowsInstallerTableDefinitions.All);
24
+ this.InputPath = inputPath;
25
+ this.IntermediateFolder = intermediateFolder;
26
+ this.OutputPath = outputPath;
27
}
28
28
- private IInscribeContext Context { get; }
29
+ private string InputPath { get; }
30
+
31
+ private string IntermediateFolder { get; }
32
+
33
+ private string OutputPath { get; }
34
35
private IMessaging Messaging { get; }
36
@@ -39,14 +44,22 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
44
var foundUnsignedExternals = false;
45
var shouldCommit = false;
46
42
- var attributes = File.GetAttributes(this.Context.InputFilePath);
47
+ var databasePath = this.OutputPath;
48
+
49
+ if (!String.Equals(this.InputPath, this.OutputPath, StringComparison.OrdinalIgnoreCase))
50
+ {
51
+ Directory.CreateDirectory(Path.GetDirectoryName(this.OutputPath));
52
+ File.Copy(this.InputPath, this.OutputPath, true);
53
+ }
54
+
55
+ var attributes = File.GetAttributes(databasePath);
56
if (FileAttributes.ReadOnly == (attributes & FileAttributes.ReadOnly))
57
{
45
- this.Messaging.Write(ErrorMessages.ReadOnlyOutputFile(this.Context.InputFilePath));
58
+ this.Messaging.Write(ErrorMessages.ReadOnlyOutputFile(databasePath));
59
return shouldCommit;
60
}
61
49
- using (var database = new Database(this.Context.InputFilePath, OpenDatabase.Transact))
62
+ using (var database = new Database(databasePath, OpenDatabase.Transact))
63
{
64
// Just use the English codepage, because the tables we're importing only have binary streams / MSI identifiers / other non-localizable content
65
var codepage = 1252;
@@ -65,8 +78,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
78
{
79
foreach (var digitalSignatureRecord in digitalSignatureView.Records)
80
{
68
- Row digitalSignatureRow = null;
69
- digitalSignatureRow = digitalSignatureTable.CreateRow(null);
81
+ var digitalSignatureRow = digitalSignatureTable.CreateRow(null);
82
83
var table = digitalSignatureRecord.GetString(0);
84
var signObject = digitalSignatureRecord.GetString(1);
@@ -78,7 +90,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
90
if (false == digitalSignatureRecord.IsNull(3))
91
{
92
// Export to a file, because the MSI API's require us to provide a file path on disk
81
- var hashPath = Path.Combine(this.Context.IntermediateFolder, "MsiDigitalSignature");
93
+ var hashPath = Path.Combine(this.IntermediateFolder, "MsiDigitalSignature");
94
var hashFileName = String.Concat(table, ".", signObject, ".bin");
95
96
Directory.CreateDirectory(hashPath);
@@ -111,7 +123,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
123
var certificateId = digitalCertificateRecord.GetString(1); // get the identifier of the certificate
124
125
// Export to a file, because the MSI API's require us to provide a file path on disk
114
- var certPath = Path.Combine(this.Context.IntermediateFolder, "MsiDigitalCertificate");
126
+ var certPath = Path.Combine(this.IntermediateFolder, "MsiDigitalCertificate");
127
Directory.CreateDirectory(certPath);
128
certPath = Path.Combine(certPath, String.Concat(certificateId, ".cer"));
129
@@ -147,7 +159,6 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
159
foreach (var mediaRecord in mediaView.Records)
160
{
161
X509Certificate2 cert2 = null;
150
- Row digitalSignatureRow = null;
162
163
var cabName = mediaRecord.GetString(4); // get the name of the cab
164
// If there is no cabinet or it's an internal cab, skip it.
@@ -157,7 +168,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
168
}
169
170
var cabId = mediaRecord.GetString(1); // get the ID of the cab
160
- var cabPath = Path.Combine(Path.GetDirectoryName(this.Context.InputFilePath), cabName);
171
+ var cabPath = Path.Combine(Path.GetDirectoryName(this.InputPath), cabName);
172
173
// If the cabs aren't there, throw an error but continue to catch the other errors
174
if (!File.Exists(cabPath))
@@ -207,7 +218,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
218
digitalCertificateRow[0] = certificateGeneratedId;
219
220
// Export to a file, because the MSI API's require us to provide a file path on disk
210
- var certPath = Path.Combine(this.Context.IntermediateFolder, "MsiDigitalCertificate");
221
+ var certPath = Path.Combine(this.IntermediateFolder, "MsiDigitalCertificate");
222
Directory.CreateDirectory(certPath);
223
certPath = Path.Combine(certPath, String.Concat(cert2.Thumbprint, ".cer"));
224
File.Delete(certPath);
@@ -224,7 +235,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
235
certificates.Add(cert2.Thumbprint, certificateGeneratedId);
236
}
237
227
- digitalSignatureRow = digitalSignatureTable.CreateRow(null);
238
+ var digitalSignatureRow = digitalSignatureTable.CreateRow(null);
239
240
digitalSignatureRow[0] = "Media";
241
digitalSignatureRow[1] = cabId;
@@ -234,7 +245,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
245
246
if (digitalCertificateTable.Rows.Count > 0)
247
{
237
- var command = new CreateIdtFileCommand(this.Messaging, digitalCertificateTable, codepage, this.Context.IntermediateFolder, true);
248
+ var command = new CreateIdtFileCommand(this.Messaging, digitalCertificateTable, codepage, this.IntermediateFolder, true);
249
command.Execute();
250
251
database.Import(command.IdtPath);
@@ -243,7 +254,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
254
255
if (digitalSignatureTable.Rows.Count > 0)
256
{
246
- var command = new CreateIdtFileCommand(this.Messaging, digitalSignatureTable, codepage, this.Context.IntermediateFolder, true);
257
+ var command = new CreateIdtFileCommand(this.Messaging, digitalSignatureTable, codepage, this.IntermediateFolder, true);
258
command.Execute();
259
260
database.Import(command.IdtPath);
@@ -257,7 +268,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
268
// If we did find external cabs but not all of them were signed, give a warning
269
if (foundUnsignedExternals)
270
{
260
- this.Messaging.Write(WarningMessages.ExternalCabsAreNotSigned(this.Context.InputFilePath));
271
+ this.Messaging.Write(WarningMessages.ExternalCabsAreNotSigned(this.InputPath));
272
}
273
274
if (shouldCommit)
src/wix/WixToolset.Core.WindowsInstaller/InscribeSubcommand.cs
new
+80
@@ -0,0 +1,80 @@
1
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
+
3
+namespace WixToolset.Core.WindowsInstaller
4
+{
5
+ using System;
6
+ using System.IO;
7
+ using System.Threading;
8
+ using System.Threading.Tasks;
9
+ using WixToolset.Core.WindowsInstaller.Inscribe;
10
+ using WixToolset.Extensibility.Services;
11
+
12
+ internal class InscribeSubcommand : WindowsInstallerSubcommandBase
13
+ {
14
+ public InscribeSubcommand(IServiceProvider serviceProvider)
15
+ {
16
+ this.ServiceProvider = serviceProvider;
17
+ this.Messaging = serviceProvider.GetService<IMessaging>();
18
+ }
19
+
20
+ private IServiceProvider ServiceProvider { get; }
21
+
22
+ private IMessaging Messaging { get; }
23
+
24
+ private string InputPath { get; set; }
25
+
26
+ private string IntermediateFolder { get; set; }
27
+
28
+ private string OutputPath { get; set; }
29
+
30
+ public override Task<int> ExecuteAsync(CancellationToken cancellationToken)
31
+ {
32
+ if (String.IsNullOrEmpty(this.InputPath))
33
+ {
34
+ Console.Error.WriteLine("Input MSI database is required");
35
+ return Task.FromResult(-1);
36
+ }
37
+
38
+ if (String.IsNullOrEmpty(this.IntermediateFolder))
39
+ {
40
+ this.IntermediateFolder = Path.GetTempPath();
41
+ }
42
+
43
+ if (String.IsNullOrEmpty(this.OutputPath))
44
+ {
45
+ this.OutputPath = this.InputPath;
46
+ }
47
+
48
+ var command = new InscribeMsiPackageCommand(this.ServiceProvider, this.InputPath, this.IntermediateFolder, this.OutputPath);
49
+ command.Execute();
50
+
51
+ return Task.FromResult(this.Messaging.LastErrorNumber);
52
+ }
53
+
54
+ public override bool TryParseArgument(ICommandLineParser parser, string argument)
55
+ {
56
+ if (parser.IsSwitch(argument))
57
+ {
58
+ var parameter = argument.Substring(1);
59
+ switch (parameter.ToLowerInvariant())
60
+ {
61
+ case "intermediatefolder":
62
+ this.IntermediateFolder = parser.GetNextArgumentAsDirectoryOrError(argument);
63
+ return true;
64
+
65
+ case "o":
66
+ case "out":
67
+ this.OutputPath = parser.GetNextArgumentAsFilePathOrError(argument);
68
+ return true;
69
+ }
70
+ }
71
+ else if (String.IsNullOrEmpty(this.InputPath))
72
+ {
73
+ this.InputPath = argument;
74
+ return true;
75
+ }
76
+
77
+ return false;
78
+ }
79
+ }
80
+}
src/wix/WixToolset.Core.WindowsInstaller/MsiBackend.cs
+4
-2
@@ -2,6 +2,7 @@
2
3
namespace WixToolset.Core.WindowsInstaller
4
{
5
+ using System;
6
using WixToolset.Core.WindowsInstaller.Bind;
7
using WixToolset.Core.WindowsInstaller.Decompile;
8
using WixToolset.Core.WindowsInstaller.Inscribe;
@@ -72,8 +73,9 @@ namespace WixToolset.Core.WindowsInstaller
73
74
public bool Inscribe(IInscribeContext context)
75
{
75
- var command = new InscribeMsiPackageCommand(context);
76
- return command.Execute();
76
+ //var command = new InscribeMsiPackageCommand(context);
77
+ //return command.Execute();
78
+ throw new NotImplementedException();
79
}
80
81
public Intermediate Unbind(IUnbindContext context)
src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerCommand.cs
new
+73
@@ -0,0 +1,73 @@
1
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
+
3
+namespace WixToolset.Core.WindowsInstaller
4
+{
5
+ using System;
6
+ using System.Threading;
7
+ using System.Threading.Tasks;
8
+ using WixToolset.Extensibility.Data;
9
+ using WixToolset.Extensibility.Services;
10
+
11
+ /// <summary>
12
+ /// Windows Installer specialized command.
13
+ /// </summary>
14
+ internal class WindowsInstallerCommand : ICommandLineCommand
15
+ {
16
+ public WindowsInstallerCommand(IServiceProvider serviceProvider)
17
+ {
18
+ this.ServiceProvider = serviceProvider;
19
+ }
20
+
21
+ public bool ShowHelp { get; set; }
22
+
23
+ public bool ShowLogo { get; set; }
24
+
25
+ public bool StopParsing { get; set; }
26
+
27
+ private IServiceProvider ServiceProvider { get; }
28
+
29
+ private WindowsInstallerSubcommandBase Subcommand { get; set; }
30
+
31
+ public Task<int> ExecuteAsync(CancellationToken cancellationToken)
32
+ {
33
+ if (this.ShowHelp || this.Subcommand is null)
34
+ {
35
+ DisplayHelp();
36
+ return Task.FromResult(1);
37
+ }
38
+
39
+ return this.Subcommand.ExecuteAsync(cancellationToken);
40
+ }
41
+
42
+ public bool TryParseArgument(ICommandLineParser parser, string argument)
43
+ {
44
+ if (this.Subcommand is null)
45
+ {
46
+ switch (argument.ToLowerInvariant())
47
+ {
48
+ case "inscribe":
49
+ this.Subcommand = new InscribeSubcommand(this.ServiceProvider);
50
+ return true;
51
+ }
52
+
53
+ return false;
54
+ }
55
+
56
+ return this.Subcommand.TryParseArgument(parser, argument);
57
+ }
58
+
59
+ private static void DisplayHelp()
60
+ {
61
+ Console.WriteLine();
62
+ Console.WriteLine("Usage: wix msi inscribe input.msi [-intermedidateFolder folder] [-out output.msi]");
63
+ Console.WriteLine();
64
+ Console.WriteLine("Options:");
65
+ Console.WriteLine(" -h|--help Show command line help.");
66
+ Console.WriteLine(" --nologo Suppress displaying the logo information.");
67
+ Console.WriteLine();
68
+ Console.WriteLine("Commands:");
69
+ Console.WriteLine();
70
+ Console.WriteLine(" inscribe Updates MSI database with cabinet signature information.");
71
+ }
72
+ }
73
+}
src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerExtensionCommandLine.cs
new
+41
@@ -0,0 +1,41 @@
1
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
+
3
+namespace WixToolset.Core.WindowsInstaller
4
+{
5
+ using System;
6
+ using System.Collections.Generic;
7
+ using WixToolset.Extensibility;
8
+ using WixToolset.Extensibility.Data;
9
+ using WixToolset.Extensibility.Services;
10
+
11
+ /// <summary>
12
+ /// Parses the "msi" command-line command. See <c>WindowsInstallerCommand</c>
13
+ /// for the bulk of the command-line processing.
14
+ /// </summary>
15
+ internal class WindowsInstallerExtensionCommandLine : BaseExtensionCommandLine
16
+ {
17
+ public WindowsInstallerExtensionCommandLine(IServiceProvider serviceProvider)
18
+ {
19
+ this.ServiceProvider = serviceProvider;
20
+ }
21
+
22
+ private IServiceProvider ServiceProvider { get; }
23
+
24
+ public override IReadOnlyCollection<ExtensionCommandLineSwitch> CommandLineSwitches => new ExtensionCommandLineSwitch[]
25
+ {
26
+ new ExtensionCommandLineSwitch { Switch = "msi", Description = "Windows Installer specialized operations." },
27
+ };
28
+
29
+ public override bool TryParseCommand(ICommandLineParser parser, string argument, out ICommandLineCommand command)
30
+ {
31
+ command = null;
32
+
33
+ if ("msi".Equals(argument, StringComparison.OrdinalIgnoreCase))
34
+ {
35
+ command = new WindowsInstallerCommand(this.ServiceProvider);
36
+ }
37
+
38
+ return command != null;
39
+ }
40
+ }
41
+}
src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerExtensionFactory.cs
+13
-2
@@ -1,4 +1,4 @@
1
-// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
1
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3
namespace WixToolset.Core.WindowsInstaller
4
{
@@ -7,11 +7,22 @@ namespace WixToolset.Core.WindowsInstaller
7
8
internal class WindowsInstallerExtensionFactory : IExtensionFactory
9
{
10
+ public WindowsInstallerExtensionFactory(IServiceProvider serviceProvider)
11
+ {
12
+ this.ServiceProvider = serviceProvider;
13
+ }
14
+
15
+ private IServiceProvider ServiceProvider { get; }
16
+
17
public bool TryCreateExtension(Type extensionType, out object extension)
18
{
19
extension = null;
20
14
- if (extensionType == typeof(IBackendFactory))
21
+ if (extensionType == typeof(IExtensionCommandLine))
22
+ {
23
+ extension = new WindowsInstallerExtensionCommandLine(this.ServiceProvider);
24
+ }
25
+ else if (extensionType == typeof(IBackendFactory))
26
{
27
extension = new WindowsInstallerBackendFactory();
28
}
src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerSubcommandBase.cs
new
+15
@@ -0,0 +1,15 @@
1
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
+
3
+namespace WixToolset.Core.WindowsInstaller
4
+{
5
+ using System.Threading;
6
+ using System.Threading.Tasks;
7
+ using WixToolset.Extensibility.Services;
8
+
9
+ internal abstract class WindowsInstallerSubcommandBase
10
+ {
11
+ public abstract bool TryParseArgument(ICommandLineParser parser, string argument);
12
+
13
+ public abstract Task<int> ExecuteAsync(CancellationToken cancellationToken);
14
+ }
15
+}
src/wix/WixToolset.Sdk/tools/wix.signing.targets
+20
-7
@@ -11,6 +11,10 @@
11
<UsingTask TaskName="GetCabList" AssemblyFile="$(WixTasksPath)" />
12
<UsingTask TaskName="GetLooseFileList" AssemblyFile="$(WixTasksPath)" />
13
14
+ <UsingTask TaskName="InscribeMsiWithCabinetSignatures" Condition=" '$(WixTasksPath64)' == '' " AssemblyFile="$(WixTasksPath)" />
15
+ <UsingTask TaskName="InscribeMsiWithCabinetSignatures" Condition=" '$(WixTasksPath64)' != '' " AssemblyFile="$(WixTasksPath)" Architecture="x86" />
16
+ <UsingTask TaskName="InscribeMsiWithCabinetSignatures" Condition=" '$(WixTasksPath64)' != '' " AssemblyFile="$(WixTasksPath64)" Architecture="x64" />
17
+
18
<!-- Default Inscribe properties. -->
19
<PropertyGroup>
20
<InscribeNoLogo Condition=" '$(InscribeNoLogo)' == '' ">$(NoLogo)</InscribeNoLogo>
@@ -21,6 +25,10 @@
25
<InscribeVerboseOutput Condition=" '$(InscribeVerboseOutput)' == '' ">$(VerboseOutput)</InscribeVerboseOutput>
26
</PropertyGroup>
27
28
+ <PropertyGroup>
29
+ <SignOutputCabs Condition=" '$(SignOutputCabs)'=='' ">$(SignOutput)</SignOutputCabs>
30
+ </PropertyGroup>
31
+
32
<!--
33
==================================================================================================
34
Signing
@@ -58,7 +66,7 @@
66
<Target
67
Name="Signing"
68
DependsOnTargets="$(SigningDependsOn)"
61
- Inputs="$(TargetPath)"
69
+ Inputs="@(_WixBuildOutputFile)"
70
Outputs="$(SignedFilePath)"
71
Condition=" '$(SignOutput)' == 'true' ">
72
@@ -76,7 +84,7 @@
84
<Target
85
Name="CalculateSignTargetFiles">
86
<ItemGroup>
79
- <SignTargetPath Include="$(TargetPath)" />
87
+ <SignTargetPath Include="@(_WixBuildOutputFile)" />
88
</ItemGroup>
89
</Target>
90
@@ -98,7 +106,8 @@
106
<Target
107
Name="GetCabsToSign"
108
Inputs="@(SignTargetPath)"
101
- Outputs="$(SignedFilePath)">
109
+ Outputs="$(SignedFilePath)"
110
+ Condition=" '$(SignOutputCabs)' == 'true' ">
111
<GetCabList Database="%(SignTargetPath.FullPath)">
112
<Output TaskParameter="CabList" ItemName="SignCabs" />
113
<Output TaskParameter="CabList" ItemName="FileWrites" />
@@ -174,18 +183,22 @@
183
Outputs="$(SignedFilePath)"
184
Condition=" '@(SignCabs)' != '' ">
185
177
- <Insignia
186
+ <InscribeMsiWithCabinetSignatures
187
DatabaseFile="%(SignTargetPath.FullPath)"
188
OutputFile="%(SignTargetPath.FullPath)"
180
- ToolPath="$(WixToolPath)"
189
+ IntermediateDirectory="%(SignTargetPath.RootDir)%(SignTargetPath.Directory)"
190
+
191
NoLogo="$(InscribeNoLogo)"
182
- RunAsSeparateProcess="$(RunWixToolsOutOfProc)"
192
SuppressAllWarnings="$(InscribeSuppressAllWarnings)"
193
SuppressSpecificWarnings="$(InscribeSuppressSpecificWarnings)"
194
TreatWarningsAsErrors="$(InscribeTreatWarningsAsErrors)"
195
TreatSpecificWarningsAsErrors="$(InscribeTreatSpecificWarningsAsErrors)"
196
VerboseOutput="$(InscribeVerboseOutput)"
188
- AdditionalOptions="$(InscribeAdditionalOptions)" />
197
+ AdditionalOptions="$(InscribeAdditionalOptions)"
198
+
199
+ RunAsSeparateProcess="$(RunWixToolsOutOfProc)"
200
+ ToolExe="$(WixToolExe)"
201
+ ToolPath="$(WixToolDir)" />
202
</Target>
203
204
<!--
src/wix/test/WixToolsetTest.CoreIntegration/SigningFixture.cs
new
+66
@@ -0,0 +1,66 @@
1
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
+
3
+namespace WixToolsetTest.CoreIntegration
4
+{
5
+ using System.IO;
6
+ using WixBuildTools.TestSupport;
7
+ using WixToolset.Core.TestPackage;
8
+ using Xunit;
9
+
10
+ public class SigningFixture
11
+ {
12
+ [Fact]
13
+ public void CanInscribeMsiWithSignedCabinet()
14
+ {
15
+ var folder = TestData.Get(@"TestData\SingleFileCompressed");
16
+ var signedFolder = TestData.Get(@"TestData\.Data");
17
+
18
+ using (var fs = new DisposableFileSystem())
19
+ {
20
+ var baseFolder = fs.GetFolder();
21
+ var intermediateFolder = Path.Combine(baseFolder, "obj");
22
+ var outputMsi = Path.Combine(intermediateFolder, @"bin\test.msi");
23
+ var signedMsi = Path.Combine(baseFolder, @"signed.msi");
24
+
25
+ var result = WixRunner.Execute(new[]
26
+ {
27
+ "build",
28
+ Path.Combine(folder, "Package.wxs"),
29
+ Path.Combine(folder, "PackageComponents.wxs"),
30
+ "-loc", Path.Combine(folder, "Package.en-us.wxl"),
31
+ "-bindpath", Path.Combine(folder, "data"),
32
+ "-intermediateFolder", intermediateFolder,
33
+ "-o", outputMsi
34
+ });
35
+
36
+ result.AssertSuccess();
37
+
38
+ var beforeRows = Query.QueryDatabase(outputMsi, new[] { "MsiDigitalSignature", "MsiDigitalCertificate" });
39
+ Assert.Empty(beforeRows);
40
+
41
+ // Swap in a pre-signed cabinet since signing during the unit test
42
+ // is a challenge. The cabinet contents almost definitely don't
43
+ // match but that's okay for these testing purposes.
44
+ File.Copy(Path.Combine(signedFolder, "signed_cab1.cab"), Path.Combine(Path.GetDirectoryName(outputMsi), "example.cab"), true);
45
+
46
+ result = WixRunner.Execute(new[]
47
+ {
48
+ "msi",
49
+ "inscribe",
50
+ outputMsi,
51
+ "-o", signedMsi,
52
+ "-intermediateFolder", intermediateFolder,
53
+ });
54
+
55
+ result.AssertSuccess();
56
+
57
+ var rows = Query.QueryDatabase(signedMsi, new[] { "MsiDigitalSignature", "MsiDigitalCertificate" });
58
+ WixAssert.CompareLineByLine(new[]
59
+ {
60
+ "MsiDigitalCertificate:cer8xpsawK5TG4sIx4em8F.i7ocIKU\t[Binary data]",
61
+ "MsiDigitalSignature:Media\t1\tcer8xpsawK5TG4sIx4em8F.i7ocIKU\t"
62
+ }, rows);
63
+ }
64
+ }
65
+ }
66
+}