aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2022-01-08 07:44:33 -0800
committerRob Mensching <rob@firegiant.com>2022-01-10 17:08:43 -0800
commit4182d6d594301b88d4780d0222a3d1448b524fde (patch)
tree3dd0aeb1e8346b4cae625022f6b501122998378f /src
parentcec50194881e99d1f3ef1c8a2537e2eb0c124d75 (diff)
downloadwix-4182d6d594301b88d4780d0222a3d1448b524fde.tar.gz
wix-4182d6d594301b88d4780d0222a3d1448b524fde.tar.bz2
wix-4182d6d594301b88d4780d0222a3d1448b524fde.zip
Introduce "msi inscribe" command and use it in wix.signing.targets
Diffstat (limited to 'src')
-rw-r--r--src/wix/WixToolset.BuildTasks/InscribeMsiWithCabinetSignatures.cs33
-rw-r--r--src/wix/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs51
-rw-r--r--src/wix/WixToolset.Core.WindowsInstaller/InscribeSubcommand.cs80
-rw-r--r--src/wix/WixToolset.Core.WindowsInstaller/MsiBackend.cs6
-rw-r--r--src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerCommand.cs73
-rw-r--r--src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerExtensionCommandLine.cs41
-rw-r--r--src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerExtensionFactory.cs15
-rw-r--r--src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerSubcommandBase.cs15
-rw-r--r--src/wix/WixToolset.Sdk/tools/wix.signing.targets27
-rw-r--r--src/wix/test/WixToolsetTest.CoreIntegration/SigningFixture.cs66
10 files changed, 376 insertions, 31 deletions
diff --git a/src/wix/WixToolset.BuildTasks/InscribeMsiWithCabinetSignatures.cs b/src/wix/WixToolset.BuildTasks/InscribeMsiWithCabinetSignatures.cs
new file mode 100644
index 00000000..9f78caa5
--- /dev/null
+++ b/src/wix/WixToolset.BuildTasks/InscribeMsiWithCabinetSignatures.cs
@@ -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
3namespace 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}
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs
index 57f2f753..80fcb8e1 100644
--- a/src/wix/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs
+++ b/src/wix/WixToolset.Core.WindowsInstaller/Inscribe/InscribeMsiPackageCommand.cs
@@ -12,20 +12,25 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
12 using WixToolset.Core.WindowsInstaller.Bind; 12 using WixToolset.Core.WindowsInstaller.Bind;
13 using WixToolset.Data; 13 using WixToolset.Data;
14 using WixToolset.Data.WindowsInstaller; 14 using WixToolset.Data.WindowsInstaller;
15 using WixToolset.Extensibility.Data;
16 using WixToolset.Extensibility.Services; 15 using WixToolset.Extensibility.Services;
17 16
18 internal class InscribeMsiPackageCommand 17 internal class InscribeMsiPackageCommand
19 { 18 {
20 public InscribeMsiPackageCommand(IInscribeContext context) 19 public InscribeMsiPackageCommand(IServiceProvider serviceProvider, string inputPath, string intermediateFolder, string outputPath)
21 { 20 {
22 this.Context = context; 21 this.Messaging = serviceProvider.GetService<IMessaging>();
23 this.Messaging = context.ServiceProvider.GetService<IMessaging>(); 22 this.WindowsInstallerBackendHelper = serviceProvider.GetService<IWindowsInstallerBackendHelper>();
24 this.WindowsInstallerBackendHelper = context.ServiceProvider.GetService<IWindowsInstallerBackendHelper>();
25 this.TableDefinitions = new TableDefinitionCollection(WindowsInstallerTableDefinitions.All); 23 this.TableDefinitions = new TableDefinitionCollection(WindowsInstallerTableDefinitions.All);
24 this.InputPath = inputPath;
25 this.IntermediateFolder = intermediateFolder;
26 this.OutputPath = outputPath;
26 } 27 }
27 28
28 private IInscribeContext Context { get; } 29 private string InputPath { get; }
30
31 private string IntermediateFolder { get; }
32
33 private string OutputPath { get; }
29 34
30 private IMessaging Messaging { get; } 35 private IMessaging Messaging { get; }
31 36
@@ -39,14 +44,22 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
39 var foundUnsignedExternals = false; 44 var foundUnsignedExternals = false;
40 var shouldCommit = false; 45 var shouldCommit = false;
41 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);
43 if (FileAttributes.ReadOnly == (attributes & FileAttributes.ReadOnly)) 56 if (FileAttributes.ReadOnly == (attributes & FileAttributes.ReadOnly))
44 { 57 {
45 this.Messaging.Write(ErrorMessages.ReadOnlyOutputFile(this.Context.InputFilePath)); 58 this.Messaging.Write(ErrorMessages.ReadOnlyOutputFile(databasePath));
46 return shouldCommit; 59 return shouldCommit;
47 } 60 }
48 61
49 using (var database = new Database(this.Context.InputFilePath, OpenDatabase.Transact)) 62 using (var database = new Database(databasePath, OpenDatabase.Transact))
50 { 63 {
51 // Just use the English codepage, because the tables we're importing only have binary streams / MSI identifiers / other non-localizable content 64 // Just use the English codepage, because the tables we're importing only have binary streams / MSI identifiers / other non-localizable content
52 var codepage = 1252; 65 var codepage = 1252;
@@ -65,8 +78,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
65 { 78 {
66 foreach (var digitalSignatureRecord in digitalSignatureView.Records) 79 foreach (var digitalSignatureRecord in digitalSignatureView.Records)
67 { 80 {
68 Row digitalSignatureRow = null; 81 var digitalSignatureRow = digitalSignatureTable.CreateRow(null);
69 digitalSignatureRow = digitalSignatureTable.CreateRow(null);
70 82
71 var table = digitalSignatureRecord.GetString(0); 83 var table = digitalSignatureRecord.GetString(0);
72 var signObject = digitalSignatureRecord.GetString(1); 84 var signObject = digitalSignatureRecord.GetString(1);
@@ -78,7 +90,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
78 if (false == digitalSignatureRecord.IsNull(3)) 90 if (false == digitalSignatureRecord.IsNull(3))
79 { 91 {
80 // Export to a file, because the MSI API's require us to provide a file path on disk 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");
82 var hashFileName = String.Concat(table, ".", signObject, ".bin"); 94 var hashFileName = String.Concat(table, ".", signObject, ".bin");
83 95
84 Directory.CreateDirectory(hashPath); 96 Directory.CreateDirectory(hashPath);
@@ -111,7 +123,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
111 var certificateId = digitalCertificateRecord.GetString(1); // get the identifier of the certificate 123 var certificateId = digitalCertificateRecord.GetString(1); // get the identifier of the certificate
112 124
113 // Export to a file, because the MSI API's require us to provide a file path on disk 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");
115 Directory.CreateDirectory(certPath); 127 Directory.CreateDirectory(certPath);
116 certPath = Path.Combine(certPath, String.Concat(certificateId, ".cer")); 128 certPath = Path.Combine(certPath, String.Concat(certificateId, ".cer"));
117 129
@@ -147,7 +159,6 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
147 foreach (var mediaRecord in mediaView.Records) 159 foreach (var mediaRecord in mediaView.Records)
148 { 160 {
149 X509Certificate2 cert2 = null; 161 X509Certificate2 cert2 = null;
150 Row digitalSignatureRow = null;
151 162
152 var cabName = mediaRecord.GetString(4); // get the name of the cab 163 var cabName = mediaRecord.GetString(4); // get the name of the cab
153 // If there is no cabinet or it's an internal cab, skip it. 164 // If there is no cabinet or it's an internal cab, skip it.
@@ -157,7 +168,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
157 } 168 }
158 169
159 var cabId = mediaRecord.GetString(1); // get the ID of the cab 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);
161 172
162 // If the cabs aren't there, throw an error but continue to catch the other errors 173 // If the cabs aren't there, throw an error but continue to catch the other errors
163 if (!File.Exists(cabPath)) 174 if (!File.Exists(cabPath))
@@ -207,7 +218,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
207 digitalCertificateRow[0] = certificateGeneratedId; 218 digitalCertificateRow[0] = certificateGeneratedId;
208 219
209 // Export to a file, because the MSI API's require us to provide a file path on disk 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");
211 Directory.CreateDirectory(certPath); 222 Directory.CreateDirectory(certPath);
212 certPath = Path.Combine(certPath, String.Concat(cert2.Thumbprint, ".cer")); 223 certPath = Path.Combine(certPath, String.Concat(cert2.Thumbprint, ".cer"));
213 File.Delete(certPath); 224 File.Delete(certPath);
@@ -224,7 +235,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
224 certificates.Add(cert2.Thumbprint, certificateGeneratedId); 235 certificates.Add(cert2.Thumbprint, certificateGeneratedId);
225 } 236 }
226 237
227 digitalSignatureRow = digitalSignatureTable.CreateRow(null); 238 var digitalSignatureRow = digitalSignatureTable.CreateRow(null);
228 239
229 digitalSignatureRow[0] = "Media"; 240 digitalSignatureRow[0] = "Media";
230 digitalSignatureRow[1] = cabId; 241 digitalSignatureRow[1] = cabId;
@@ -234,7 +245,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
234 245
235 if (digitalCertificateTable.Rows.Count > 0) 246 if (digitalCertificateTable.Rows.Count > 0)
236 { 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);
238 command.Execute(); 249 command.Execute();
239 250
240 database.Import(command.IdtPath); 251 database.Import(command.IdtPath);
@@ -243,7 +254,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
243 254
244 if (digitalSignatureTable.Rows.Count > 0) 255 if (digitalSignatureTable.Rows.Count > 0)
245 { 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);
247 command.Execute(); 258 command.Execute();
248 259
249 database.Import(command.IdtPath); 260 database.Import(command.IdtPath);
@@ -257,7 +268,7 @@ namespace WixToolset.Core.WindowsInstaller.Inscribe
257 // If we did find external cabs but not all of them were signed, give a warning 268 // If we did find external cabs but not all of them were signed, give a warning
258 if (foundUnsignedExternals) 269 if (foundUnsignedExternals)
259 { 270 {
260 this.Messaging.Write(WarningMessages.ExternalCabsAreNotSigned(this.Context.InputFilePath)); 271 this.Messaging.Write(WarningMessages.ExternalCabsAreNotSigned(this.InputPath));
261 } 272 }
262 273
263 if (shouldCommit) 274 if (shouldCommit)
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/InscribeSubcommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/InscribeSubcommand.cs
new file mode 100644
index 00000000..d44fb0bd
--- /dev/null
+++ b/src/wix/WixToolset.Core.WindowsInstaller/InscribeSubcommand.cs
@@ -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
3namespace 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}
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/MsiBackend.cs b/src/wix/WixToolset.Core.WindowsInstaller/MsiBackend.cs
index 3bd58c25..ab8def5f 100644
--- a/src/wix/WixToolset.Core.WindowsInstaller/MsiBackend.cs
+++ b/src/wix/WixToolset.Core.WindowsInstaller/MsiBackend.cs
@@ -2,6 +2,7 @@
2 2
3namespace WixToolset.Core.WindowsInstaller 3namespace WixToolset.Core.WindowsInstaller
4{ 4{
5 using System;
5 using WixToolset.Core.WindowsInstaller.Bind; 6 using WixToolset.Core.WindowsInstaller.Bind;
6 using WixToolset.Core.WindowsInstaller.Decompile; 7 using WixToolset.Core.WindowsInstaller.Decompile;
7 using WixToolset.Core.WindowsInstaller.Inscribe; 8 using WixToolset.Core.WindowsInstaller.Inscribe;
@@ -72,8 +73,9 @@ namespace WixToolset.Core.WindowsInstaller
72 73
73 public bool Inscribe(IInscribeContext context) 74 public bool Inscribe(IInscribeContext context)
74 { 75 {
75 var command = new InscribeMsiPackageCommand(context); 76 //var command = new InscribeMsiPackageCommand(context);
76 return command.Execute(); 77 //return command.Execute();
78 throw new NotImplementedException();
77 } 79 }
78 80
79 public Intermediate Unbind(IUnbindContext context) 81 public Intermediate Unbind(IUnbindContext context)
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerCommand.cs
new file mode 100644
index 00000000..cedc65b2
--- /dev/null
+++ b/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerCommand.cs
@@ -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
3namespace 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}
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerExtensionCommandLine.cs b/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerExtensionCommandLine.cs
new file mode 100644
index 00000000..4c516d0d
--- /dev/null
+++ b/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerExtensionCommandLine.cs
@@ -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
3namespace 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}
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerExtensionFactory.cs b/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerExtensionFactory.cs
index 7b12fc8c..0eb4df5e 100644
--- a/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerExtensionFactory.cs
+++ b/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerExtensionFactory.cs
@@ -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 2
3namespace WixToolset.Core.WindowsInstaller 3namespace WixToolset.Core.WindowsInstaller
4{ 4{
@@ -7,11 +7,22 @@ namespace WixToolset.Core.WindowsInstaller
7 7
8 internal class WindowsInstallerExtensionFactory : IExtensionFactory 8 internal class WindowsInstallerExtensionFactory : IExtensionFactory
9 { 9 {
10 public WindowsInstallerExtensionFactory(IServiceProvider serviceProvider)
11 {
12 this.ServiceProvider = serviceProvider;
13 }
14
15 private IServiceProvider ServiceProvider { get; }
16
10 public bool TryCreateExtension(Type extensionType, out object extension) 17 public bool TryCreateExtension(Type extensionType, out object extension)
11 { 18 {
12 extension = null; 19 extension = null;
13 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))
15 { 26 {
16 extension = new WindowsInstallerBackendFactory(); 27 extension = new WindowsInstallerBackendFactory();
17 } 28 }
diff --git a/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerSubcommandBase.cs b/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerSubcommandBase.cs
new file mode 100644
index 00000000..c5156a1d
--- /dev/null
+++ b/src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerSubcommandBase.cs
@@ -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
3namespace 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}
diff --git a/src/wix/WixToolset.Sdk/tools/wix.signing.targets b/src/wix/WixToolset.Sdk/tools/wix.signing.targets
index 5a4ea98d..3df05d51 100644
--- a/src/wix/WixToolset.Sdk/tools/wix.signing.targets
+++ b/src/wix/WixToolset.Sdk/tools/wix.signing.targets
@@ -11,6 +11,10 @@
11 <UsingTask TaskName="GetCabList" AssemblyFile="$(WixTasksPath)" /> 11 <UsingTask TaskName="GetCabList" AssemblyFile="$(WixTasksPath)" />
12 <UsingTask TaskName="GetLooseFileList" AssemblyFile="$(WixTasksPath)" /> 12 <UsingTask TaskName="GetLooseFileList" AssemblyFile="$(WixTasksPath)" />
13 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
14 <!-- Default Inscribe properties. --> 18 <!-- Default Inscribe properties. -->
15 <PropertyGroup> 19 <PropertyGroup>
16 <InscribeNoLogo Condition=" '$(InscribeNoLogo)' == '' ">$(NoLogo)</InscribeNoLogo> 20 <InscribeNoLogo Condition=" '$(InscribeNoLogo)' == '' ">$(NoLogo)</InscribeNoLogo>
@@ -21,6 +25,10 @@
21 <InscribeVerboseOutput Condition=" '$(InscribeVerboseOutput)' == '' ">$(VerboseOutput)</InscribeVerboseOutput> 25 <InscribeVerboseOutput Condition=" '$(InscribeVerboseOutput)' == '' ">$(VerboseOutput)</InscribeVerboseOutput>
22 </PropertyGroup> 26 </PropertyGroup>
23 27
28 <PropertyGroup>
29 <SignOutputCabs Condition=" '$(SignOutputCabs)'=='' ">$(SignOutput)</SignOutputCabs>
30 </PropertyGroup>
31
24 <!-- 32 <!--
25 ================================================================================================== 33 ==================================================================================================
26 Signing 34 Signing
@@ -58,7 +66,7 @@
58 <Target 66 <Target
59 Name="Signing" 67 Name="Signing"
60 DependsOnTargets="$(SigningDependsOn)" 68 DependsOnTargets="$(SigningDependsOn)"
61 Inputs="$(TargetPath)" 69 Inputs="@(_WixBuildOutputFile)"
62 Outputs="$(SignedFilePath)" 70 Outputs="$(SignedFilePath)"
63 Condition=" '$(SignOutput)' == 'true' "> 71 Condition=" '$(SignOutput)' == 'true' ">
64 72
@@ -76,7 +84,7 @@
76 <Target 84 <Target
77 Name="CalculateSignTargetFiles"> 85 Name="CalculateSignTargetFiles">
78 <ItemGroup> 86 <ItemGroup>
79 <SignTargetPath Include="$(TargetPath)" /> 87 <SignTargetPath Include="@(_WixBuildOutputFile)" />
80 </ItemGroup> 88 </ItemGroup>
81 </Target> 89 </Target>
82 90
@@ -98,7 +106,8 @@
98 <Target 106 <Target
99 Name="GetCabsToSign" 107 Name="GetCabsToSign"
100 Inputs="@(SignTargetPath)" 108 Inputs="@(SignTargetPath)"
101 Outputs="$(SignedFilePath)"> 109 Outputs="$(SignedFilePath)"
110 Condition=" '$(SignOutputCabs)' == 'true' ">
102 <GetCabList Database="%(SignTargetPath.FullPath)"> 111 <GetCabList Database="%(SignTargetPath.FullPath)">
103 <Output TaskParameter="CabList" ItemName="SignCabs" /> 112 <Output TaskParameter="CabList" ItemName="SignCabs" />
104 <Output TaskParameter="CabList" ItemName="FileWrites" /> 113 <Output TaskParameter="CabList" ItemName="FileWrites" />
@@ -174,18 +183,22 @@
174 Outputs="$(SignedFilePath)" 183 Outputs="$(SignedFilePath)"
175 Condition=" '@(SignCabs)' != '' "> 184 Condition=" '@(SignCabs)' != '' ">
176 185
177 <Insignia 186 <InscribeMsiWithCabinetSignatures
178 DatabaseFile="%(SignTargetPath.FullPath)" 187 DatabaseFile="%(SignTargetPath.FullPath)"
179 OutputFile="%(SignTargetPath.FullPath)" 188 OutputFile="%(SignTargetPath.FullPath)"
180 ToolPath="$(WixToolPath)" 189 IntermediateDirectory="%(SignTargetPath.RootDir)%(SignTargetPath.Directory)"
190
181 NoLogo="$(InscribeNoLogo)" 191 NoLogo="$(InscribeNoLogo)"
182 RunAsSeparateProcess="$(RunWixToolsOutOfProc)"
183 SuppressAllWarnings="$(InscribeSuppressAllWarnings)" 192 SuppressAllWarnings="$(InscribeSuppressAllWarnings)"
184 SuppressSpecificWarnings="$(InscribeSuppressSpecificWarnings)" 193 SuppressSpecificWarnings="$(InscribeSuppressSpecificWarnings)"
185 TreatWarningsAsErrors="$(InscribeTreatWarningsAsErrors)" 194 TreatWarningsAsErrors="$(InscribeTreatWarningsAsErrors)"
186 TreatSpecificWarningsAsErrors="$(InscribeTreatSpecificWarningsAsErrors)" 195 TreatSpecificWarningsAsErrors="$(InscribeTreatSpecificWarningsAsErrors)"
187 VerboseOutput="$(InscribeVerboseOutput)" 196 VerboseOutput="$(InscribeVerboseOutput)"
188 AdditionalOptions="$(InscribeAdditionalOptions)" /> 197 AdditionalOptions="$(InscribeAdditionalOptions)"
198
199 RunAsSeparateProcess="$(RunWixToolsOutOfProc)"
200 ToolExe="$(WixToolExe)"
201 ToolPath="$(WixToolDir)" />
189 </Target> 202 </Target>
190 203
191 <!-- 204 <!--
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/SigningFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/SigningFixture.cs
new file mode 100644
index 00000000..79896172
--- /dev/null
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/SigningFixture.cs
@@ -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
3namespace 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}