private static bool IsBundlePackage(string path) { try { using IAppxFileReader fileReader = new ZipArchiveFileReaderAdapter(path); return(fileReader.FileExists(FileConstants.AppxBundleManifestFilePath)); } catch (Exception) { return(false); } }
private static async Task <AppxIdentity> GetIdentityFromBundle(string bundlePath, CancellationToken cancellationToken = default) { try { using IAppxFileReader reader = new ZipArchiveFileReaderAdapter(bundlePath); return(await GetIdentityFromBundleManifest(reader.GetFile(FileConstants.AppxBundleManifestFilePath), cancellationToken).ConfigureAwait(false)); } catch (FileNotFoundException e) { throw new ArgumentException("File " + bundlePath + " is not an APPX/MSIX bundle, because it does not contain a manifest.", nameof(bundlePath), e); } }
private static bool IsMsixPackage(string path) { try { using (IAppxFileReader fileReader = new ZipArchiveFileReaderAdapter(path)) { return(fileReader.FileExists("AppxBlockMap.xml")); } } catch (Exception) { return(false); } }
private static bool IsBundlePackage(string path) { try { using (IAppxFileReader fileReader = new ZipArchiveFileReaderAdapter(path)) { return(fileReader.FileExists("AppxMetadata\\AppxBundleManifest.xml")); } } catch (Exception) { return(false); } }
public async Task <string> CalculateSignatureHashAsync(FileInfo fileInfo, CancellationToken cancellationToken = default, IProgress <ProgressData> progress = null) { var ext = Path.GetExtension(fileInfo.FullName); if ( string.Equals(".appx", ext, StringComparison.OrdinalIgnoreCase) || string.Equals(".msix", ext, StringComparison.OrdinalIgnoreCase) || string.Equals(".appxbundle", ext, StringComparison.OrdinalIgnoreCase) || string.Equals(".msixbundle", ext, StringComparison.OrdinalIgnoreCase)) { using (IAppxFileReader src = new ZipArchiveFileReaderAdapter(fileInfo.FullName)) { if (src.FileExists("AppxSignature.p7x")) { using (var appxSignature = src.GetFile("AppxSignature.p7x")) { var buffer = new byte[ushort.MaxValue]; var read = await appxSignature.ReadAsync(buffer, 0, ushort.MaxValue, cancellationToken).ConfigureAwait(false); var builder = new StringBuilder(); using (var sha = SHA256.Create()) { foreach (var b in sha.ComputeHash(buffer, 0, read)) { cancellationToken.ThrowIfCancellationRequested(); builder.Append(b.ToString("X2")); } return(builder.ToString()); } } } throw new ArgumentException($"The file '{fileInfo.Name}' does not contain a signature.", nameof(fileInfo)); } } var directory = fileInfo.Directory; // ReSharper disable once PossibleNullReferenceException var signatureInfo = new FileInfo(Path.Combine(directory.FullName, "AppxSignature.p7x")); if (signatureInfo.Exists) { return(await CalculateHashAsync(signatureInfo, cancellationToken, progress).ConfigureAwait(false)); } throw new ArgumentException("Only MSIX/APPX formats support signature footprints.", nameof(fileInfo)); }
public async Task <UpdateImpactResults> Analyze( string msixPath1, string msixPath2, bool ignoreVersionCheck = false, CancellationToken cancellationToken = default, IProgress <ProgressData> progressReporter = default) { if (msixPath1 == null) { throw new ArgumentNullException(nameof(msixPath1)); } if (msixPath2 == null) { throw new ArgumentNullException(nameof(msixPath2)); } if (!IsMsixPackage(msixPath1)) { throw new ArgumentException($"File {Path.GetFileName(msixPath1)} is not a valid MSIX."); } if (!IsMsixPackage(msixPath2)) { throw new ArgumentException($"File {Path.GetFileName(msixPath2)} is not a valid MSIX."); } progressReporter?.Report(new ProgressData(0, "Comparing files...")); using (IAppxFileReader fileReader1 = new ZipArchiveFileReaderAdapter(msixPath1)) { using (IAppxFileReader fileReader2 = new ZipArchiveFileReaderAdapter(msixPath2)) { await using (var file1 = fileReader1.GetFile("AppxBlockMap.xml")) { await using (var file2 = fileReader2.GetFile("AppxBlockMap.xml")) { var reader = new AppxBlockMapUpdateImpactAnalyzer(); var result = await reader.Analyze(file1, file2, cancellationToken, progressReporter).ConfigureAwait(false); result.OldPackage = msixPath1; result.NewPackage = msixPath2; return(result); } } } } }
public void ReadFromFile() { var file = Path.Combine("Resources", "ConEmuPack-O2004-M1220.603-P380-F_19.1.8.0_x64__xwfzvwzp69w2e.msix"); using (IAppxFileReader appxFileReader = new ZipArchiveFileReaderAdapter(file)) { var manifestReader = new AppxManifestReader(); var manifest = manifestReader.Read(appxFileReader).GetAwaiter().GetResult(); var app = manifest.Applications[0]; var type = PackageTypeConverter.GetPackageTypeFrom(app.EntryPoint, app.Executable, app.StartPage, manifest.IsFramework); Assert.AreEqual(MsixPackageType.BridgePsf, type); Assert.AreEqual(app.Psf.Executable, "VFS\\AppVPackageDrive\\ConEmuPack\\ConEmu64.exe"); Assert.AreEqual("VFS\\AppVPackageDrive\\ConEmuPack\\PsfLauncher1.exe", app.Executable); } }
private void SourcePathOnValueChanged(object sender, ValueChangedEventArgs e) { try { var ext = Path.GetExtension((string)e.NewValue); if (string.Equals(".msix", ext)) { using (IAppxFileReader reader = new ZipArchiveFileReaderAdapter((string)e.NewValue)) { var mr = new AppxManifestReader(); var read = mr.Read(reader).GetAwaiter().GetResult(); if (string.IsNullOrWhiteSpace(this.DisplayName.CurrentValue)) { this.DisplayName.CurrentValue = read.DisplayName + " - Modification package"; } this.ParentName.CurrentValue = read.Name; this.ParentPublisher.CurrentValue = read.Publisher; } } else { using (IAppxFileReader reader = new FileInfoFileReaderAdapter((string)e.NewValue)) { var mr = new AppxManifestReader(); var read = mr.Read(reader).GetAwaiter().GetResult(); if (string.IsNullOrWhiteSpace(this.DisplayName.CurrentValue)) { this.DisplayName.CurrentValue = read.DisplayName + " - Modification package"; } this.ParentName.CurrentValue = read.Name; this.ParentPublisher.CurrentValue = read.Publisher; } } this.OnPropertyChanged(nameof(IsIncludeVfsFoldersEnabled)); } catch (Exception exception) { Logger.Error(exception); this.interactionService.ShowError("Could not read the properties from the package.", exception); } }
public async Task <UpdateImpactResults> Analyze( string package1Path, string package2Path, bool ignoreVersionCheck = false, CancellationToken cancellationToken = default, IProgress <ProgressData> progressReporter = default) { var type1 = GetPackageTypeFromFile(package1Path); if (type1 == PackageType.Unsupported) { throw new ArgumentException($"File {Path.GetFileName(package1Path)} is not supported."); } var type2 = GetPackageTypeFromFile(package2Path); if (type2 == PackageType.Unsupported) { throw new ArgumentException($"File {Path.GetFileName(package2Path)} is not supported."); } await AssertPackagesUpgradable(package1Path, package2Path, ignoreVersionCheck).ConfigureAwait(false); if (type1 == type2) { switch (type1) { case PackageType.Msix: { var comparer = new MsixUpdateImpactAnalyzer(); var result = await comparer.Analyze(package1Path, package2Path, ignoreVersionCheck, cancellationToken, progressReporter).ConfigureAwait(false); result.OldPackage = package1Path; result.NewPackage = package2Path; return(result); } case PackageType.Manifest: { var comparer = new AppxBlockMapUpdateImpactAnalyzer(); var appxBlock1 = Path.Join(Path.GetDirectoryName(package1Path), "AppxBlockMap.xml"); var appxBlock2 = Path.Join(Path.GetDirectoryName(package2Path), "AppxBlockMap.xml"); var result = await comparer.Analyze(appxBlock1, appxBlock2, ignoreVersionCheck, cancellationToken, progressReporter).ConfigureAwait(false); result.OldPackage = package1Path; result.NewPackage = package2Path; return(result); } case PackageType.Bundle: { var comparer = new BundleUpdateImpactAnalyzer(); var result = await comparer.Analyze(package1Path, package2Path, ignoreVersionCheck, cancellationToken, progressReporter).ConfigureAwait(false); result.OldPackage = package1Path; result.NewPackage = package2Path; return(result); } case PackageType.AppxBlockMap: { var comparer = new AppxBlockMapUpdateImpactAnalyzer(); var result = await comparer.Analyze(package1Path, package2Path, ignoreVersionCheck, cancellationToken, progressReporter).ConfigureAwait(false); result.OldPackage = package1Path; result.NewPackage = package2Path; return(result); } } } else { if (type2 == PackageType.Bundle || type1 == PackageType.Bundle) { throw new NotSupportedException("A bundle can be only compared to another bundle."); } string appxBlock1 = null; string appxBlock2 = null; var tempPaths = new List <string>(); try { switch (type1) { case PackageType.Msix: using (IAppxFileReader fileReader = new ZipArchiveFileReaderAdapter(package1Path)) { using (var msixStream = fileReader.GetFile("AppxBlockMap.xml")) { var tempFile = Path.Join(Path.GetTempPath(), "msix-hero-cp-" + Guid.NewGuid().ToString("N").Substring(0, 8)); using (var fs = File.OpenWrite(tempFile)) { await msixStream.CopyToAsync(fs, cancellationToken).ConfigureAwait(false); await fs.FlushAsync(cancellationToken).ConfigureAwait(false); } tempPaths.Add(tempFile); appxBlock1 = tempFile; } } break; case PackageType.Manifest: appxBlock1 = Path.Join(Path.GetDirectoryName(package1Path), "AppxBlockMap.xml"); break; case PackageType.AppxBlockMap: appxBlock1 = package1Path; break; } switch (type2) { case PackageType.Msix: using (IAppxFileReader fileReader = new ZipArchiveFileReaderAdapter(package2Path)) { using (var msixStream = fileReader.GetFile("AppxBlockMap.xml")) { var tempFile = Path.Join(Path.GetTempPath(), "msix-hero-cp-" + Guid.NewGuid().ToString("N").Substring(0, 8)); using (var fs = File.OpenWrite(tempFile)) { await msixStream.CopyToAsync(fs, cancellationToken).ConfigureAwait(false); await fs.FlushAsync(cancellationToken).ConfigureAwait(false); } tempPaths.Add(tempFile); appxBlock2 = tempFile; } } break; case PackageType.Manifest: appxBlock2 = Path.Join(Path.GetDirectoryName(package2Path), "AppxBlockMap.xml"); break; case PackageType.AppxBlockMap: appxBlock2 = package2Path; break; } var comparer = new AppxBlockMapUpdateImpactAnalyzer(); var result = await comparer.Analyze(appxBlock1, appxBlock2, ignoreVersionCheck, cancellationToken, progressReporter).ConfigureAwait(false); result.OldPackage = package1Path; result.NewPackage = package2Path; return(result); } finally { foreach (var item in tempPaths.Where(File.Exists)) { File.Delete(item); } } } throw new NotSupportedException(); }
private async Task PrepareModificationPackage(XDocument template, ModificationPackageConfig config) { XNamespace nsUap4 = "http://schemas.microsoft.com/appx/manifest/uap/windows10/4"; XNamespace nsUap6 = "http://schemas.microsoft.com/appx/manifest/uap/windows10/6"; XNamespace nsRescap = "http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"; XNamespace nsRescap6 = "http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities/6"; XNamespace nsBuild = "http://schemas.microsoft.com/developer/appx/2015/build"; XNamespace defaultNamespace = "http://schemas.microsoft.com/appx/manifest/foundation/windows10"; var root = template.Root; if (root == null) { root = new XElement(defaultNamespace + "Package"); template.Add(root); } else { defaultNamespace = root.GetDefaultNamespace(); } if (root.GetPrefixOfNamespace(nsUap4) == null) { root.Add(new XAttribute(XNamespace.Xmlns + "uap4", nsUap6.NamespaceName)); } if (root.GetPrefixOfNamespace(nsUap6) == null) { root.Add(new XAttribute(XNamespace.Xmlns + "uap6", nsUap6.NamespaceName)); } if (root.GetPrefixOfNamespace(nsRescap) == null) { root.Add(new XAttribute(XNamespace.Xmlns + "rescap", nsRescap.NamespaceName)); } if (root.GetPrefixOfNamespace(nsRescap6) == null) { root.Add(new XAttribute(XNamespace.Xmlns + "rescap6", nsRescap6.NamespaceName)); } if (root.GetPrefixOfNamespace(nsBuild) == null) { root.Add(new XAttribute(XNamespace.Xmlns + "build", nsBuild.NamespaceName)); } var package = GetOrCreateNode(template, "Package", defaultNamespace); var dependencies = GetOrCreateNode(package, "Dependencies", defaultNamespace); var dependency = new XElement(nsUap4 + "MainPackageDependency"); dependencies.Add(dependency); var parentName = config.ParentName; var parentPublisher = config.ParentPublisher; if (string.IsNullOrEmpty(parentPublisher) || string.IsNullOrEmpty(parentName)) { IAppxFileReader reader = null; try { if (string.Equals(FileConstants.AppxManifestFile, Path.GetFileName(config.ParentPackagePath), StringComparison.OrdinalIgnoreCase)) { reader = new FileInfoFileReaderAdapter(config.ParentPackagePath); } else { reader = new ZipArchiveFileReaderAdapter(config.ParentPackagePath); } var manifestReader = new AppxManifestReader(); var read = await manifestReader.Read(reader).ConfigureAwait(false); if (string.IsNullOrEmpty(parentPublisher)) { parentPublisher = read.Publisher; } if (string.IsNullOrEmpty(parentName)) { parentName = read.Name; } } finally { reader?.Dispose(); } } dependency.SetAttributeValue("Name", parentName); dependency.SetAttributeValue("Publisher", parentPublisher); var identity = GetOrCreateNode(package, "Identity", defaultNamespace); identity.SetAttributeValue("Name", config.Name); identity.SetAttributeValue("Publisher", config.Publisher); var fixVersion = Version.Parse(config.Version); var major = fixVersion.Major; var minor = fixVersion.Minor; var build = fixVersion.Build; var revision = fixVersion.Revision; if (major < 0) { throw new FormatException("Invalid version format, major version is required."); } if (minor < 0) { throw new FormatException("Invalid version format, major version is required."); } if (revision < 0) { revision = 0; } if (build < 0) { build = 0; } identity.SetAttributeValue("Version", new Version(major, minor, build, revision).ToString(4)); var properties = GetOrCreateNode(package, "Properties", defaultNamespace); GetOrCreateNode(properties, "DisplayName", defaultNamespace).Value = config.DisplayName ?? "Modification Package Name"; GetOrCreateNode(properties, "PublisherDisplayName", defaultNamespace).Value = config.DisplayPublisher ?? "Modification Package Publisher Name"; GetOrCreateNode(properties, "Description", defaultNamespace).Value = "Modification Package for " + parentName; GetOrCreateNode(properties, "Logo", defaultNamespace).Value = "Assets\\Logo.png"; GetOrCreateNode(properties, "ModificationPackage", nsRescap6).Value = "true"; var branding = new MsixHeroBrandingInjector(); branding.Inject(template); }
public async Task <AppxIdentity> GetIdentity(Stream file, CancellationToken cancellationToken = default) { if (file == null) { throw new ArgumentNullException(nameof(file)); } Logger.Info("Reading identity from stream of type " + file.GetType().Name); if (file is FileStream fileStream) { Logger.Debug("The input is a file stream, trying to evaluate its name..."); switch (Path.GetExtension(fileStream.Name).ToLowerInvariant()) { case FileConstants.AppxBundleExtension: case FileConstants.MsixBundleExtension: { Logger.Info("The file seems to be a bundle package (compressed)."); try { using IAppxFileReader reader = new ZipArchiveFileReaderAdapter(fileStream); return(await GetIdentityFromBundleManifest(reader.GetFile(FileConstants.AppxBundleManifestFilePath), cancellationToken).ConfigureAwait(false)); } catch (FileNotFoundException e) { throw new ArgumentException("File " + fileStream.Name + " is not an APPX/MSIX bundle, because it does not contain a manifest.", nameof(file), e); } } case FileConstants.AppxExtension: case FileConstants.MsixExtension: { Logger.Info("The file seems to be a package (compressed)."); try { using IAppxFileReader reader = new ZipArchiveFileReaderAdapter(fileStream); return(await GetIdentityFromBundleManifest(reader.GetFile(FileConstants.AppxManifestFile), cancellationToken).ConfigureAwait(false)); } catch (FileNotFoundException e) { throw new ArgumentException("File " + fileStream.Name + " is not an APPX/MSIX package, because it does not contain a manifest.", nameof(file), e); } } } switch (Path.GetFileName(fileStream.Name).ToLowerInvariant()) { case FileConstants.AppxManifestFile: Logger.Info("The file seems to be a package (manifest)."); return(await GetIdentityFromPackageManifest(fileStream, cancellationToken).ConfigureAwait(false)); case FileConstants.AppxBundleManifestFile: Logger.Info("The file seems to be a bundle (manifest)."); return(await GetIdentityFromBundleManifest(fileStream, cancellationToken).ConfigureAwait(false)); } } try { Logger.Debug("Trying to interpret the input file as an XML manifest..."); var doc = await XDocument.LoadAsync(file, LoadOptions.None, cancellationToken).ConfigureAwait(false); var firstElement = doc.Elements().FirstOrDefault(); if (firstElement != null) { if (firstElement.Name.LocalName == "Package") { Logger.Info("The file seems to be a package (manifest)."); return(GetIdentityFromPackageManifest(doc)); } if (firstElement.Name.LocalName == "Bundle") { Logger.Info("The file seems to be a bundle (manifest)."); return(GetIdentityFromBundleManifest(doc)); } // This is an XML file but neither a package manifest or a bundle manifest, so we can stop here. throw new ArgumentException("This XML file is neither package nor a bundle manifest (missing <Package /> or <Bundle /> root element)."); } } catch { // this is ok, it seems that the file was not XML so we should continue to find out some other possibilities Logger.Debug("The file was not in XML format (exception thrown during parsing)."); } try { file.Seek(0, SeekOrigin.Begin); using var zip = new ZipArchive(file, ZipArchiveMode.Read, true); using IAppxFileReader reader = new ZipArchiveFileReaderAdapter(zip); if (reader.FileExists(FileConstants.AppxManifestFile)) { return(await GetIdentityFromPackageManifest(reader.GetFile(FileConstants.AppxManifestFile), cancellationToken).ConfigureAwait(false)); } if (reader.FileExists(FileConstants.AppxBundleManifestFilePath)) { return(await GetIdentityFromBundleManifest(reader.GetFile(FileConstants.AppxBundleManifestFilePath), cancellationToken).ConfigureAwait(false)); } // This is a ZIP archive but neither a package or bundle, so we can stop here. throw new ArgumentException("This compressed file is neither an APPX/MSIX or bundle because it contains no manifest file."); } catch { // this is ok, it seems that the file was not ZIP format so we should continue to find out some other possibilities Logger.Debug("The file was not in ZIP format (exception thrown during opening)."); } throw new ArgumentException("The input stream is neither a valid manifest or package file."); }
private async Task <YamlDefinition> CreateFromMsix(string filePath, CancellationToken cancellationToken = default) { var yamlDefinition = new YamlDefinition() { Installers = new List <YamlInstaller> { new YamlInstaller { Scope = YamlScope.user, InstallerType = YamlInstallerType.msix } } }; IAppxFileReader reader; if (filePath.EndsWith(".xml", StringComparison.OrdinalIgnoreCase)) { reader = new FileInfoFileReaderAdapter(filePath); } else { reader = new ZipArchiveFileReaderAdapter(filePath); try { yamlDefinition.Installers[0].SignatureSha256 = await this.CalculateSignatureHashAsync(new FileInfo(filePath), cancellationToken).ConfigureAwait(false); } catch (ArgumentException) { } } using (reader) { var manifestReader = new AppxManifestReader(); var details = await manifestReader.Read(reader, cancellationToken).ConfigureAwait(false); yamlDefinition.Name = details.DisplayName; yamlDefinition.Publisher = details.PublisherDisplayName; yamlDefinition.Version = details.Version; yamlDefinition.Description = details.Description; if (details.Applications?.Any() == true) { // Exclude some unrelated PSF stuff - they are not the right choice for the app moniker. var candidateForAppMoniker = details.Applications.Select(a => a.Executable) .FirstOrDefault(a => !string.IsNullOrEmpty(a) && !a.StartsWith("psf", StringComparison.OrdinalIgnoreCase) && !a.StartsWith("AI_stubs", StringComparison.OrdinalIgnoreCase) && a.EndsWith(".exe", StringComparison.OrdinalIgnoreCase)); if (!string.IsNullOrEmpty(candidateForAppMoniker)) { yamlDefinition.AppMoniker = candidateForAppMoniker.Substring(0, candidateForAppMoniker.Length - ".exe".Length).Split('\\', '/').Last(); } } switch (details.ProcessorArchitecture) { case AppxPackageArchitecture.Arm: yamlDefinition.Installers[0].Arch = YamlArchitecture.arm; break; case AppxPackageArchitecture.Neutral: yamlDefinition.Installers[0].Arch = YamlArchitecture.Neutral; break; case AppxPackageArchitecture.Arm64: yamlDefinition.Installers[0].Arch = YamlArchitecture.arm64; break; case AppxPackageArchitecture.x86: yamlDefinition.Installers[0].Arch = YamlArchitecture.x86; break; case AppxPackageArchitecture.x64: yamlDefinition.Installers[0].Arch = YamlArchitecture.x64; break; } } return(yamlDefinition); }