Skip to content

Commit

Permalink
Download MSIX installer during manifest validation (if necessary) (#2587
Browse files Browse the repository at this point in the history
)
  • Loading branch information
AmelBawa-msft authored Oct 11, 2022
1 parent a8a19c7 commit 9d30e9f
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 20 deletions.
105 changes: 90 additions & 15 deletions src/AppInstallerCommonCore/Manifest/MsixManifestValidation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// Licensed under the MIT License.
#include "pch.h"
#include "AppInstallerLogging.h"
#include "AppInstallerRuntime.h"
#include "AppInstallerDownloader.h"
#include "winget/MsixManifestValidation.h"

namespace AppInstaller::Manifest
Expand All @@ -12,7 +14,7 @@ namespace AppInstaller::Manifest
{
std::vector<ValidationError> errors;
Msix::PackageVersion packageVersion(manifest.Version);
auto msixInfo = GetMsixInfo(installer.Url, errors);
auto msixInfo = GetMsixInfo(installer.Url);
if (msixInfo)
{
ValidateMsixManifestSignatureHash(msixInfo, installer.SignatureSha256, errors);
Expand All @@ -26,37 +28,110 @@ namespace AppInstaller::Manifest
ValidateMsixManifestMinOSVersion(msixManifest.GetMinimumOSVersionForSupportedPlatforms(), installerMinOSVersion, installer.Url, errors);
}
}
else
{
errors.emplace_back(ManifestError::InstallerFailedToProcess, "InstallerUrl", installer.Url);
}

return errors;
}

std::shared_ptr<Msix::MsixInfo> MsixManifestValidation::GetMsixInfo(
std::string installerUrl,
std::vector<ValidationError> &errors)
std::optional<std::filesystem::path> MsixManifestValidation::DownloadInstaller(std::string installerUrl, int retryCount)
{
while (retryCount-- > 0)
{
try
{
AICLI_LOG(Core, Info, << "Start downloading installer");
auto tempFile = Runtime::GetNewTempFilePath();
ProgressCallback callback;
Utility::Download(installerUrl, tempFile, Utility::DownloadType::Installer, callback);
return tempFile;
}
catch (...)
{
AICLI_LOG(Core, Error, << "Downloading installer failed. Remaining attempts: " << retryCount);
}
}

return std::nullopt;
}

std::shared_ptr<Msix::MsixInfo> MsixManifestValidation::GetMsixInfoFromUrl(std::string installerUrl)
{
std::shared_ptr<Msix::MsixInfo> msixInfo;
try
{
// Cache Msix info for new installer url
auto findMsixInfo = m_msixInfoCache.find(installerUrl);
if (findMsixInfo == m_msixInfoCache.end())
AICLI_LOG(Core, Info, << "Fetching Msix info from installer url");
return std::make_shared<Msix::MsixInfo>(installerUrl);
}
catch (...)
{
AICLI_LOG(Core, Error, << "Error fetching Msix info from the installer url.");
return nullptr;
}
}

std::shared_ptr<Msix::MsixInfo> MsixManifestValidation::GetMsixInfoFromLocalPath(std::string installerUrl)
{
int maxRetry = 3;
std::shared_ptr<Msix::MsixInfo> msixInfo;
auto installerPath = DownloadInstaller(installerUrl, maxRetry);
if (installerPath.has_value())
{
try
{
AICLI_LOG(Core, Info, << "Fetching Msix info from installer local path");
msixInfo = std::make_shared<Msix::MsixInfo>(installerPath.value());
}
catch (...)
{
AICLI_LOG(Core, Error, << "Error fetching Msix info from the installer local path.");
}

AICLI_LOG(Core, Info, << "Removing downloaded installer");
if (!std::filesystem::remove(installerPath.value()))
{
AICLI_LOG(Core, Warning, << "Failed to remove downloaded installer");
}
}
else
{
AICLI_LOG(Core, Error, << "Failed to download installer.");
}

return msixInfo;
}

std::shared_ptr<Msix::MsixInfo> MsixManifestValidation::GetMsixInfo(std::string installerUrl)
{
std::shared_ptr<Msix::MsixInfo> msixInfo;
// Cache Msix info for new installer url
auto findMsixInfo = m_msixInfoCache.find(installerUrl);
if (findMsixInfo == m_msixInfoCache.end())
{
msixInfo = GetMsixInfoFromUrl(installerUrl);
if (!msixInfo)
{
AICLI_LOG(Core, Warning, << "Failed to get Msix info directly from the installer url. "
<< "Downloading installer instead.");
msixInfo = GetMsixInfoFromLocalPath(installerUrl);
}

if (msixInfo)
{
msixInfo = std::make_shared<Msix::MsixInfo>(installerUrl);
m_msixInfoCache.insert({ installerUrl, msixInfo });
}
else
{
msixInfo = findMsixInfo->second;
AICLI_LOG(Core, Error, << "Msix info could not be obtained.");
}

return msixInfo;
}
catch (...)
else
{
errors.emplace_back(ManifestError::InstallerFailedToProcess, "InstallerUrl", installerUrl);
msixInfo = findMsixInfo->second;
}

return nullptr;
return msixInfo;
}

std::optional<Msix::OSVersion> MsixManifestValidation::GetManifestInstallerMinOSVersion(
Expand Down
20 changes: 15 additions & 5 deletions src/AppInstallerCommonCore/Public/winget/MsixManifestValidation.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,21 @@ namespace AppInstaller::Manifest
std::map<std::string, std::shared_ptr<Msix::MsixInfo>> m_msixInfoCache;
ValidationError::Level m_validationErrorLevel;

// Get Msix info from installer url, or load it from cache. Return null
// pointer if failed to process installer url.
std::shared_ptr<Msix::MsixInfo> GetMsixInfo(
std::string installerUrl,
std::vector<ValidationError>& errors);
// Get Msix info from url/local path, or load it from cache.
// Return null pointer if operation failed.
std::shared_ptr<Msix::MsixInfo> GetMsixInfo(std::string installerUrl);

// Get Msix info from installer url.
// Return null pointer if operation failed.
std::shared_ptr<Msix::MsixInfo> GetMsixInfoFromUrl(std::string installerUrl);

// Download and get msix info from installer local path.
// Return null pointer if operation failed.
std::shared_ptr<Msix::MsixInfo> GetMsixInfoFromLocalPath(std::string installerUrl);

// Download the installer.
// If the download was successful, return the destination path.
std::optional<std::filesystem::path> DownloadInstaller(std::string installerUrl, int retryCount);

// Get manifest installer minimum OS version or nullopt if failed to
// parse input.
Expand Down

0 comments on commit 9d30e9f

Please sign in to comment.