예제 #1
0
        public void TestMessages()
        {
            var progress = new TestProgress();

            using (var wrapped = new WrappedProgress(progress))
            {
                var progressA = wrapped.GetChildProgress();
                var progressB = wrapped.GetChildProgress();

                progressA.Report(new ProgressData(10, "A1"));
                Assert.AreEqual("A1", progress.Last.Message);

                progressA.Report(new ProgressData(20, "A2"));
                Assert.AreEqual("A2", progress.Last.Message);

                progressB.Report(new ProgressData(10, "B1"));
                Assert.AreEqual("B1", progress.Last.Message);

                progressA.Report(new ProgressData(100, "A3"));
                Assert.AreEqual("A3", progress.Last.Message);

                progressB.Report(new ProgressData(100, "B2"));
                Assert.AreEqual("B2", progress.Last.Message);
            }
        }
예제 #2
0
        public void TestZeroWeight()
        {
            var progress = new TestProgress();

            using (var wrapped = new WrappedProgress(progress))
            {
                Assert.Throws <ArgumentOutOfRangeException>(() => wrapped.GetChildProgress(0), "Zero weight must throw ArgumentOutOfRange exception.");
                Assert.Throws <ArgumentOutOfRangeException>(() => wrapped.GetChildProgress(-1), "Negative weight must throw ArgumentOutOfRange exception.");
            }
        }
예제 #3
0
        public void TestNullParent()
        {
            using (var wrapped = new WrappedProgress(null))
            {
                var p1 = wrapped.GetChildProgress();
                var p2 = wrapped.GetChildProgress();

                // The following may not throw. This class should by design handle cases where parent is null,
                // by simply swallowing sub-progress reports.
                p1.Report(new ProgressData(10, "test"));
                p2.Report(new ProgressData(10, "test"));
            }
        }
예제 #4
0
        protected override async Task <bool> Save(CancellationToken cancellationToken, IProgress <ProgressData> progress)
        {
            AppxPackerOptions opts = 0;

            if (!this.Validate.CurrentValue)
            {
                opts |= AppxPackerOptions.NoValidation;
            }

            if (!this.Compress.CurrentValue)
            {
                opts |= AppxPackerOptions.NoCompress;
            }

            using (var progressWrapper = new WrappedProgress(progress))
            {
                var progress1 = progressWrapper.GetChildProgress(50);
                var progress2 = this.Sign.CurrentValue ? progressWrapper.GetChildProgress(30) : null;

                await this.appxPacker.Pack(this.InputPath.CurrentValue, this.OutputPath.CurrentValue, opts, cancellationToken, progress1).ConfigureAwait(false);

                if (this.Sign.CurrentValue)
                {
                    var manager = await this.signingManagerFactory.GetProxyFor(SelfElevationLevel.HighestAvailable, cancellationToken).ConfigureAwait(false);

                    switch (this.SelectedCertificate.Store.CurrentValue)
                    {
                    case CertificateSource.Personal:
                        await manager.SignPackageWithInstalled(this.OutputPath.CurrentValue, this.OverrideSubject.CurrentValue, this.SelectedCertificate.SelectedPersonalCertificate.CurrentValue?.Model, this.SelectedCertificate.TimeStamp.CurrentValue, IncreaseVersionMethod.None, cancellationToken, progress2).ConfigureAwait(false);

                        break;

                    case CertificateSource.Pfx:
                        await manager.SignPackageWithPfx(this.OutputPath.CurrentValue, this.OverrideSubject.CurrentValue, this.SelectedCertificate.PfxPath.CurrentValue, this.SelectedCertificate.Password.CurrentValue, this.SelectedCertificate.TimeStamp.CurrentValue, IncreaseVersionMethod.None, cancellationToken, progress2).ConfigureAwait(false);

                        break;

                    case CertificateSource.DeviceGuard:
                        await manager.SignPackageWithDeviceGuardFromUi(this.OutputPath.CurrentValue, this.SelectedCertificate.DeviceGuard.CurrentValue, this.SelectedCertificate.TimeStamp.CurrentValue, IncreaseVersionMethod.None, cancellationToken, progress2).ConfigureAwait(false);

                        break;
                    }
                }
            }


            return(true);
        }
예제 #5
0
        public void TestWrongChildrenReports()
        {
            var progress = new TestProgress();

            using (var wrapped = new WrappedProgress(progress))
            {
                var p1 = wrapped.GetChildProgress();
                var p2 = wrapped.GetChildProgress();

                p1.Report(new ProgressData(200, null));
                Assert.AreEqual(50, progress.Last.Progress, "Even though the children may report over 100% completion, the overall progress may not overflow.");

                p2.Report(new ProgressData(300, null));
                Assert.AreEqual(100, progress.Last.Progress, "Even though the children may report over 100% completion, the overall progress may not overflow.");
            }
        }
예제 #6
0
        public async Task Dismount(string name, CancellationToken cancellationToken = default, IProgress <ProgressData> progress = default)
        {
            using var wrappedProgress = new WrappedProgress(progress);
            var p1         = wrappedProgress.GetChildProgress();
            var p2         = wrappedProgress.GetChildProgress();
            var allVolumes = await this.GetAll(cancellationToken, p1).ConfigureAwait(false);

            var volume = allVolumes.FirstOrDefault(v => string.Equals(name, v.Name, StringComparison.OrdinalIgnoreCase));

            if (volume == null)
            {
                return;
            }

            await this.Dismount(volume, cancellationToken, p2).ConfigureAwait(false);
        }
예제 #7
0
        public void TestWrappedProgress()
        {
            var progress = new TestProgress();

            using (var wrapped = new WrappedProgress(progress))
            {
                Assert.AreEqual(0, progress.Last.Progress);

                const int weight1 = 700;
                const int weight2 = 200;
                const int weight3 = 100;

                var p1 = wrapped.GetChildProgress(weight1);
                var p2 = wrapped.GetChildProgress(weight2);
                var p3 = wrapped.GetChildProgress(weight3);

                p1.Report(new ProgressData(0, null));
                p2.Report(new ProgressData(0, null));
                p3.Report(new ProgressData(0, null));
                Assert.AreEqual(0, progress.Last.Progress, "If all sub elements report 0% progress, then the overall progress is also 0%.");

                p1.Report(new ProgressData(100, null));
                // (100% * 700 + 0% * 200 + 0% * 100) / (100 + 200 + 700) = 70%
                Assert.AreEqual(70, progress.Last.Progress);

                p2.Report(new ProgressData(50, null));
                // (100% * 700 + 50% * 200 + 0% * 100) / (100 + 200 + 700) = 80%
                Assert.AreEqual(80, progress.Last.Progress);

                p3.Report(new ProgressData(10, null));
                // (100% * 700 + 50% * 200 + 10% * 100) / (100 + 200 + 700) = 81%
                Assert.AreEqual(81, progress.Last.Progress);

                p2.Report(new ProgressData(100, null));
                // (100% * 700 + 100% * 200 + 10% * 100) / (100 + 200 + 700) = 91%
                Assert.AreEqual(91, progress.Last.Progress);

                p3.Report(new ProgressData(100, null));
                // (100% * 700 + 100% * 200 + 100% * 100) / (100 + 200 + 700) = 100%
                Assert.AreEqual(100, progress.Last.Progress);

                p3.Report(new ProgressData(0, null));
                // (100% * 700 + 100% * 200 + 0% * 100) / (100 + 200 + 700) = 90%
                Assert.AreEqual(90, progress.Last.Progress, "If progress of a child element goes backward, the reported wrapped progress should also reflect this.");
            }
        }
예제 #8
0
        protected override async Task <bool> Save(CancellationToken cancellationToken, IProgress <ProgressData> progress)
        {
            var manager = await this.signingManagerFactory.GetProxyFor(SelfElevationLevel.AsInvoker, cancellationToken).ConfigureAwait(false);

            cancellationToken.ThrowIfCancellationRequested();

            using (var progressAll = new WrappedProgress(progress))
            {
                // ReSharper disable once AccessToDisposedClosure
                var progressForFiles = this.Files.ToDictionary(p => p, _ => progressAll.GetChildProgress());

                foreach (var file in this.Files)
                {
                    var currentProgress = progressForFiles[file];

                    cancellationToken.ThrowIfCancellationRequested();

                    string timeStampUrl;
                    switch (this.CertificateSelector.TimeStampSelectionMode.CurrentValue)
                    {
                    case TimeStampSelectionMode.None:
                        timeStampUrl = null;
                        break;

                    case TimeStampSelectionMode.Auto:
                        timeStampUrl = "auto";
                        break;

                    case TimeStampSelectionMode.Url:
                        timeStampUrl = this.CertificateSelector.TimeStamp.CurrentValue;
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }

                    switch (this.CertificateSelector.Store.CurrentValue)
                    {
                    case CertificateSource.Pfx:
                        await manager.SignPackageWithPfx(file, this.OverrideSubject.CurrentValue, this.CertificateSelector.PfxPath.CurrentValue, this.CertificateSelector.Password.CurrentValue, timeStampUrl, this.IncreaseVersion.CurrentValue, cancellationToken, currentProgress).ConfigureAwait(false);

                        break;

                    case CertificateSource.Personal:
                        await manager.SignPackageWithInstalled(file, this.OverrideSubject.CurrentValue, this.CertificateSelector.SelectedPersonalCertificate.CurrentValue.Model, timeStampUrl, this.IncreaseVersion.CurrentValue, cancellationToken, currentProgress).ConfigureAwait(false);

                        break;

                    case CertificateSource.DeviceGuard:
                        await manager.SignPackageWithDeviceGuardFromUi(file, this.CertificateSelector.DeviceGuard.CurrentValue, timeStampUrl, this.IncreaseVersion.CurrentValue, cancellationToken, currentProgress).ConfigureAwait(false);

                        break;
                    }
                }
            }

            return(true);
        }
예제 #9
0
        public void TestInvalidOperations()
        {
            var progress = new TestProgress();

            using (var wrapped = new WrappedProgress(progress))
            {
                var p1 = wrapped.GetChildProgress();
                p1.Report(new ProgressData(50, "test"));

                Assert.Throws <InvalidOperationException>(() => wrapped.GetChildProgress(), "Creating a new child progress should be disallowed once at lest one sub-progress has already reported.");
            }

            var progress2 = new TestProgress();

            using (var wrapped = new WrappedProgress(progress2, false))
            {
                var p1 = wrapped.GetChildProgress();
                p1.Report(new ProgressData(50, "test"));

                // This may not throw because of the second argument in WrappedProgress ctor
                wrapped.GetChildProgress();
            }
        }
예제 #10
0
        public async Task SetDefault(string drivePath, CancellationToken cancellationToken = default, IProgress <ProgressData> progress = default)
        {
            using var wrappedProgress = new WrappedProgress(progress);
            var p1         = wrappedProgress.GetChildProgress();
            var p2         = wrappedProgress.GetChildProgress();
            var allVolumes = await this.GetAll(cancellationToken, p1).ConfigureAwait(false);

            drivePath = GetDriveLetterFromPath(drivePath);
            Logger.Info("Looking for volume {0}...", drivePath);
            foreach (var item in allVolumes)
            {
                Logger.Debug(" * Found volume '{0}'", item.PackageStorePath);
            }

            var volume = allVolumes.FirstOrDefault(v => GetDriveLetterFromPath(v.PackageStorePath) == drivePath);

            if (volume == null)
            {
                throw new DriveNotFoundException($"Could not find volume '{drivePath}'");
            }

            await this.SetDefault(volume, cancellationToken, p2).ConfigureAwait(false);
        }
예제 #11
0
        public async Task <List <Log> > GetLogs(int maxCount, CancellationToken cancellationToken = default, IProgress <ProgressData> progress = default)
        {
            Logger.Info("Getting last {0} log files...", maxCount);

            var allLogs = new List <Log>();

            using var ps = await PowerShellSession.CreateForModule().ConfigureAwait(false);

            using var script = ps.AddScript("(Get-WinEvent -ListLog *Microsoft-Windows-*Appx* -ErrorAction SilentlyContinue).ProviderNames");
            using var logs   = await ps.InvokeAsync().ConfigureAwait(false);

            var logNames = logs.ToArray();

            var progresses = new IProgress <ProgressData> [logNames.Length];

            using (var wrapperProgress = new WrappedProgress(progress ?? new Progress <ProgressData>()))
            {
                for (var index = 0; index < logNames.Length; index++)
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    progresses[index] = wrapperProgress.GetChildProgress();
                }

                var allTasks = new List <Task <IList <Log> > >();
                for (var index = 0; index < logNames.Length; index++)
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    var item         = logNames[index];
                    var itemProgress = progresses[index];

                    allTasks.Add(this.GetLogsFromProvider(item, maxCount, cancellationToken, itemProgress));
                }

                await Task.WhenAll(allTasks).ConfigureAwait(false);

                foreach (var item in allTasks)
                {
                    allLogs.AddRange(await item.ConfigureAwait(false));
                }
            }

            if (maxCount > 0)
            {
                return(allLogs.OrderByDescending(l => l.DateTime).Take(maxCount).ToList());
            }

            return(allLogs);
        }
예제 #12
0
        public async Task CreateVolume(
            string packagePath,
            string volumePath,
            long?customSize,
            CancellationToken cancellationToken       = default,
            IProgress <ProgressData> progressReporter = null)
        {
            if (packagePath == null)
            {
                throw new ArgumentNullException(nameof(packagePath), "Package path must not be empty.");
            }

            if (volumePath == null)
            {
                throw new ArgumentNullException(nameof(volumePath), "Volume path must not be empty.");
            }

            var packageFileInfo = new FileInfo(packagePath);

            if (!packageFileInfo.Exists)
            {
                throw new FileNotFoundException($"File {packagePath} does not exist.", packagePath);
            }

            switch (Path.GetExtension(volumePath).ToLowerInvariant())
            {
            case FileConstants.AppAttachVhdExtension:
            case FileConstants.AppAttachVhdxExtension:
                break;

            default:
                throw new NotSupportedException($"Disk format {Path.GetExtension(volumePath)} is not supported.");
            }

            var volumeFileInfo = new FileInfo(volumePath);

            if (volumeFileInfo.Directory != null && !volumeFileInfo.Directory.Exists)
            {
                volumeFileInfo.Directory.Create();
            }

            var tmpPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N") + Path.GetExtension(volumePath));

            using var progress = new WrappedProgress(progressReporter);

            // ReSharper disable once UnusedVariable
            var progressSize           = customSize <= 0 ? progress.GetChildProgress(30) : null;
            var progressInitializeDisk = progress.GetChildProgress(100);
            var progressExpand         = progress.GetChildProgress(120);

            try
            {
                long minimumSize;
                if (customSize.HasValue && customSize.Value > 0)
                {
                    minimumSize = 1024 * 1024 * customSize.Value;
                }
                else
                {
                    ISizeCalculator sizeCalculator = new VhdSizeCalculator();
                    minimumSize = await sizeCalculator.GetRequiredSize(packagePath, cancellationToken : cancellationToken).ConfigureAwait(false);
                }

                var wrapper = new DiskPartWrapper();

                try
                {
                    Logger.Debug("Getting drives (NTFS, ready) and volumes...");
                    var allDrives = DriveInfo.GetDrives().Where(d => d.IsReady && d.DriveFormat == "NTFS").Select(d => d.Name.ToLowerInvariant()).ToArray();
                    foreach (var item in allDrives)
                    {
                        Logger.Debug("* Drive: " + item);
                    }

                    var allVolumes = await MountVolumeHelper.GetVolumeIdentifiers().ConfigureAwait(false);

                    foreach (var item in allDrives)
                    {
                        Logger.Debug("* Volume: " + item);
                    }

                    await wrapper.CreateVhdAndAssignDriveLetter(tmpPath, minimumSize, cancellationToken, progressInitializeDisk).ConfigureAwait(false);

                    var newVolumes = (await MountVolumeHelper.GetVolumeIdentifiers().ConfigureAwait(false)).Except(allVolumes).ToArray();
                    foreach (var item in newVolumes)
                    {
                        Logger.Debug("* New volume: " + item);
                    }

                    var newDrives = DriveInfo.GetDrives().Where(d => d.IsReady && d.DriveFormat == "NTFS").Select(d => d.Name.ToLowerInvariant()).Except(allDrives).ToArray();
                    foreach (var item in newDrives)
                    {
                        Logger.Debug("* New drive: " + item);
                    }

                    if (newDrives.Length != 1 || newVolumes.Length != 1)
                    {
                        throw new InvalidOperationException("Could not mount the drive.");
                    }

                    cancellationToken.ThrowIfCancellationRequested();
                    await this.ExpandMsix(packagePath, newDrives.First() + Path.GetFileNameWithoutExtension(packagePath), cancellationToken, progressExpand).ConfigureAwait(false);
                }
                finally
                {
                    await wrapper.DismountVhd(tmpPath, cancellationToken).ConfigureAwait(false);
                }

                if (File.Exists(tmpPath))
                {
                    File.Move(tmpPath, volumeFileInfo.FullName, true);
                }
            }
            finally
            {
                if (File.Exists(tmpPath))
                {
                    File.Delete(tmpPath);
                }
            }
        }
        private async void OnRemovePackage()
        {
            if (!this.IsAnySelected())
            {
                return;
            }

            var config = await this.configurationService.GetCurrentConfigurationAsync().ConfigureAwait(false);

            if (config.UiConfiguration.ConfirmDeletion)
            {
                var options = new List <string>
                {
                    "Remove for current user",
                    "Do not remove"
                };

                var singleSelection = this.GetSingleOrDefaultSelection();
                if (singleSelection != null)
                {
                    var caption = "Are you sure you want to remove " + singleSelection.DisplayName + " " + singleSelection.Version + "? This operation is irreversible.";

                    var selectedOption = this.interactionService.ShowMessage(caption, options, "Removing package", systemButtons: InteractionResult.Cancel);
                    if (selectedOption != 0)
                    {
                        return;
                    }
                }
                else
                {
                    var selection = this.application.ApplicationState.Packages.SelectedPackages;
                    var caption   = "Are you sure you want to remove " + selection.Count + " packages? This operation is irreversible.";

                    var selectedOption = this.interactionService.ShowMessage(caption, options, "Removing package", systemButtons: InteractionResult.Cancel);
                    if (selectedOption != 0)
                    {
                        return;
                    }
                }
            }

            var context = this.busyManager.Begin();

            try
            {
                using var wrappedProgress = new WrappedProgress(context);
                var p1 = wrappedProgress.GetChildProgress(70);
                var p2 = wrappedProgress.GetChildProgress(30);

                var manager = await this.packageInstallerProvider.GetProxyFor(SelfElevationLevel.AsInvoker).ConfigureAwait(false);

                var removedPackageNames = this.application.ApplicationState.Packages.SelectedPackages.Select(p => p.DisplayName).ToArray();
                var removedPackages     = this.application.ApplicationState.Packages.SelectedPackages.Select(p => p.PackageId).ToArray();
                await manager.Remove(removedPackages, progress : p1).ConfigureAwait(false);

                await this.application.CommandExecutor.Invoke(this, new SelectPackagesCommand()).ConfigureAwait(false);

                switch (removedPackages.Length)
                {
                case 1:
#pragma warning disable 4014
                    this.interactionService.ShowToast("App removed", $"{removedPackageNames.FirstOrDefault()} has been just removed.", InteractionType.None);
#pragma warning restore 4014
                    break;

                default:
#pragma warning disable 4014
                    this.interactionService.ShowToast("Apps removed", $"{removedPackages.Length} apps has been just removed.", InteractionType.None);
#pragma warning restore 4014
                    break;
                }

                await this.application.CommandExecutor.Invoke <GetPackagesCommand, IList <InstalledPackage> >(this, new GetPackagesCommand(), progress : p2).ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                this.interactionService.ShowError("Could not remove the package.", exception);
            }
            finally
            {
                this.busyManager.End(context);
            }
        }
        private async void OnAddPackage(string packagePath, bool forAllUsers)
        {
            if (packagePath == null)
            {
                if (forAllUsers)
                {
                    if (!this.interactionService.SelectFile(FileDialogSettings.FromFilterString(new DialogFilterBuilder("*" + FileConstants.MsixExtension, "*" + FileConstants.AppxExtension).BuildFilter()), out packagePath))
                    {
                        return;
                    }
                }
                else
                {
                    if (!this.interactionService.SelectFile(
                            // ReSharper disable StringLiteralTypo
                            FileDialogSettings.FromFilterString(new DialogFilterBuilder("*" + FileConstants.MsixExtension, "*" + FileConstants.AppxExtension, "*" + FileConstants.AppxBundleExtension, "*" + FileConstants.AppInstallerExtension, FileConstants.AppxManifestFile).BuildFilter()), out packagePath))
                    // ReSharper restore StringLiteralTypo
                    {
                        return;
                    }
                }
            }

            AddAppxPackageOptions options = 0;

            if (forAllUsers)
            {
                options |= AddAppxPackageOptions.AllUsers;
            }

            options |= AddAppxPackageOptions.KillRunningApps;

            var context = this.busyManager.Begin();

            try
            {
                using var wrappedProgress = new WrappedProgress(context);
                var p1 = wrappedProgress.GetChildProgress(90);
                var p2 = wrappedProgress.GetChildProgress(10);

                var manager = await this.packageInstallerProvider.GetProxyFor(forAllUsers?SelfElevationLevel.AsAdministrator : SelfElevationLevel.AsInvoker).ConfigureAwait(false);

                await manager.Add(packagePath, options, progress : p1).ConfigureAwait(false);

                AppxIdentity appxIdentity = null;
                if (!string.Equals(FileConstants.AppInstallerExtension, Path.GetExtension(packagePath), StringComparison.OrdinalIgnoreCase))
                {
                    appxIdentity = await new AppxIdentityReader().GetIdentity(packagePath).ConfigureAwait(false);

#pragma warning disable 4014
                    this.interactionService.ShowToast("App installed", $"{appxIdentity.Name} has been just installed.", InteractionType.None);
#pragma warning restore 4014
                }
                else
                {
#pragma warning disable 4014
                    this.interactionService.ShowToast("App installed", $"A new app has been just installed from {Path.GetFileName(packagePath)}.", InteractionType.None);
#pragma warning restore 4014
                }

                var allPackages = await this.application.CommandExecutor.Invoke <GetPackagesCommand, IList <InstalledPackage> >(this, new GetPackagesCommand(forAllUsers ? PackageFindMode.AllUsers : PackageFindMode.CurrentUser), progress : p2).ConfigureAwait(false);

                if (appxIdentity != null)
                {
                    var selected = allPackages.FirstOrDefault(p => p.Name == appxIdentity.Name);
                    if (selected != null)
                    {
                        //this.application.ApplicationState.Packages.SelectedPackages.Clear();
                        //this.application.ApplicationState.Packages.SelectedPackages.Add(selected);

                        await this.application.CommandExecutor.Invoke(this, new SelectPackagesCommand(selected.ManifestLocation)).ConfigureAwait(false);
                    }
                }
                else
                {
                    await this.application.CommandExecutor.Invoke(this, new SelectPackagesCommand()).ConfigureAwait(false);
                }
            }
            catch (Exception exception)
            {
                Logger.Error(exception);
                this.interactionService.ShowError(exception.Message, exception);
            }
            finally
            {
                this.busyManager.End(context);
            }
        }
예제 #15
0
        protected override async Task <bool> Save(CancellationToken cancellationToken, IProgress <ProgressData> progress)
        {
            var temporaryFiles = new List <string>();

            try
            {
                var fileListBuilder = new PackageFileListBuilder();
                fileListBuilder.AddDirectory(this.InputPath.CurrentValue, true, null);

                if (this.PrePackOptions != null && !this.PrePackOptions.ManifestPresent)
                {
                    if (!this.PrePackOptions.CanConvert)
                    {
                        throw new InvalidOperationException("The selected folder does not contain a manifest file and any executable files. It cannot be packed to MSIX format.");
                    }

                    if (!string.IsNullOrEmpty(this.InputPath.CurrentValue))
                    {
                        progress.Report(new ProgressData(0, "Creating manifest file..."));
                        var options = new AppxManifestCreatorOptions
                        {
                            CreateLogo         = this.PrePackOptions.CreateLogo,
                            EntryPoints        = this.PrePackOptions.EntryPoints.Where(e => e.IsChecked).Select(e => e.Value).ToArray(),
                            PackageDisplayName = Path.GetFileName(this.InputPath.CurrentValue),
                            RegistryFile       = this.PrePackOptions.SelectedRegistry?.FilePath == null ? null : new FileInfo(this.PrePackOptions.SelectedRegistry.FilePath)
                        };

                        // ReSharper disable once AssignNullToNotNullAttribute
                        await foreach (var result in this.manifestCreator.CreateManifestForDirectory(new DirectoryInfo(this.InputPath.CurrentValue), options, cancellationToken).ConfigureAwait(false))
                        {
                            temporaryFiles.Add(result.SourcePath);

                            if (result.PackageRelativePath == null)
                            {
                                continue;
                            }

                            fileListBuilder.AddFile(result.SourcePath, result.PackageRelativePath);
                        }
                    }
                }

                using var progressWrapper = new WrappedProgress(progress);
                var progress1 = progressWrapper.GetChildProgress(50);
                var progress2 = this.Sign.CurrentValue ? progressWrapper.GetChildProgress(30) : null;

                var tempFileList = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N") + ".list");
                temporaryFiles.Add(tempFileList);

                var tempManifestPath = Path.Combine(Path.GetTempPath(), "AppxManifest-" + Guid.NewGuid().ToString("N") + ".xml");
                temporaryFiles.Add(tempManifestPath);

                var srcManifest = fileListBuilder.GetManifestSourcePath();
                if (srcManifest == null || !File.Exists(srcManifest))
                {
                    throw new InvalidOperationException("The selected folder cannot be packed because it has no manifest, and MSIX Hero was unable to create one. A manifest can be only created if the selected folder contains any executable file.");
                }

                // Copy manifest to a temporary file
                var injector = new MsixHeroBrandingInjector();
                await using (var manifestStream = File.OpenRead(fileListBuilder.GetManifestSourcePath()))
                {
                    var xml = await XDocument.LoadAsync(manifestStream, LoadOptions.None, cancellationToken).ConfigureAwait(false);

                    await injector.Inject(xml).ConfigureAwait(false);

                    await File.WriteAllTextAsync(tempManifestPath, xml.ToString(SaveOptions.None), cancellationToken);

                    fileListBuilder.AddManifest(tempManifestPath);
                }

                await File.WriteAllTextAsync(tempFileList, fileListBuilder.ToString(), cancellationToken).ConfigureAwait(false);

                var sdk = new MakeAppxWrapper();
                await sdk.PackPackageFiles(tempFileList, this.OutputPath.CurrentValue, this.Compress.CurrentValue, this.Validate.CurrentValue, cancellationToken, progress1).ConfigureAwait(false);

                if (this.Sign.CurrentValue)
                {
                    var manager = await this.signingManagerFactory.GetProxyFor(SelfElevationLevel.HighestAvailable, cancellationToken).ConfigureAwait(false);

                    string timeStampUrl;
                    switch (this.SelectedCertificate.TimeStampSelectionMode.CurrentValue)
                    {
                    case TimeStampSelectionMode.None:
                        timeStampUrl = null;
                        break;

                    case TimeStampSelectionMode.Auto:
                        timeStampUrl = "auto";
                        break;

                    case TimeStampSelectionMode.Url:
                        timeStampUrl = this.SelectedCertificate.TimeStamp.CurrentValue;
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }

                    switch (this.SelectedCertificate.Store.CurrentValue)
                    {
                    case CertificateSource.Personal:
                        await manager.SignPackageWithInstalled(this.OutputPath.CurrentValue, this.OverrideSubject.CurrentValue, this.SelectedCertificate.SelectedPersonalCertificate.CurrentValue?.Model, timeStampUrl, IncreaseVersionMethod.None, cancellationToken, progress2).ConfigureAwait(false);

                        break;

                    case CertificateSource.Pfx:
                        await manager.SignPackageWithPfx(this.OutputPath.CurrentValue, this.OverrideSubject.CurrentValue, this.SelectedCertificate.PfxPath.CurrentValue, this.SelectedCertificate.Password.CurrentValue, timeStampUrl, IncreaseVersionMethod.None, cancellationToken, progress2).ConfigureAwait(false);

                        break;

                    case CertificateSource.DeviceGuard:
                        await manager.SignPackageWithDeviceGuardFromUi(this.OutputPath.CurrentValue, this.SelectedCertificate.DeviceGuard.CurrentValue, timeStampUrl, IncreaseVersionMethod.None, cancellationToken, progress2).ConfigureAwait(false);

                        break;
                    }
                }

                if (this.RemoveDirectory.CurrentValue)
                {
                    ExceptionGuard.Guard(() => Directory.Delete(this.InputPath.CurrentValue, true));
                }

                return(true);
            }
            finally
            {
                foreach (var tempFile in temporaryFiles)
                {
                    ExceptionGuard.Guard(() => File.Delete(tempFile));
                }
            }
        }
예제 #16
0
        public async Task <string> CalculateSignatureHashAsync(Uri url, CancellationToken cancellationToken = default, IProgress <ProgressData> progress = null)
        {
            using var wrappedProgress = new WrappedProgress(progress);
            var progressForDownload = wrappedProgress.GetChildProgress(85);
            var progressForHashing  = wrappedProgress.GetChildProgress(15);

            var webRequest = (HttpWebRequest)WebRequest.Create(url);

            using var response = webRequest.GetResponse();
            var tempFileName = Path.Combine(Path.GetTempPath(), "msixhero-" + Guid.NewGuid().ToString("N").Substring(0, 8) + FileConstants.MsixExtension);

            try
            {
                // ReSharper disable once UseAwaitUsing
                using (var fs = File.OpenWrite(tempFileName))
                {
                    var buffer = new byte[4096];

                    await using var responseStream = response.GetResponseStream();
                    if (responseStream == null)
                    {
                        throw new InvalidOperationException("Could not download the file.");
                    }

                    int read;

                    var        totalSize      = response.ContentLength;
                    var        processed      = 0L;
                    var        lastFlush      = 0L;
                    const long bufferFlushing = 1024 * 1024 * 10; // 10 MB

                    while ((read = await responseStream.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) > 0)
                    {
                        processed += read;

                        if (totalSize > 0)
                        {
                            var p = (int)(100.0 * processed / totalSize);
                            progressForDownload.Report(new ProgressData(p, $"Downloading... ({p}%)"));
                        }

                        cancellationToken.ThrowIfCancellationRequested();
                        await fs.WriteAsync(buffer, 0, read, cancellationToken).ConfigureAwait(false);

                        if (processed + bufferFlushing > lastFlush)
                        {
                            await fs.FlushAsync(cancellationToken).ConfigureAwait(false);

                            lastFlush = processed;
                        }
                    }

                    await fs.FlushAsync(cancellationToken).ConfigureAwait(false);
                }

                return(await this.CalculateSignatureHashAsync(new FileInfo(tempFileName), cancellationToken, progressForHashing).ConfigureAwait(false));
            }
            finally
            {
                File.Delete(tempFileName);
            }
        }
예제 #17
0
        public async Task CreateVolume(string packagePath, string volumePath, uint vhdSize, bool extractCertificate, bool generateScripts, CancellationToken cancellationToken = default, IProgress <ProgressData> progressReporter = null)
        {
            if (packagePath == null)
            {
                throw new ArgumentNullException(nameof(packagePath));
            }

            if (volumePath == null)
            {
                throw new ArgumentNullException(nameof(packagePath));
            }

            var packageFileInfo = new FileInfo(packagePath);

            if (!packageFileInfo.Exists)
            {
                throw new FileNotFoundException($"File {packagePath} does not exist.", packagePath);
            }

            var volumeFileInfo = new FileInfo(volumePath);

            if (volumeFileInfo.Directory != null && !volumeFileInfo.Directory.Exists)
            {
                volumeFileInfo.Directory.Create();
            }

            var tmpPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N") + ".vhd");

            using (var progress = new WrappedProgress(progressReporter))
            {
                // ReSharper disable once UnusedVariable
                var progressSize           = vhdSize <= 0 ? progress.GetChildProgress(30) : null;
                var progressStopService    = progress.GetChildProgress(10);
                var progressInitializeDisk = progress.GetChildProgress(100);
                // var progressNewPartition = progress.GetChildProgress(30);
                // var progressFormatVolume = progress.GetChildProgress(80);
                var progressStartService = progress.GetChildProgress(10);
                var progressExpand       = progress.GetChildProgress(120);
                var progressScripts      = generateScripts ? progress.GetChildProgress(10) : null;

                try
                {
                    var minimumSize = vhdSize > 0 ? 1024 * 1024 * vhdSize : await GetVhdSize(packagePath, cancellationToken : cancellationToken).ConfigureAwait(false);

                    bool requiresRestart;
                    try
                    {
                        requiresRestart = await StopService(cancellationToken, progressStopService).ConfigureAwait(false);
                    }
                    catch (Exception)
                    {
                        requiresRestart = false;
                    }

                    Guid   volumeGuid;
                    var    wrapper = new DiskPartWrapper();
                    string pkgFullName;

                    try
                    {
                        var allDrives = DriveInfo.GetDrives().Where(d => d.IsReady && d.DriveFormat == "NTFS").Select(d => d.Name.ToLowerInvariant()).ToArray();

                        var existing = await this.GetVolumeIdentifiers().ConfigureAwait(false);

                        await wrapper.CreateVhdAndAssignDriveLetter(tmpPath, minimumSize, cancellationToken, progressInitializeDisk).ConfigureAwait(false);

                        var newVolumes = (await this.GetVolumeIdentifiers().ConfigureAwait(false)).Except(existing).ToArray();

                        var newDrives = DriveInfo.GetDrives().Where(d => d.IsReady && d.DriveFormat == "NTFS").Select(d => d.Name.ToLowerInvariant()).Except(allDrives).ToArray();

                        if (newDrives.Length != 1 || newVolumes.Length != 1)
                        {
                            throw new InvalidOperationException("Could not mount the drive.");
                        }

                        volumeGuid = newVolumes[0];
                        cancellationToken.ThrowIfCancellationRequested();
                        pkgFullName = await this.ExpandMsix(packagePath, newDrives.First() + Path.GetFileNameWithoutExtension(packagePath), cancellationToken, progressExpand).ConfigureAwait(false);
                    }
                    finally
                    {
                        await wrapper.DismountVhd(tmpPath, cancellationToken).ConfigureAwait(false);

                        if (requiresRestart)
                        {
                            try
                            {
                                await StartService(cancellationToken, progressStartService).ConfigureAwait(false);
                            }
                            catch (Exception e)
                            {
                                Logger.Warn(e, "Could not restart the service ShellHWDetection.");
                            }
                        }
                    }

                    if (File.Exists(tmpPath))
                    {
                        if (generateScripts)
                        {
                            await CreateScripts(volumeFileInfo.FullName, Path.GetFileNameWithoutExtension(packagePath), volumeGuid, pkgFullName, cancellationToken, progressScripts).ConfigureAwait(false);
                        }

                        await CreateJson(volumeFileInfo.FullName, Path.GetFileNameWithoutExtension(packagePath), volumeGuid, pkgFullName, cancellationToken, progressScripts).ConfigureAwait(false);

                        if (extractCertificate)
                        {
                            ISigningManager certMgr = this.signingManager;
                            if (certMgr == null)
                            {
                                certMgr = await this.managerFactory.GetProxyFor(SelfElevationLevel.AsInvoker, cancellationToken).ConfigureAwait(false);
                            }

                            cancellationToken.ThrowIfCancellationRequested();

                            // ReSharper disable once AssignNullToNotNullAttribute
                            await certMgr.ExtractCertificateFromMsix(packagePath, Path.Combine(volumeFileInfo.DirectoryName, Path.GetFileNameWithoutExtension(volumeFileInfo.FullName)) + ".cer", cancellationToken).ConfigureAwait(false);
                        }

                        File.Move(tmpPath, volumeFileInfo.FullName, true);
                    }
                }
                finally
                {
                    if (File.Exists(tmpPath))
                    {
                        File.Delete(tmpPath);
                    }
                }
            }
        }