winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

Helpers.cs (7385B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 
      4 namespace Microsoft.WinGetSourceCreator
      5 {
      6     using global::WinGetSourceCreator.Model;
      7     using Microsoft.Msix.Utils.ProcessRunner;
      8     using System.Diagnostics;
      9     using System.Xml;
     10 
     11     internal static class Helpers
     12     {
     13         public static void SignInstaller(SourceInstaller installer, Signature signature)
     14         {
     15             if (installer.Type == InstallerType.Msix)
     16             {
     17                 SignMsixFile(installer.InstallerFile, signature);
     18             }
     19             else
     20             {
     21                 SignFile(installer.InstallerFile, signature);
     22             }
     23         }
     24 
     25         public static void SignFile(string fileToSign, Signature signature)
     26         {
     27             if (!File.Exists(fileToSign))
     28             {
     29                 throw new FileNotFoundException(fileToSign);
     30             }
     31 
     32             if (!File.Exists(signature.CertFile))
     33             {
     34                 throw new FileNotFoundException(signature.CertFile);
     35             }
     36 
     37             string pathToSDK = SDKDetector.Instance.LatestSDKBinPath;
     38             string signtoolExecutable = Path.Combine(pathToSDK, "signtool.exe");
     39             string command = $"sign /a /fd sha256 /f {signature.CertFile} ";
     40             if (!string.IsNullOrEmpty(signature.Password))
     41             {
     42                 command += $"/p {signature.Password} ";
     43             }
     44             command += fileToSign;
     45             RunCommand(signtoolExecutable, command);
     46         }
     47 
     48         public static void SignMsixFile(string fileToSign, Signature signature)
     49         {
     50             if (!File.Exists(fileToSign))
     51             {
     52                 throw new FileNotFoundException(fileToSign);
     53             }
     54 
     55             // Modify publisher if needed.
     56             if (signature.Publisher != null)
     57             {
     58                 string tmpPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
     59                 Unpack(fileToSign, tmpPath);
     60                 ModifyAppxManifestIdentity(Path.Combine(tmpPath, "AppxManifest.xml"), signature.Publisher);
     61                 Pack(fileToSign, tmpPath);
     62 
     63                 try
     64                 {
     65                     Directory.Delete(tmpPath, true);
     66                 }
     67                 catch (Exception)
     68                 {
     69                 }
     70             }
     71 
     72             SignFile(fileToSign, signature);
     73         }
     74 
     75         public static void Unpack(string package, string outDir)
     76         {
     77             if (!File.Exists(package))
     78             {
     79                 throw new FileNotFoundException(package);
     80             }
     81 
     82             string pathToSDK = SDKDetector.Instance.LatestSDKBinPath;
     83             string makeappxExecutable = Path.Combine(pathToSDK, "makeappx.exe");
     84             string args = $"unpack /nv /p {package} /d {outDir}";
     85             Process p = new Process
     86             {
     87                 StartInfo = new ProcessStartInfo(makeappxExecutable, args)
     88             };
     89             p.Start();
     90             p.WaitForExit();
     91         }
     92 
     93         public static void PackWithMappingFile(string outputPackage, string mappingFile)
     94         {
     95             if (!File.Exists(mappingFile))
     96             {
     97                 throw new FileNotFoundException(mappingFile);
     98             }
     99 
    100             string pathToSDK = SDKDetector.Instance.LatestSDKBinPath;
    101             string makeappxExecutable = Path.Combine(pathToSDK, "makeappx.exe");
    102             string args = $"pack /o /nv /f {mappingFile} /p {outputPackage}";
    103             RunCommand(makeappxExecutable, args);
    104         }
    105 
    106         public static void Pack(string outputPackage, string directoryToPack)
    107         {
    108             if (!Directory.Exists(directoryToPack))
    109             {
    110                 throw new DirectoryNotFoundException(directoryToPack);
    111             }
    112 
    113             if (File.Exists(outputPackage))
    114             {
    115                 File.Delete(outputPackage);
    116             }
    117 
    118             string pathToSDK = SDKDetector.Instance.LatestSDKBinPath;
    119             string makeappxExecutable = Path.Combine(pathToSDK, "makeappx.exe");
    120             string args = $"pack /o /d {directoryToPack} /p {outputPackage}";
    121             RunCommand(makeappxExecutable, args);
    122         }
    123 
    124         public static void RunCommand(string command, string args, string? workingDirectory = null)
    125         {
    126             Process p = new()
    127             {
    128                 StartInfo = new ProcessStartInfo(command, args)
    129             };
    130 
    131             if (workingDirectory != null)
    132             {
    133                 p.StartInfo.WorkingDirectory = workingDirectory;
    134             }
    135             p.Start();
    136             p.WaitForExit();
    137         }
    138 
    139         // If in the future we edit more elements, this should be a nice wrapper class.
    140         public static void ModifyAppxManifestIdentity(string manifestFile, string? identityPublisher)
    141         {
    142             if (!File.Exists(manifestFile))
    143             {
    144                 throw new FileNotFoundException(manifestFile);
    145             }
    146 
    147             var xmlDoc = new XmlDocument();
    148             XmlNamespaceManager namespaces = new XmlNamespaceManager(xmlDoc.NameTable);
    149             namespaces.AddNamespace("n", "http://schemas.microsoft.com/appx/manifest/foundation/windows10");
    150             xmlDoc.Load(manifestFile);
    151             var identityNode = xmlDoc.SelectSingleNode("/n:Package/n:Identity", namespaces);
    152             if (identityNode == null)
    153             {
    154                 throw new NullReferenceException("Identity node");
    155             }
    156 
    157             if (!string.IsNullOrEmpty(identityPublisher))
    158             {
    159                 var attr = identityNode.Attributes?["Publisher"];
    160                 if (attr == null)
    161                 {
    162                     throw new NullReferenceException("Publisher attribute");
    163                 }
    164                 attr.Value = identityPublisher;
    165             }
    166 
    167             xmlDoc.Save(manifestFile);
    168         }
    169 
    170         // Gets the AppxSignature.p7x file.
    171         public static string GetSignatureFileFromMsix(string packageFilePath)
    172         {
    173             string extractedPackageDest = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
    174             if (Directory.Exists(extractedPackageDest))
    175             {
    176                 Directory.Delete(extractedPackageDest, true);
    177             }
    178 
    179             Helpers.Unpack(packageFilePath, extractedPackageDest);
    180 
    181             return Path.Combine(extractedPackageDest, "AppxSignature.p7x");
    182         }
    183 
    184         public static void CopyDirectory(string sourceDirName, string destDirName)
    185         {
    186             if (!Directory.Exists(destDirName))
    187             {
    188                 Directory.CreateDirectory(destDirName);
    189             }
    190 
    191             DirectoryInfo dir = new (sourceDirName);
    192             DirectoryInfo[] dirs = dir.GetDirectories();
    193 
    194             FileInfo[] files = dir.GetFiles();
    195             foreach (FileInfo file in files)
    196             {
    197                 string temppath = Path.Combine(destDirName, file.Name);
    198                 file.CopyTo(temppath, false);
    199             }
    200 
    201             foreach (DirectoryInfo subdir in dirs)
    202             {
    203                 string temppath = Path.Combine(destDirName, subdir.Name);
    204                 CopyDirectory(subdir.FullName, temppath);
    205             }
    206         }
    207     }
    208 }