winget-cli

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

PackageCatalogReference.cpp (16430B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #include "pch.h"
      4 #include <winget/RepositorySource.h>
      5 #include "PackageCatalogReference.h"
      6 #include "PackageCatalogReference.g.cpp"
      7 #include "PackageCatalogInfo.h"
      8 #include "PackageCatalog.h"
      9 #include "SourceAgreement.h"
     10 #include "ConnectResult.h"
     11 #include "AuthenticationInfo.h"
     12 #include "Workflows/WorkflowBase.h"
     13 #include "Converters.h"
     14 #include "Microsoft/PredefinedInstalledSourceFactory.h"
     15 #include <wil\cppwinrt_wrl.h>
     16 #include <winget/GroupPolicy.h>
     17 #include <AppInstallerErrors.h>
     18 #include <AppInstallerStrings.h>
     19 #include <winget/UserSettings.h>
     20 #include <Helpers.h>
     21 #include <ExecutionContext.h>
     22 #include <RefreshPackageCatalogResult.h>
     23 #include <PackageCatalogProgress.h>
     24 
     25 namespace winrt::Microsoft::Management::Deployment::implementation
     26 {
     27     namespace
     28     {
     29         winrt::Microsoft::Management::Deployment::RefreshPackageCatalogResult GetRefreshPackageCatalogResult(winrt::hresult terminationStatus)
     30         {
     31             winrt::Microsoft::Management::Deployment::RefreshPackageCatalogStatus status = GetPackageCatalogOperationStatus<RefreshPackageCatalogStatus>(terminationStatus);
     32             auto updateResult = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::RefreshPackageCatalogResult>>();
     33             updateResult->Initialize(status, terminationStatus);
     34             return *updateResult;
     35         }
     36     }
     37 
     38     void PackageCatalogReference::Initialize(winrt::Microsoft::Management::Deployment::PackageCatalogInfo packageCatalogInfo, ::AppInstaller::Repository::Source sourceReference)
     39     {
     40         m_info = packageCatalogInfo;
     41         m_sourceReference = std::move(sourceReference);
     42         m_packageCatalogBackgroundUpdateInterval = ::AppInstaller::Settings::User().Get<::AppInstaller::Settings::Setting::AutoUpdateTimeInMinutes>();
     43 
     44         if (IsBackgroundProcessForPolicy())
     45         {
     46             // Delay the default update interval for these background processes
     47             static constexpr winrt::Windows::Foundation::TimeSpan s_PackageCatalogUpdateIntervalDelay_Base = 168h; //1 week
     48 
     49             // Add a bit of randomness to the default interval time
     50             std::default_random_engine randomEngine(std::random_device{}());
     51             std::uniform_int_distribution<long long> distribution(0, 604800);
     52 
     53             m_packageCatalogBackgroundUpdateInterval = s_PackageCatalogUpdateIntervalDelay_Base + std::chrono::seconds(distribution(randomEngine));
     54 
     55             // Prevent any update / data processing by default for these background processes for now
     56             m_installedPackageInformationOnly = m_sourceReference.IsWellKnownSource(AppInstaller::Repository::WellKnownSource::WinGet);
     57         }
     58     }
     59 
     60     void PackageCatalogReference::Initialize(winrt::Microsoft::Management::Deployment::CreateCompositePackageCatalogOptions options)
     61     {
     62         m_compositePackageCatalogOptions = options;
     63     }
     64 
     65     bool PackageCatalogReference::IsComposite()
     66     {
     67         return (m_compositePackageCatalogOptions != nullptr);
     68     }
     69     winrt::Microsoft::Management::Deployment::PackageCatalogInfo PackageCatalogReference::Info()
     70     {
     71         return m_info;
     72     }
     73     winrt::Windows::Foundation::IAsyncOperation<winrt::Microsoft::Management::Deployment::ConnectResult> PackageCatalogReference::ConnectAsync()
     74     {
     75         co_return Connect();
     76     }
     77     winrt::Microsoft::Management::Deployment::ConnectResult GetConnectCatalogErrorResult(hresult hr)
     78     {
     79         auto connectResult = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::ConnectResult>>();
     80         connectResult->Initialize(winrt::Microsoft::Management::Deployment::ConnectResultStatus::CatalogError, nullptr, hr);
     81         return *connectResult;
     82     }
     83     winrt::Microsoft::Management::Deployment::ConnectResult GetConnectSourceAgreementsNotAcceptedErrorResult()
     84     {
     85         auto connectResult = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::ConnectResult>>();
     86         connectResult->Initialize(winrt::Microsoft::Management::Deployment::ConnectResultStatus::SourceAgreementsNotAccepted, nullptr, APPINSTALLER_CLI_ERROR_SOURCE_AGREEMENTS_NOT_ACCEPTED);
     87         return *connectResult;
     88     }
     89     winrt::Microsoft::Management::Deployment::ConnectResult PackageCatalogReference::Connect() try
     90     {
     91         HRESULT hr = EnsureComCallerHasCapability(Capability::PackageQuery);
     92         if (FAILED(hr))
     93         {
     94             // TODO: When more error codes are added, this should go back as something other than CatalogError.
     95             return GetConnectCatalogErrorResult(hr);
     96         }
     97 
     98         std::string callerName = GetCallerName();
     99 
    100         ::AppInstaller::ProgressCallback progress;
    101         ::AppInstaller::Repository::Source source;
    102         if (m_compositePackageCatalogOptions)
    103         {
    104             std::vector<::AppInstaller::Repository::Source> remoteSources;
    105 
    106             for (uint32_t i = 0; i < m_compositePackageCatalogOptions.Catalogs().Size(); ++i)
    107             {
    108                 auto catalog = m_compositePackageCatalogOptions.Catalogs().GetAt(i);
    109                 if (!catalog.AcceptSourceAgreements() && catalog.SourceAgreements().Size() != 0)
    110                 {
    111                     return GetConnectSourceAgreementsNotAcceptedErrorResult();
    112                 }
    113 
    114                 winrt::Microsoft::Management::Deployment::implementation::PackageCatalogReference* catalogImpl = get_self<winrt::Microsoft::Management::Deployment::implementation::PackageCatalogReference>(catalog);
    115                 auto copy = catalogImpl->m_sourceReference;
    116                 copy.SetCaller(callerName);
    117                 copy.SetBackgroundUpdateInterval(catalog.PackageCatalogBackgroundUpdateInterval());
    118                 copy.InstalledPackageInformationOnly(catalog.InstalledPackageInformationOnly());
    119                 if (catalog.AuthenticationInfo().AuthenticationType() != winrt::Microsoft::Management::Deployment::AuthenticationType::None)
    120                 {
    121                     copy.SetAuthenticationArguments(GetAuthenticationArguments(catalog.AuthenticationArguments()));
    122                 }
    123                 copy.Open(progress);
    124                 remoteSources.emplace_back(std::move(copy));
    125             }
    126 
    127             // Create the aggregated source.
    128             source = ::AppInstaller::Repository::Source{ remoteSources };
    129 
    130             // Create composite with installed source if needed.
    131             ::AppInstaller::Repository::CompositeSearchBehavior searchBehavior = GetRepositoryCompositeSearchBehavior(m_compositePackageCatalogOptions.CompositeSearchBehavior());
    132 
    133             // Check if search behavior indicates that the caller does not want to do local correlation.
    134             if (m_compositePackageCatalogOptions.CompositeSearchBehavior() != Microsoft::Management::Deployment::CompositeSearchBehavior::RemotePackagesFromRemoteCatalogs)
    135             {
    136                 ::AppInstaller::Repository::Source installedSource;
    137                 auto manifestInstalledScope = GetManifestScope(m_compositePackageCatalogOptions.InstalledScope()).first;
    138                 if (manifestInstalledScope == ::AppInstaller::Manifest::ScopeEnum::User)
    139                 {
    140                     installedSource = ::AppInstaller::Repository::Source{ ::AppInstaller::Repository::PredefinedSource::InstalledUser };
    141                 }
    142                 else if (manifestInstalledScope == ::AppInstaller::Manifest::ScopeEnum::Machine)
    143                 {
    144                     installedSource = ::AppInstaller::Repository::Source{ ::AppInstaller::Repository::PredefinedSource::InstalledMachine };
    145                 }
    146                 else
    147                 {
    148                     installedSource = ::AppInstaller::Repository::Source{ ::AppInstaller::Repository::PredefinedSource::Installed };
    149                 }
    150 
    151                 installedSource.Open(progress);
    152                 source = ::AppInstaller::Repository::Source{ installedSource, source, searchBehavior };
    153             }
    154         }
    155         else
    156         {
    157             if (!AcceptSourceAgreements() && SourceAgreements().Size() != 0)
    158             {
    159                 return GetConnectSourceAgreementsNotAcceptedErrorResult();
    160             }
    161 
    162             source = m_sourceReference;
    163             source.SetCaller(callerName);
    164             source.SetBackgroundUpdateInterval(PackageCatalogBackgroundUpdateInterval());
    165             source.InstalledPackageInformationOnly(m_installedPackageInformationOnly);
    166             if (AuthenticationInfo().AuthenticationType() != winrt::Microsoft::Management::Deployment::AuthenticationType::None)
    167             {
    168                 source.SetAuthenticationArguments(GetAuthenticationArguments(m_authenticationArguments));
    169             }
    170             source.Open(progress);
    171         }
    172 
    173         if (!source)
    174         {
    175             // We call `Open` on each individual source above, meaning that they should throw any error that occurs.
    176             // If the source is still not open at this point it is a bug.
    177             return GetConnectCatalogErrorResult(E_UNEXPECTED);
    178         }
    179 
    180         // Have to make another package catalog info because source->GetDetails has more fields than m_info does.
    181         // Specifically, Rest sources do not have the Ids filled in m_info since they only get the id from the rest server after being Opened.
    182         auto packageCatalogInfo = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::PackageCatalogInfo>>();
    183         packageCatalogInfo->Initialize(source.GetDetails());
    184         auto connectResult = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::ConnectResult>>();
    185         auto packageCatalog = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::PackageCatalog>>();
    186         packageCatalog->Initialize(*packageCatalogInfo, source, (m_compositePackageCatalogOptions != nullptr));
    187         connectResult->Initialize(winrt::Microsoft::Management::Deployment::ConnectResultStatus::Ok, *packageCatalog, S_OK);
    188         return *connectResult;
    189     }
    190     catch (...)
    191     {
    192         return GetConnectCatalogErrorResult(AppInstaller::CLI::Workflow::HandleException(nullptr, std::current_exception()));
    193     }
    194 
    195     winrt::Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Management::Deployment::SourceAgreement> PackageCatalogReference::SourceAgreements()
    196     {
    197         std::call_once(m_sourceAgreementsOnceFlag,
    198             [&]()
    199             {
    200                 if (!IsComposite())
    201                 {
    202                     for (auto const& agreement : m_sourceReference.GetInformation().SourceAgreements)
    203                     {
    204                         auto sourceAgreement = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::SourceAgreement>>();
    205                         sourceAgreement->Initialize(agreement);
    206                         m_sourceAgreements.Append(*sourceAgreement);
    207                     }
    208                 }
    209             });
    210         return m_sourceAgreements.GetView();
    211     }
    212     hstring PackageCatalogReference::AdditionalPackageCatalogArguments()
    213     {
    214         if (!IsComposite())
    215         {
    216             if (m_additionalPackageCatalogArguments.has_value())
    217             {
    218                 return winrt::to_hstring(m_additionalPackageCatalogArguments.value());
    219             }
    220         }
    221 
    222         return {};
    223     }
    224     void PackageCatalogReference::AdditionalPackageCatalogArguments(hstring const& value)
    225     {
    226         if (IsComposite())
    227         {
    228             // Can't set AdditionalPackageCatalogArguments on a composite. Callers should set it on each non-composite PackageCatalogReference in the composite.
    229             throw winrt::hresult_illegal_state_change();
    230         }
    231         else
    232         {
    233             m_additionalPackageCatalogArguments = ::AppInstaller::Utility::ConvertToUTF8(value);
    234             m_sourceReference.SetCustomHeader(m_additionalPackageCatalogArguments);
    235         }
    236     }
    237     void PackageCatalogReference::AcceptSourceAgreements(bool value)
    238     {
    239         if (IsComposite())
    240         {
    241             // Can't set AcceptSourceAgreements on a composite. Callers should set it on each non-composite PackageCatalogReference in the composite.
    242             throw winrt::hresult_illegal_state_change();
    243         }
    244         m_acceptSourceAgreements = value;
    245     }
    246     bool PackageCatalogReference::AcceptSourceAgreements()
    247     {
    248         return m_acceptSourceAgreements;
    249     }
    250 
    251     void PackageCatalogReference::PackageCatalogBackgroundUpdateInterval(winrt::Windows::Foundation::TimeSpan const& value)
    252     {
    253         if (IsComposite())
    254         {
    255             // Can't set PackageCatalogBackgroundUpdateInterval on a composite. Callers should set it on each non-composite PackageCatalogReference in the composite.
    256             throw winrt::hresult_illegal_state_change();
    257         }
    258         m_packageCatalogBackgroundUpdateInterval = value;
    259     }
    260     winrt::Windows::Foundation::TimeSpan PackageCatalogReference::PackageCatalogBackgroundUpdateInterval()
    261     {
    262         return m_packageCatalogBackgroundUpdateInterval;
    263     }
    264 
    265     bool PackageCatalogReference::InstalledPackageInformationOnly()
    266     {
    267         return m_installedPackageInformationOnly;
    268     }
    269 
    270     void PackageCatalogReference::InstalledPackageInformationOnly(bool value)
    271     {
    272         if (IsComposite())
    273         {
    274             throw winrt::hresult_illegal_state_change();
    275         }
    276 
    277         m_installedPackageInformationOnly = value;
    278     }
    279     winrt::Microsoft::Management::Deployment::AuthenticationArguments PackageCatalogReference::AuthenticationArguments()
    280     {
    281         return m_authenticationArguments;
    282     }
    283     void PackageCatalogReference::AuthenticationArguments(winrt::Microsoft::Management::Deployment::AuthenticationArguments const& value)
    284     {
    285         if (IsComposite())
    286         {
    287             throw winrt::hresult_illegal_state_change();
    288         }
    289 
    290         m_authenticationArguments = value;
    291     }
    292     winrt::Microsoft::Management::Deployment::AuthenticationInfo PackageCatalogReference::AuthenticationInfo()
    293     {
    294         std::call_once(m_authenticationInfoOnceFlag,
    295             [&]()
    296             {
    297                 if (!IsComposite())
    298                 {
    299                     auto authenticationInfo = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::AuthenticationInfo>>();
    300                     authenticationInfo->Initialize(m_sourceReference.GetInformation().Authentication);
    301                     m_authenticationInfo = *authenticationInfo;
    302                 }
    303             });
    304         return m_authenticationInfo;
    305     }
    306 
    307     winrt::Windows::Foundation::IAsyncOperationWithProgress<winrt::Microsoft::Management::Deployment::RefreshPackageCatalogResult, double> PackageCatalogReference::RefreshPackageCatalogAsync()
    308     {
    309         HRESULT terminationHR = S_OK;
    310         try {
    311             // Check for permissions and get caller info for telemetry
    312             THROW_IF_FAILED(EnsureComCallerHasCapability(Capability::PackageQuery));
    313 
    314             auto strong_this = get_strong();
    315             auto report_progress{ co_await winrt::get_progress_token() };
    316             co_await winrt::resume_background();
    317 
    318             auto packageCatalogProgressSink = winrt::Microsoft::Management::Deployment::ProgressSinkFactory::CreatePackageCatalogProgressSink(this->m_sourceReference.GetDetails().Type, report_progress);
    319 
    320             packageCatalogProgressSink->BeginProgress();
    321             ::AppInstaller::ProgressCallback progress(packageCatalogProgressSink.get());
    322             this->m_sourceReference.Update(progress);
    323             packageCatalogProgressSink->EndProgress(false);
    324         }
    325         catch (...)
    326         {
    327             terminationHR = AppInstaller::CLI::Workflow::HandleException(nullptr, std::current_exception());
    328         }
    329 
    330         co_return GetRefreshPackageCatalogResult(terminationHR);
    331     }
    332 }